使用 MeshDataTool
MeshDataTool 不是用来生成几何体的,但它对动态改变几何体很有帮助,例如,如果你想写一个脚本来分割,简化或变形网格.
The MeshDataTool is not as fast as altering arrays directly using ArrayMesh. However, it provides more information and tools to work with meshes than the ArrayMesh does. When the MeshDataTool is used, it calculates mesh data that is not available in ArrayMeshes such as faces and edges, which are necessary for certain mesh algorithms. If you do not need this extra information then it may be better to use an ArrayMesh.
备注
MeshDataTool 只能用于使用 Mesh.PRIMITIVE_TRIANGLES PrimitiveType 的网格。
We initialize the MeshDataTool from an ArrayMesh by calling create_from_surface(). If there is already data initialized in the MeshDataTool,
calling create_from_surface() will clear it for you. Alternatively, you can call clear() yourself before re-using the MeshDataTool.
下面的例子中,假定已经创建了一个名叫 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);
}
}