标题
[godot动态顶点生成]返璞归真经典 opengl 模式下的三角形如何在 godot 下实现
clq
浏览(7) +
2025-03-13 16:34:33 发表
编辑
关键字:
[2025-03-13 16:40:23 最后更新]
[godot动态顶点生成]返璞归真经典 opengl 模式下的三角形如何在 godot 下实现 https://www.bilibili.com/video/BV1o8QAY6Eap/ -------------------------------------------------------- godot 是很强大,但如果要绘制经典 opengl 风格的三个顶点组成的三角形应该如何实现呢? 这里要注意的是 godot 生成顶点的方法有好几种。注意参考官方文档 https://www.bookstack.cn/read/Godot-3.4-zh/bee3b17b697e13f3.md 本来想给大家小结一下各个生成顶点的方法的区别,但是自己也不熟悉,文档描述和 ai 的说法又小有出入。所以还是很出链接,大家在开发中多加留意区分和实测吧。[喜极而泣] 忘记说了选择的这种方式主要是更接近现在主流的 glb 模型格式,还可有助于模型格式的研究。另外很重要的一点,这里的法线指的是顶点的法线,和 blender 中的面法线是不同的,准确的来说面法线其实是顶点法线计算出来的,具体更详细的情况可以看我们之前的视频。 -------------------------------------------------------- 要注意的是用 MeshInstance3D 实现(ArrayMesh 方法)。在 godot 下有好几种动态生成顶点的方法,比较容易搞晕。 目前来看 ArrayMesh 法是最好或者说当下最合适的方法。 1.SurfaceTool 2.使用 ArrayMesh 直接定义顶点 3.使用 ImmediateGeometry 实时绘制 性能较低,不适合生成大量静态几何体。 无法直接保存为网格资源。 4.使用 MeshDataTool 编辑网格 避免在每帧中使用 MeshDataTool,因为它的性能开销较大。 -------------------------------------------------------- AI 说: 哪种方法最好? 如果需要动态生成复杂几何体,推荐使用 SurfaceTool 或 MeshDataTool。 如果需要快速生成简单几何体,推荐使用 ArrayMesh。 如果需要实时绘制动态几何体,推荐使用 ImmediateGeometry。 如果需要高级编辑功能,推荐使用 MeshDataTool。 对于大多数场景,ArrayMesh 是最简单和高效的选择。如果你需要更多的灵活性(如设置法线、UV 等),可以使用 SurfaceTool。 这和 https://www.bookstack.cn/read/Godot-3.4-zh/bee3b17b697e13f3.md 的说法有些差异。还是自己多实测吧。 -------------------------------------------------------- 我应该使用哪一个? 用哪种方法取决于你想做什么, 以及你能接受什么样的程序. SurfaceTool和ArrayMesh都是生成不随时间变化的静态几何体(网格)的绝佳工具. 使用 ArrayMesh 比使用 SurfaceTool 稍快一些,但 API 的难度更大一些。另外,SurfaceTool 还有一些便捷的方法,比如 generate_normals() 和 index()。 ImmediateGeometry 每一帧都会重新生成网格,所以它比 ArrayMesh 或 SurfaceTool 慢很多。然而,如果你本来就需要每一帧都改变几何体,它提供的接口更简单,甚至可能比每一帧生成一个 ArrayMesh 更快。 MeshDataTool 的速度并不快,但它可以让你访问网格的各种属性,而这些属性是其他工具无法获得的(边、面等)。当你需要根据这类数据来变换网格时,它是非常有用的,但如果不需要这些信息,就不适合使用。如果您要使用需要访问面数组或边数组的算法,最好使用 MeshDataTool。 ======================================================== 以下是与 ai 的对话,不一定正确,供参考。 godot 根据三个顶面生成一个面的方法有几种,哪种最好? -------------------------------------------------------- 在 Godot 中,根据三个顶点生成一个面(三角形)有几种方法,具体选择哪种方法取决于你的需求和场景。以下是常见的几种方法及其优缺点: 1. 使用 SurfaceTool 创建网格 SurfaceTool 是 Godot 中用于动态生成网格的工具。你可以通过它定义顶点、法线、UV 等属性,并生成一个面。 示例代码: gdscript 复制 extends MeshInstance func _ready(): var st = SurfaceTool.new() st.begin(Mesh.PRIMITIVE_TRIANGLES) # 定义三个顶点 st.add_vertex(Vector3(-1, 0, 0)) # 顶点 1 st.add_vertex(Vector3(1, 0, 0)) # 顶点 2 st.add_vertex(Vector3(0, 1, 0)) # 顶点 3 # 生成网格 var mesh = st.commit() self.mesh = mesh 优点: 灵活性强,可以自定义顶点、法线、UV 等属性。 适用于动态生成复杂的几何体。 缺点: 代码量稍多,适合需要精细控制的场景。 2. 使用 ArrayMesh 直接定义顶点 ArrayMesh 是 Godot 中用于通过数组数据创建网格的类。你可以直接传入顶点数组来生成面。 示例代码: gdscript 复制 extends MeshInstance func _ready(): var vertices = PoolVector3Array([ Vector3(-1, 0, 0), # 顶点 1 Vector3(1, 0, 0), # 顶点 2 Vector3(0, 1, 0), # 顶点 3 ]) var indices = PoolIntArray([0, 1, 2]) # 定义面的顶点索引 var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arrays[Mesh.ARRAY_INDEX] = indices var mesh = ArrayMesh.new() mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) self.mesh = mesh 优点: 代码简洁,适合快速生成简单的几何体。 性能较高,适合需要生成大量简单几何体的场景。 缺点: 灵活性较低,无法直接设置法线、UV 等属性。 3. 使用 ImmediateGeometry 实时绘制 ImmediateGeometry 是 Godot 中用于实时绘制几何体的节点。你可以逐顶点绘制面。 示例代码: gdscript 复制 extends ImmediateGeometry func _ready(): clear() begin(Mesh.PRIMITIVE_TRIANGLES) # 定义三个顶点 add_vertex(Vector3(-1, 0, 0)) # 顶点 1 add_vertex(Vector3(1, 0, 0)) # 顶点 2 add_vertex(Vector3(0, 1, 0)) # 顶点 3 end() 优点: 适合实时绘制动态几何体(如调试工具、动态效果)。 使用简单,适合快速原型开发。 缺点: 性能较低,不适合生成大量静态几何体。 无法直接保存为网格资源。 4. 使用 MeshDataTool 编辑网格 MeshDataTool 是 Godot 中用于编辑网格数据的工具。你可以通过它动态修改网格的顶点、面等属性。 示例代码: gdscript 复制 extends MeshInstance func _ready(): var mesh = ArrayMesh.new() var mdt = MeshDataTool.new() # 创建初始网格 var vertices = PoolVector3Array([ Vector3(-1, 0, 0), # 顶点 1 Vector3(1, 0, 0), # 顶点 2 Vector3(0, 1, 0), # 顶点 3 ]) var indices = PoolIntArray([0, 1, 2]) var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arrays[Mesh.ARRAY_INDEX] = indices mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) # 使用 MeshDataTool 编辑网格 mdt.create_from_surface(mesh, 0) self.mesh = mesh 优点: 适合需要对网格进行复杂编辑的场景。 可以访问和修改网格的顶点、面、法线等属性。 缺点: 代码量较多,适合高级用户。 5. 使用 Geometry 工具类 Godot 提供了 Geometry 工具类,可以用于生成几何体(如平面、球体等)。虽然它主要用于生成复杂几何体,但也可以用于生成简单的面。 示例代码: gdscript 复制 extends MeshInstance func _ready(): var vertices = PoolVector3Array([ Vector3(-1, 0, 0), # 顶点 1 Vector3(1, 0, 0), # 顶点 2 Vector3(0, 1, 0), # 顶点 3 ]) var mesh = ArrayMesh.new() var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) self.mesh = mesh 优点: 代码简洁,适合快速生成简单几何体。 缺点: 功能有限,无法直接生成复杂几何体。 哪种方法最好? 如果需要动态生成复杂几何体,推荐使用 SurfaceTool 或 MeshDataTool。 如果需要快速生成简单几何体,推荐使用 ArrayMesh。 如果需要实时绘制动态几何体,推荐使用 ImmediateGeometry。 如果需要高级编辑功能,推荐使用 MeshDataTool。 对于大多数场景,ArrayMesh 是最简单和高效的选择。如果你需要更多的灵活性(如设置法线、UV 等),可以使用 SurfaceTool。 ArrayMesh 中的顶点可以动态修改吗? 是的,ArrayMesh 中的顶点可以动态修改。Godot 提供了灵活的方式来更新 ArrayMesh 的顶点数据,适用于需要动态调整几何体的场景(如变形动画、实时生成地形等)。 如何动态修改 ArrayMesh 的顶点? 1. 使用 surface_get_arrays 和 surface_update_region 通过 surface_get_arrays 获取当前网格的表面数据。 修改顶点数据后,使用 surface_update_region 更新网格。 示例代码: gdscript 复制 extends MeshInstance func _ready(): # 创建初始网格 var vertices = PoolVector3Array([ Vector3(-1, 0, 0), # 顶点 1 Vector3(1, 0, 0), # 顶点 2 Vector3(0, 1, 0), # 顶点 3 ]) var indices = PoolIntArray([0, 1, 2]) var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arrays[Mesh.ARRAY_INDEX] = indices var mesh = ArrayMesh.new() mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) self.mesh = mesh func update_vertices(new_vertices: PoolVector3Array): if mesh.get_surface_count() > 0: var arrays = mesh.surface_get_arrays(0) arrays[Mesh.ARRAY_VERTEX] = new_vertices mesh.surface_update_region(0, arrays) 说明: surface_get_arrays 获取当前表面的数据。 surface_update_region 更新指定表面的数据。 2. 使用 SurfaceTool 重新生成网格 如果需要频繁修改顶点,可以使用 SurfaceTool 重新生成网格。 示例代码: gdscript 复制 extends MeshInstance func _ready(): generate_mesh([Vector3(-1, 0, 0), Vector3(1, 0, 0), Vector3(0, 1, 0)]) func generate_mesh(vertices: PoolVector3Array): var st = SurfaceTool.new() st.begin(Mesh.PRIMITIVE_TRIANGLES) for vertex in vertices: st.add_vertex(vertex) var mesh = st.commit() self.mesh = mesh 说明: 每次修改顶点时,调用 generate_mesh 重新生成网格。 3. 使用 MeshDataTool 修改顶点 MeshDataTool 提供了更高级的网格编辑功能,可以精确修改顶点、面、法线等属性。 示例代码: gdscript 复制 extends MeshInstance func _ready(): # 创建初始网格 var vertices = PoolVector3Array([ Vector3(-1, 0, 0), # 顶点 1 Vector3(1, 0, 0), # 顶点 2 Vector3(0, 1, 0), # 顶点 3 ]) var indices = PoolIntArray([0, 1, 2]) var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arrays[Mesh.ARRAY_INDEX] = indices var mesh = ArrayMesh.new() mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) self.mesh = mesh func update_vertices(new_vertices: PoolVector3Array): var mdt = MeshDataTool.new() if mdt.create_from_surface(mesh, 0) == OK: for i in range(mdt.get_vertex_count()): mdt.set_vertex(i, new_vertices[i]) mesh.surface_remove(0) mdt.commit_to_surface(mesh) 说明: MeshDataTool 可以精确修改每个顶点的属性。 修改后,使用 commit_to_surface 将数据写回网格。 性能考虑 频繁修改顶点: 如果顶点数据需要频繁修改(如每帧更新),建议使用 SurfaceTool 或 ArrayMesh 的 surface_update_region。 避免在每帧中使用 MeshDataTool,因为它的性能开销较大。 静态或低频修改: 如果顶点数据不需要频繁修改,可以使用 MeshDataTool 进行精确编辑。 总结 ArrayMesh 支持动态修改顶点,可以通过 surface_get_arrays 和 surface_update_region 实现。 SurfaceTool 适合重新生成网格,适合频繁修改的场景。 MeshDataTool 提供了更高级的编辑功能,适合需要精确修改的场景。 根据你的需求选择合适的方法即可! surface_update_region 如何使用 surface_update_region 是 Godot 中用于更新 ArrayMesh 表面数据的函数。它允许你更新网格的某一部分(如顶点、法线、UV 等),而不需要重新生成整个网格。这在需要动态修改网格数据时非常有用。 surface_update_region 的基本用法 函数签名 gdscript 复制 void surface_update_region(int surface, Array arrays, int offset = 0, int count = -1) surface:要更新的表面索引(从 0 开始)。 arrays:包含更新数据的数组,格式与 add_surface_from_arrays 相同。 offset:更新的起始位置(默认为 0)。 count:更新的元素数量(默认为 -1,表示更新到数组末尾)。 使用步骤 获取当前表面的数据(使用 surface_get_arrays)。 修改需要更新的部分数据。 调用 surface_update_region 更新网格。 示例代码 以下是一个完整的示例,展示如何使用 surface_update_region 动态更新网格的顶点数据: gdscript 复制 extends MeshInstance func _ready(): # 创建初始网格 var vertices = PoolVector3Array([ Vector3(-1, 0, 0), # 顶点 1 Vector3(1, 0, 0), # 顶点 2 Vector3(0, 1, 0), # 顶点 3 ]) var indices = PoolIntArray([0, 1, 2]) var arrays = [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arrays[Mesh.ARRAY_INDEX] = indices var mesh = ArrayMesh.new() mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) self.mesh = mesh func update_vertices(new_vertices: PoolVector3Array): if mesh.get_surface_count() > 0: # 获取当前表面的数据 var arrays = mesh.surface_get_arrays(0) # 更新顶点数据 arrays[Mesh.ARRAY_VERTEX] = new_vertices # 更新网格表面 mesh.surface_update_region(0, arrays) 详细说明 创建初始网格: 使用 add_surface_from_arrays 创建一个包含三个顶点的三角形网格。 更新顶点数据: 调用 surface_get_arrays 获取当前表面的数据。 修改 arrays 中的顶点数据(Mesh.ARRAY_VERTEX)。 调用 surface_update_region 更新网格。 动态更新: 可以在运行时调用 update_vertices 函数,传入新的顶点数据来更新网格。 更新部分数据 如果你只需要更新部分顶点(而不是全部顶点),可以通过 offset 和 count 参数指定更新的范围。 示例:更新部分顶点 gdscript 复制 func update_partial_vertices(new_vertices: PoolVector3Array, offset: int, count: int): if mesh.get_surface_count() > 0: # 获取当前表面的数据 var arrays = mesh.surface_get_arrays(0) # 更新部分顶点数据 for i in range(count): arrays[Mesh.ARRAY_VERTEX][offset + i] = new_vertices[i] # 更新网格表面 mesh.surface_update_region(0, arrays, offset, count) 注意事项 性能: surface_update_region 的性能优于完全重新生成网格,但仍需避免每帧频繁调用。 如果需要每帧更新,建议使用 ImmediateGeometry 或 SurfaceTool。 数据一致性: 更新顶点数据时,确保其他相关数据(如法线、UV 等)也保持一致。 如果需要更新法线或 UV,可以同时修改 arrays 中的 Mesh.ARRAY_NORMAL 或 Mesh.ARRAY_TEX_UV。 索引数据: 如果修改了顶点数据,可能需要同时更新索引数据(Mesh.ARRAY_INDEX),以确保面片正确连接。 总结 surface_update_region 是动态更新 ArrayMesh 数据的有效方法。 它允许你更新网格的某一部分,而不需要重新生成整个网格。 适用于需要动态修改顶点、法线、UV 等属性的场景。 通过合理使用 surface_update_region,你可以在 Godot 中实现高效的动态网格更新!
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.