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.

Використання MeshDataTool

MeshDataTool не використовується для створення геометрії. Але він корисний для динамічної зміни геометрії, наприклад, якщо ви хочете написати скрипт для тесселяції, спрощення, або деформування, меша.

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

Примітка

MeshDataTool можна використовувати лише в Мешах, які використовують PrimitiveType Mesh.PRIMITIVE_TRIANGLES.

Ми ініціалізуємо MeshDataTool з ArrayMesh, викликаючи create_from_surface(). Якщо в MeshDataTool вже є ініціалізовані дані, виклик create_from_surface() очистить їх. Або ж ви можете самостійно викликати clear() перед повторним використанням MeshDataTool.

У наведених нижче прикладах припустимо, що ArrayMesh під назвою mesh вже створено. Перегляньте зразок генерації меша в посібнику ArrayMesh.

var mdt = MeshDataTool.new()
mdt.create_from_surface(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.

Те, що ви вирішите зробити за допомогою цих функцій, залежить від вас. Поширений випадок використання полягає в тому, щоб ітерувати всі вершини і перетворити їх певним чином:

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)

Ці зміни не виконуються зразу на 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()
        # 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)