下面我将详细分解这段代码的每个步骤,展示如何在 Godot 引擎中从零开始创建一个不规则棱柱体并实现旋转动画:
步骤1:设置场景基础结构
gdscript
extends Node3D # 继承自3D场景节点
var prism_mesh_instance: MeshInstance3D # 声明棱柱体网格实例变量
- 脚本继承自
Node3D
,这是所有3D场景的基类 - 声明一个
MeshInstance3D
类型的变量,用于存储创建的棱柱体
步骤2:初始化场景 (_ready 函数)
gdscript
func _ready() -> void:
# 定义底面多边形的5个顶点坐标
var base_points = [
Vector3(-3, 0, -2), # 点1 (X, Y, Z)
Vector3(2, 0, -3), # 点2
Vector3(4, 0, 1), # 点3
Vector3(1, 0, 4), # 点4
Vector3(-2, 0, 3) # 点5
]
# 设置棱柱体的高度
var height = 2.5
# 调用创建棱柱体的核心函数
create_prism_from_base_and_height(base_points, height)
- 在场景加载时自动执行
- 定义了一个不规则五边形的底面顶点坐标(所有Y值为0,位于XZ平面)
- 设置棱柱体的高度为2.5个单位
- 调用核心函数创建棱柱体
步骤3:创建棱柱体核心函数
3.1 验证输入和准备数据
gdscript
func create_prism_from_base_and_height(base_points: Array, height: float) -> void:
# 验证输入是否有效(至少3个点才能构成多边形)
if base_points.size() < 3:
print("错误:至少需要3个点来构成多边形")
return
var point_count = base_points.size()
var prism_points = [] # 存储所有顶点(底面+顶面)
- 检查底面点数是否足够(至少3个点)
- 获取底面点数
- 初始化顶点数组
3.2 计算顶点位置
gdscript
# 添加底面顶点
for i in range(point_count):
prism_points.append(base_points[i])
# 添加顶面顶点(底面顶点+Y方向偏移)
for i in range(point_count):
var top_point = base_points[i] + Vector3(0, height, 0)
prism_points.append(top_point)
- 首先添加所有底面顶点
- 然后添加顶面顶点(每个底面顶点沿Y轴向上偏移高度值)
3.3 使用 SurfaceTool 创建网格
gdscript
# 初始化SurfaceTool
var surface_tool = SurfaceTool.new()
surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
- 创建 SurfaceTool 实例,用于动态生成网格
- 指定网格使用三角形图元
3.4 创建底面
gdscript
# 计算底面中心点(用于三角剖分)
var bottom_center = Vector3.ZERO
for point in base_points:
bottom_center += point
bottom_center /= point_count
bottom_center.y = 0 # 确保在底面平面上
# 创建底面三角形(扇形三角剖分)
for i in range(point_count):
var next_i = (i + 1) % point_count
surface_tool.add_vertex(bottom_center) # 中心点
surface_tool.add_vertex(prism_points[i]) # 当前点
surface_tool.add_vertex(prism_points[next_i]) # 下一个点
- 计算底面多边形的中心点(所有顶点的平均值)
- 使用扇形三角剖分创建底面:
- 从中心点出发
- 连接相邻顶点形成三角形
3.5 创建顶面
gdscript
# 计算顶面中心点
var top_center = bottom_center + Vector3(0, height, 0)
var top_start = point_count # 顶面顶点起始索引
# 创建顶面三角形(类似底面)
for i in range(point_count):
var next_i = (i + 1) % point_count
surface_tool.add_vertex(top_center) # 顶部中心点
surface_tool.add_vertex(prism_points[top_start + i]) # 当前顶部点
surface_tool.add_vertex(prism_points[top_start + next_i]) # 下一个顶部点
- 顶面中心点是底面中心点沿Y轴偏移高度值
- 使用相同的扇形三角剖分方法创建顶面
3.6 创建侧面
gdscript
# 创建侧面(四边形分解为两个三角形)
for i in range(point_count):
var next_i = (i + 1) % point_count
# 第一个三角形
surface_tool.add_vertex(prism_points[i]) # 底部当前点
surface_tool.add_vertex(prism_points[top_start + i]) # 顶部当前点
surface_tool.add_vertex(prism_points[next_i]) # 底部下一个点
# 第二个三角形
surface_tool.add_vertex(prism_points[next_i]) # 底部下一个点
surface_tool.add_vertex(prism_points[top_start + i]) # 顶部当前点
surface_tool.add_vertex(prism_points[top_start + next_i]) # 顶部下一个点
- 每个侧面由四边形组成
- 每个四边形被分解为两个三角形:
- 底部点A → 顶部点A → 底部点B
- 底部点B → 顶部点A → 顶部点B
- 确保所有三角形顶点顺序为逆时针(保证法线方向正确)
3.7 生成网格和材质
gdscript
# 生成法线(用于光照计算)
surface_tool.generate_normals()
# 提交网格数据
var array_mesh = surface_tool.commit()
# 创建网格实例
prism_mesh_instance = MeshInstance3D.new()
prism_mesh_instance.mesh = array_mesh
# 创建材质
var material = StandardMaterial3D.new()
material.albedo_color = Color(0.2, 0.6, 0.8) # 蓝色
material.cull_mode = BaseMaterial3D.CULL_DISABLED # 禁用背面剔除
prism_mesh_instance.material_override = material
# 添加到场景
add_child(prism_mesh_instance)
- 自动生成顶点法线(使光照效果正确)
- 提交网格数据生成 ArrayMesh
- 创建 MeshInstance3D 节点并设置网格
- 创建蓝色材质并禁用背面剔除(保证从内部也能看到)
- 将棱柱体添加到场景中
3.8 设置摄像机视角
gdscript
# 定位摄像机
$Camera3D.position = Vector3(0, 10, 10) # 摄像机位置(斜上方)
$Camera3D.look_at(prism_mesh_instance.position) # 看向棱柱体中心
- 将摄像机放置在 (0, 10, 10) 位置
- 让摄像机看向棱柱体中心点 (0, 0, 0)
步骤4:实现旋转动画 (_process 函数)
gdscript
func _process(delta: float) -> void:
if prism_mesh_instance:
# 每秒绕Y轴旋转30度
prism_mesh_instance.rotate_y(deg_to_rad(30) * delta)
- 每帧执行一次
- 检查棱柱体是否已创建
- 使用
rotate_y()
方法绕Y轴旋转 deg_to_rad(30)
将角度转换为弧度- 乘以
delta
保证旋转速度与帧率无关
最终效果
当运行此代码时:
- 场景初始化时创建一个不规则五边形底面的棱柱体
- 棱柱体呈现蓝色,禁用背面剔除
- 摄像机从斜上方 (0,10,10) 位置看向棱柱体中心
- 棱柱体以每秒30度的速度绕Y轴匀速旋转

完整代码
ini
extends Node3D
var prism_mesh_instance: MeshInstance3D
func _ready() -> void:
# Called when the node enters the scene tree for the first time.
var base_points = [
Vector3(-3, 0, -2), # 点1
Vector3(2, 0, -3), # 点2
Vector3(4, 0, 1), # 点3
Vector3(1, 0, 4), # 点4
Vector3(-2, 0, 3) # 点5
]
# 棱柱体高度
var height = 2.5
# 调用函数创建棱柱体
create_prism_from_base_and_height(base_points, height)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
if prism_mesh_instance:
# 绕y轴旋转,每秒旋转30度
prism_mesh_instance.rotate_y(deg_to_rad(30) * delta)
# 根据任意多边形底面和高度创建棱柱体
func create_prism_from_base_and_height(base_points: Array, height: float) -> void:
# 验证输入
if base_points.size() < 3:
print("错误:至少需要3个点来构成多边形")
return
var point_count = base_points.size()
# 计算棱柱体的所有顶点
var prism_points = []
# 底部点(底面多边形)
for i in range(point_count):
prism_points.append(base_points[i])
# 顶部点(底面多边形加上高度)
for i in range(point_count):
var top_point = base_points[i] + Vector3(0, height, 0)
prism_points.append(top_point)
# 使用SurfaceTool创建棱柱体
var surface_tool = SurfaceTool.new()
surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
# 创建底面(多边形三角剖分 - 使用扇形三角剖分)
var bottom_center = Vector3.ZERO
for point in base_points:
bottom_center += point
bottom_center /= point_count
bottom_center.y = 0 # 确保在底面平面上
for i in range(point_count):
var next_i = (i + 1) % point_count
surface_tool.add_vertex(bottom_center) # 中心点
surface_tool.add_vertex(prism_points[i]) # 当前点
surface_tool.add_vertex(prism_points[next_i]) # 下一个点
# 创建顶面(多边形三角剖分 - 使用扇形三角剖分)
var top_start = point_count
var top_center = bottom_center + Vector3(0, height, 0)
for i in range(point_count):
var next_i = (i + 1) % point_count
surface_tool.add_vertex(top_center) # 顶部中心点
surface_tool.add_vertex(prism_points[top_start + i]) # 当前顶部点
surface_tool.add_vertex(prism_points[top_start + next_i]) # 下一个顶部点
# 创建侧面(连接底部和顶部的四边形面)
for i in range(point_count):
var next_i = (i + 1) % point_count # 下一个点的索引(循环)
# 侧面四边形分解为两个三角形
# 第一个三角形(逆时针顺序)
surface_tool.add_vertex(prism_points[i]) # 底部当前点
surface_tool.add_vertex(prism_points[top_start + i]) # 顶部当前点
surface_tool.add_vertex(prism_points[next_i]) # 底部下一个点
# 第二个三角形(逆时针顺序)
surface_tool.add_vertex(prism_points[next_i]) # 底部下一个点
surface_tool.add_vertex(prism_points[top_start + i]) # 顶部当前点
surface_tool.add_vertex(prism_points[top_start + next_i]) # 顶部下一个点
surface_tool.generate_normals()
# 生成网格
var array_mesh = surface_tool.commit()
# 创建节点和材质
prism_mesh_instance = MeshInstance3D.new()
prism_mesh_instance.mesh = array_mesh
var material = StandardMaterial3D.new()
material.albedo_color = Color(0.2, 0.6, 0.8) # 蓝色
material.cull_mode = BaseMaterial3D.CULL_DISABLED # 禁用背面剔除
prism_mesh_instance.material_override = material
add_child(prism_mesh_instance)
print("基于不规则多边形底面创建棱柱体完成!点数:", point_count)
$Camera3D.position = Vector3(0,10,10)
$Camera3D.look_at(prism_mesh_instance.position)