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 можна використовувати лише в Мешах, які використовують PrimitiveType Mesh.PRIMITIVE_TRIANGLES.

Ми ініціалізуємо MeshDataTool з ArrayMesh, викликавши create_from_surface(). Якщо в MeshDataTool вже ініціалізовані дані, виклик очистить їх для вас. Крім того, ви можете викликати 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 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)