Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
使用 MeshDataTool
MeshDataTool 不是用来生成几何体的,但它对动态改变几何体很有帮助,例如,如果你想写一个脚本来分割,简化或变形网格.
MeshDataTool不像直接使用 ArrayMesh 修改数组那么快。但是,它提供了比ArrayMesh更多的信息和工具来处理网格。当使用MeshDataTool时,它会计算ArrayMeshes中没有的网格数据,如面和边,这些数据对于某些网格算法来说是必要的。如果你不需要这些额外的信息,那么使用ArrayMesh可能会更好。
备注
MeshDataTool 只能用于使用 Mesh.PRIMITIVE_TRIANGLES PrimitiveType 的网格。
我们通过调用 create_from_surface() 来使用 ArrayMesh 初始化 MeshDataTool。如果该 MeshDataTool 中已经有初始化的数据了,调用 create_from_surface() 会为你将其清除。或者你可以在重用 MeshDataTool 之前自己调用 clear() 。
下面的例子中,假定已经创建了一个名叫 mesh 的 ArrayMesh。网格生成的示例见 ArrayMesh 教程。
var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh, 0)
var mdt = new MeshDataTool();
mdt.CreateFromSurface(mesh, 0);
create_from_surface() 使用 ArrayMesh 中的顶点数组来计算另外两个数组,一个是边、一个是面,总计三个数组。
边缘是任意两个顶点之间的连接. 边缘数组中的每一条边缘都包含了对它所组成的两个顶点的引用,以及它所包含的最多的两个面.
面是由三个顶点和三条对应的边组成的三角形. 面数组中的每个面都包含了它所组成的三个三角形和三条边的参考.
顶点数组包含与每个顶点相连的边、面、法线、颜色、切线、uv、uv2、骨骼和权重信息。
为了从这些数组中获取信息,你可以使用 get_ **** () 的函数:
mdt.get_vertex_count() # Returns the number of vertices in the vertex array.
mdt.get_vertex_faces(0) # Returns an array of faces that contain vertex[0].
mdt.get_face_normal(1) # Calculates and returns the face normal of the second face.
mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.
mdt.GetVertexCount(); // Returns the number of vertices in the vertex array.
mdt.GetVertexFaces(0); // Returns an array of faces that contain vertex[0].
mdt.GetFaceNormal(1); // Calculates and returns the face normal of the second face.
mdt.GetEdgeVertex(10, 1); // Returns the second vertex comprising the edge at index 10.
你选择用这些函数做什么取决于你。一个常见的用例是对所有顶点进行迭代,并以某种方式对它们进行转换:
for i in range(mdt.get_vertex_count()):
var vert = mdt.get_vertex(i)
vert *= 2.0 # Scales the vertex by doubling its size.
mdt.set_vertex(i, vert)
for (var i = 0; i < mdt.GetVertexCount(); i++)
{
Vector3 vert = mdt.GetVertex(i);
vert *= 2.0f; // Scales the vertex by doubling its size.
mdt.SetVertex(i, vert);
}
这些修改不是在 ArrayMesh 上直接进行的。如果你要动态更新现有的 ArrayMesh,请在添加新表面前使用 commit_to_surface() 来删除已有表面:
mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
mdt.commit_to_surface(mesh)
mesh.ClearSurfaces(); // Deletes all of the mesh's surfaces.
mdt.CommitToSurface(mesh);
下面是一个完整的示例,将一个叫做 mesh 的球体网格变成随机变形的块状,并更新了法线和顶点颜色。如何生成基础网格见 ArrayMesh 教程。
extends MeshInstance3D
var fnl = FastNoiseLite.new()
var mdt = MeshDataTool.new()
func _ready():
fnl.frequency = 0.7
mdt.create_from_surface(mesh, 0)
for i in range(mdt.get_vertex_count()):
var vertex = mdt.get_vertex(i).normalized()
# Scale the vertices using noise.
vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
mdt.set_vertex(i, vertex)
# Calculate the vertex normals, face-by-face.
for i in range(mdt.get_face_count()):
# Get the index in the vertex array.
var a = mdt.get_face_vertex(i, 0)
var b = mdt.get_face_vertex(i, 1)
var c = mdt.get_face_vertex(i, 2)
# Get the vertex position using the vertex index.
var ap = mdt.get_vertex(a)
var bp = mdt.get_vertex(b)
var cp = mdt.get_vertex(c)
# Calculate the normal of the face.
var n = (bp - cp).cross(ap - bp).normalized()
# Add this face normal to the current vertex normals.
# This will not result in perfect normals, but it will be close.
mdt.set_vertex_normal(a, n + mdt.get_vertex_normal(a))
mdt.set_vertex_normal(b, n + mdt.get_vertex_normal(b))
mdt.set_vertex_normal(c, n + mdt.get_vertex_normal(c))
# Run through the vertices one last time to normalize their normals and
# set the vertex colors to these new normals.
for i in range(mdt.get_vertex_count()):
var v = mdt.get_vertex_normal(i).normalized()
mdt.set_vertex_normal(i, v)
mdt.set_vertex_color(i, Color(v.x, v.y, v.z))
mesh.clear_surfaces()
mdt.commit_to_surface(mesh)
using Godot;
public partial class MyMeshInstance3D : MeshInstance3D
{
MeshDataTool mdt = new MeshDataTool();
FastNoiseLite fnl = new FastNoiseLite();
public override void _Ready()
{
fnl.Frequency = 0.7f;
ArrayMesh mesh = Mesh as ArrayMesh; // The mesh assigned the MeshInstance3D needs to be an ArrayMesh.
mdt.CreateFromSurface(mesh, 0);
for (var i = 0; i < mdt.GetVertexCount(); i++)
{
Vector3 vertex = mdt.GetVertex(i).Normalized();
// Scale the vertices using noise.
vertex = vertex * (fnl.GetNoise3Dv(vertex) * 0.5f + 0.75f);
mdt.SetVertex(i, vertex);
}
// Calculate the vertex normals, face-by-face.
for (var i = 0; i < mdt.GetFaceCount(); i++)
{
// Get the index in the vertex array.
var a = mdt.GetFaceVertex(i, 0);
var b = mdt.GetFaceVertex(i, 1);
var c = mdt.GetFaceVertex(i, 2);
// Get the vertex position using the vertex index.
var ap = mdt.GetVertex(a);
var bp = mdt.GetVertex(b);
var cp = mdt.GetVertex(c);
// Calculate the normal of the face.
var n = (bp - cp).Cross(ap - bp).Normalized();
// Add this face normal to the current vertex normals.
// This will not result in perfect normals, but it will be close.
mdt.SetVertexNormal(a, n + mdt.GetVertexNormal(a));
mdt.SetVertexNormal(b, n + mdt.GetVertexNormal(b));
mdt.SetVertexNormal(c, n + mdt.GetVertexNormal(c));
}
// Run through the vertices one last time to normalize their normals and
// set the vertex colors to these new normals.
for (var i = 0; i < mdt.GetVertexCount(); i++)
{
var v = mdt.GetVertexNormal(i).Normalized();
mdt.SetVertexNormal(i, v);
mdt.SetVertexColor(i, new Color(v.X, v.Y, v.Z));
}
mesh.ClearSurfaces();
mdt.CommitToSurface(mesh);
}
}