使用 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)

create_from_surface() 使用 ArrayMesh 中的頂點陣列來計算另外兩個陣列,一個是邊、一個是面,總計三個陣列。

邊緣是任意兩個頂點之間的連接. 邊緣陣列中的每一條邊緣都包含了對它所組成的兩個頂點的引用, 以及它所包含的最多的兩個面.

面是由三個頂點和三條對應的邊組成的三角形. 面陣列中的每個面都包含了它所組成的三個三角形和三條邊的參考.

頂點陣列包含與每個頂點相連的邊、面、法線、顏色、切線、uv、uv2、骨骼和權重信息。

為了從這些陣列中獲取資訊, 你可以使用 get_ **** () 的函式:

mdt.get_vertex_count() # Returns number of vertices in vertex array.
mdt.get_vertex_faces(0) # Returns array of faces that contain vertex[0].
mdt.get_face_normal(1) # Calculates and returns face normal of the second face.
mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.

你選擇用這些函式做什麼取決於你。一個常見的用例是對所有頂點進行反覆運算,並以某種方式對它們進行轉換:

for i in range(get_vertex_count):
    var vert = mdt.get_vertex(i)
    vert *= 2.0 # Scales the vertex by doubling size.
    mdt.set_vertex(i, vert)

這些修改不是在 ArrayMesh 上直接進行的。如果你要動態更新現有的 ArrayMesh,請在新增新表面前使用 commit_to_surface() 來刪除已有表面:

mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
mdt.commit_to_surface(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()
        # Push out vertex by noise.
        vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
        mdt.set_vertex(i, vertex)

    # Calculate 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 vertex position using vertex index.
        var ap = mdt.get_vertex(a)
        var bp = mdt.get_vertex(b)
        var cp = mdt.get_vertex(c)
        # Calculate face normal.
        var n = (bp - cp).cross(ap - bp).normalized()
        # Add face normal to current vertex normal.
        # 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 vertices one last time to normalize normals and
    # set color to normal.
    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)