Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

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