Godot 城市模拟 – 003 根据不规则底面和高度,动态创建节点
本文最后更新于17 天前

下面我将详细分解这段代码的每个步骤,展示如何在 Godot 引擎中从零开始创建一个不规则棱柱体并实现旋转动画:

步骤1:设置场景基础结构

extends Node3D  # 继承自3D场景节点

var prism_mesh_instance: MeshInstance3D  # 声明棱柱体网格实例变量
  • 脚本继承自 Node3D,这是所有3D场景的基类
  • 声明一个 MeshInstance3D 类型的变量,用于存储创建的棱柱体

步骤2:初始化场景 (_ready 函数)

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 验证输入和准备数据

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 计算顶点位置

    # 添加底面顶点
    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 创建网格

    # 初始化SurfaceTool
    var surface_tool = SurfaceTool.new()
    surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
  • 创建 SurfaceTool 实例,用于动态生成网格
  • 指定网格使用三角形图元

3.4 创建底面

    # 计算底面中心点(用于三角剖分)
    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 创建顶面

    # 计算顶面中心点
    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 创建侧面

    # 创建侧面(四边形分解为两个三角形)
    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])   # 顶部下一个点
  • 每个侧面由四边形组成
  • 每个四边形被分解为两个三角形:
    1. 底部点A → 顶部点A → 底部点B
    2. 底部点B → 顶部点A → 顶部点B
  • 确保所有三角形顶点顺序为逆时针(保证法线方向正确)

3.7 生成网格和材质

    # 生成法线(用于光照计算)
    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 设置摄像机视角

    # 定位摄像机
    $Camera3D.position = Vector3(0, 10, 10)  # 摄像机位置(斜上方)
    $Camera3D.look_at(prism_mesh_instance.position)  # 看向棱柱体中心
  • 将摄像机放置在 (0, 10, 10) 位置
  • 让摄像机看向棱柱体中心点 (0, 0, 0)

步骤4:实现旋转动画 (_process 函数)

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 保证旋转速度与帧率无关

最终效果

当运行此代码时:

  1. 场景初始化时创建一个不规则五边形底面的棱柱体
  2. 棱柱体呈现蓝色,禁用背面剔除
  3. 摄像机从斜上方 (0,10,10) 位置看向棱柱体中心
  4. 棱柱体以每秒30度的速度绕Y轴匀速旋转

完整代码

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)


扫码关注,及时关注技术动态


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇