登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 开发 vlog >> 主题: [godot动态顶点生成]返璞归真经典 opengl 模式下的三角形如何在 godot 下实现     [回主站]     [分站链接]
标题
[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 中实现高效的动态网格更新!




总数:0 页次:1/0 首页 尾页  
总数:0 页次:1/0 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1