如何在Godot: Triangle Fan中制作PLY解析器



我一直在为Godot中的着色3D模型创建工具,但我需要能够将PLY格式转换为Godot中的SurfaceTool。PLY格式有一个头,解释结构是什么,然后给出数据。下面是一个立方体的例子:

ply
format ascii 1.0
comment made by Greg Turk
comment this file is a cube
element vertex 8
property float x
property float y
property float z
element face 6
property list uchar int vertex_index
end_header
0 0 0
0 0 1
0 1 1
0 1 0
1 0 0
1 0 1
1 1 1
1 1 0
4 0 1 2 3
4 7 6 5 4
4 0 4 5 1
4 1 5 6 2
4 2 6 7 3
4 3 7 4 0

我把不同的数组顶点和面信息在header。我已经创建了这样的网格:

var meshBuilder = SurfaceTool.new()
meshBuilder.begin(Mesh.PRIMITIVE_TRIANGLE_FAN)

我已经添加了这样的顶点:

for i in range(vertex_count):
meshBuilder.add_normal(Vector3.UP)
meshBuilder.add_vertex(Vector3(float(data[0]),
float(data[1]),
float(data[2])))
line = loadedFile.get_line()
if line == "":
break
data = line.split(" ")

但我不知道如何添加面孔。它是一个三角形扇形,其中第一个面4 0 1 2 3是4个顶点,由三角形0 1 2和0 2 3组成,而不是0 1 2和1 2 3。这是所用顶点的顺序

也许我应该按照面的顺序添加顶点但我不知道如何使用add_uv因为我被告知要使用它

首先,不要直接将顶点添加到SurfaceTool。您将把顶点存储在数组中,然后根据从文件中读取的面添加顶点。

第二,在PLY格式中,每个是一个三角扇形。整个不是一个三角球迷。此外,SurfaceTool将不允许您一次创建多个三角形风扇(第二次调用begin内部调用clear)。因此,我们需要在创建三角形扇形时提交它们。

顺便说一下,在你的例子中没有UV(纹理坐标)


让我们首先将顶点存储到一个数组中(假设您只是读取"end_header"):

var vertex_array:Array = []
for vertex_index in vertex_count:
line = loadedFile.get_line()
data = line.split(" ")
var vertex := Vector3(float(data[0]), float(data[1]), float(data[2]))
vertex_array.append(vertex)

然后我们需要读取面部:

var mesh := ArrayMesh.new()
var mesh_builder := SurfaceTool.new()
for face_index in faces_count:
line = loadedFile.get_line()
data = line.split(" ")
mesh_builder.begin(Mesh.PRIMITIVE_TRIANGLE_FAN)
for face_vertex_index in range(1, data.size()):
mesh_builder.add_vertex(vertex_array[int(data[face_vertex_index])])
mesh_builder.commit(mesh)

注意,我确实放弃了处理面部顶点的数量(data[0])。相反,我通过使用range(1, data.size())跳过它(如果我们包含它,范围将从0而不是1开始)。data中的其他值是存储顶点的数组的索引。

所以4 0 1 2 3意味着我需要从位于位置0,1,23的数组中获取顶点(正如我所说,我放弃了处理4)。


设置法线需要额外的工作。我们需要分别处理每个三角形(不是每个三角形扇形),并计算法线。

法向量垂直于三角形,我们可以通过顶点差的叉乘来计算。这意味着我们需要一组顶点组成每个三角形,来计算它们的法线。

如果我们要单独处理每个三角形,我们不妨使用PRIMITIVE_TRIANGLESgenerate_normals(只有当我们使用PRIMITIVE_TRIANGLES时才有效):

var mesh := ArrayMesh.new()
var mesh_builder := SurfaceTool.new()
for face_index in faces_count:
line = loadedFile.get_line()
data = line.split(" ")
mesh_builder.begin(Mesh.PRIMITIVE_TRIANGLES)
for triangle_index in range(2, data.size() - 1):
mesh_builder.add_vertex(vertex_array[int(data[1])])
mesh_builder.add_vertex(vertex_array[int(data[triangle_index])])
mesh_builder.add_vertex(vertex_array[int(data[triangle_index + 1])])
surface_tool.generate_normals()
mesh_builder.commit(mesh)

记住它们被存储为三角形扇形。它们都共享第一个顶点(data[1])。因此,在4 0 1 2 3中,三角形共享存储在数组中位置0的顶点。

我们可以遍历data来获得第二个顶点。这意味着这次我们需要跳过两个元素(40),因此range(2, data.size() - 1)中的2

最后,第三个顶点总是第二个顶点之后的下一个。这也意味着我们不能迭代到最后,因此range(2, data.size() - 1)中的- 1


之后,您可以将mesh设置为MeshIntance

最新更新