Using the MeshDataTool

Инструмент MeshDataTool не используется для создания геометрии. Но он полезен для динамического изменения геометрии, например, если вы хотите написать сценарий для тесселяции, упрощения или деформации сетки.

MeshDataTool работает не так быстро, как изменение массивов непосредственно с помощью ArrayMesh. Однако он предоставляет больше информации и инструментов для работы с сетками, чем ArrayMesh. Когда используется MeshDataTool, он вычисляет данные сетки, которые недоступны в массивах, таких как грани и ребра, которые необходимы для определенных алгоритмов сетки. Если вам не нужна эта дополнительная информация, то, возможно, лучше использовать ArrayMesh.

Примечание

MeshDataTool можно использовать только в сетках, использующих примитивный тип Mesh.PRIMITIVE_TRIANGLES.

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.

In the examples below, assume an ArrayMesh called mesh has already been created. See ArrayMesh tutorial for an example of mesh generation.

var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh, 0)

create_from_surface() uses the vertex arrays from the ArrayMesh to calculate two additional arrays, one for edges and one for faces, for a total of three arrays.

Ребро - это соединение между любыми двумя вершинами. Каждое ребро в массиве ребер содержит ссылку на две вершины, из которых оно состоит, и до двух граней, внутри которых оно содержится.

Грань - это треугольник, состоящий из трех вершин и трех соответствующих ребер. Каждая грань в массиве граней содержит ссылку на три вершины и три ребра, из которых она состоит.

The vertex array contains edge, face, normal, color, tangent, uv, uv2, bone, and weight information connected with each vertex.

Для доступа к информации из этих массивов вы используете функцию вида 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)

These modifications are not done in place on the ArrayMesh. If you are dynamically updating an existing ArrayMesh, first delete the existing surface before adding a new one using commit_to_surface():

mesh.surface_remove(0) # Deletes the first surface of the mesh.
mdt.commit_to_surface(mesh)

Below is a complete example that turns a spherical mesh called mesh into a randomly deformed blob complete with updated normals and vertex colors. See ArrayMesh tutorial for how to generate the base mesh.

extends MeshInstance

var sn = OpenSimplexNoise.new()
var mdt = MeshDataTool.new()

func _ready():
    sn.period = 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 * (sn.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.surface_remove(0)
    mdt.commit_to_surface(mesh)