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

Цей урок дасть основи використання ArrayMesh.

Ми будемо використовувати функцію add_surface_from_arrays(), яка приймає до чотирьох параметрів. Перші два обов'язкові, а другі два - необов'язкові.

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

Другий - arrays,це фактичний Масив, який зберігає інформацію про меш. Це звичайний масив Godot, побудований порожніми дужками []. Він зберігає Pool**Array (наприклад, PoolVector3Array, PoolIntArray тощо) для кожного типу інформації, яка буде використовуватися для побудови поверхні.

Можливі елементи arrays перераховані нижче, разом з позицією, яку вони повинні мати в межах arrays. Дивіться також Mesh.ArrayType.

Індекс

Mesh.ArrayType Enum

Тип масиву

0

ARRAY_VERTEX

PoolVector3Array, або PoolVector2Array

1

ARRAY_NORMAL

PoolVector3Array

2

ARRAY_TANGENT

PoolRealArray групи з 4-х десяткових. Перші 3 десяткові визначають тангенс, а останній - бінормальний напрямок типу -1, або 1.

3

ARRAY_COLOR

PoolColorArray

4

ARRAY_TEX_UV

PoolVector2Array, або PoolVector3Array

5

ARRAY_TEX_UV2

PoolVector2Array, або PoolVector3Array

6

ARRAY_BONES

PoolRealArray груп з 4-х десяткових, або PoolIntArray груп з 4-х цілих. Кожна група перераховує індекси 4-х кісток, які впливають на задану вершину.

7

ARRAY_WEIGHTS

PoolRealArray груп з 4-х десяткових. Кожне десяткове вказує силу ваги кістки, визначеної в ARRAY_BONES, на задану вершину.

8

ARRAY_INDEX

PoolIntArray

Масив вершин (з індексом 0) завжди обов'язковий. Масив індексів необов'язковий і використовується тільки в разі включення. Ми не будемо використовувати його тут.

Всі інші масиви несуть інформацію про вершини. Вони також необов'язкові і будуть використовуватися лише в тому випадку, якщо вони включені. Деякі з цих масивів (наприклад ARRAY_COLOR) використовують один запис на вершину, щоб надати додаткову інформацію про вершини. Вони повинні мати той же розмір, що і масив вершин. Інші масиви (наприклад ARRAY_TANGENT) використовують чотири записи для опису однієї вершини. Вони повинні бути рівно в чотири рази більше масиву вершин.

Для звичайного використання останні два параметри в add_surface_from_arrays() зазвичай залишаються порожніми.

ArrayMesh

У редакторі створіть MeshInstance і додайте йому ArrayMesh в Інспекторі. Як правило, додавання ArrayMesh в редактор не є корисним, але це дозволяє отримати доступ до масиву ArrayMesh з коду, без створення самого меша.

Далі додайте скрипт до MeshInstance.

Під _ready() створіть новий масив.

var surface_array = []

Це буде масив, в якому ми зберігаємо інформацію про нашу поверхню, він буде містити всі масиви даних, які потрібні поверхні. Godot очікує, що він буде розміром з Mesh.ARRAY_MAX, тому змініть його відповідно.

var surface_array = []
surface_array.resize(Mesh.ARRAY_MAX)

Далі створіть масиви для кожного типу даних, які ви будете використовувати.

var verts = PoolVector3Array()
var uvs = PoolVector2Array()
var normals = PoolVector3Array()
var indices = PoolIntArray()

Після того, як ви заповнили свої масиви даних геометрією, ви можете створити меш, додавши кожен масив до surface_array (масиву поверхні).

surface_array[Mesh.ARRAY_VERTEX] = verts
surface_array[Mesh.ARRAY_TEX_UV] = uvs
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices

mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) # No blendshapes or compression used.

Примітка

У цьому прикладі ми використовували Mesh.PRIMITIVE_TRIANGLES, але ви можете використовувати будь-який тип примітиву, доступний для меша.

В сукупності повний код виглядає так:

extends MeshInstance

func _ready():
    var surface_array= []
    surface_array.resize(Mesh.ARRAY_MAX)

    # PoolVector**Arrays for mesh construction.
    var verts = PoolVector3Array()
    var uvs = PoolVector2Array()
    var normals = PoolVector3Array()
    var indices = PoolIntArray()

    #######################################
    ## Insert code here to generate mesh ##
    #######################################

    # Assign arrays to mesh array.
    surface_array[Mesh.ARRAY_VERTEX] = verts
    surface_array[Mesh.ARRAY_TEX_UV] = uvs
    surface_array[Mesh.ARRAY_NORMAL] = normals
    surface_array[Mesh.ARRAY_INDEX] = indices

    # Create mesh surface from mesh array.
    mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) # No blendshapes or compression used.

Код в середині, може бути інший, залежно від вашого бажання. Нижче ми наведемо кілька прикладів коду для генерування сфери.

Генерування геометрії

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

extends MeshInstance

var rings = 50
var radial_segments = 50
var height = 1
var radius = 1

func _ready():

    # Insert setting up the PoolVector**Arrays here.

    # Vertex indices.
    var thisrow = 0
    var prevrow = 0
    var point = 0

    # Loop over rings.
    for i in range(rings + 1):
        var v = float(i) / rings
        var w = sin(PI * v)
        var y = cos(PI * v)

        # Loop over segments in ring.
        for j in range(radial_segments):
            var u = float(j) / radial_segments
            var x = sin(u * PI * 2.0)
            var z = cos(u * PI * 2.0)
            var vert = Vector3(x * radius * w, y, z * radius * w)
            verts.append(vert)
            normals.append(vert.normalized())
            uvs.append(Vector2(u, v))
            point += 1

            # Create triangles in ring using indices.
            if i > 0 and j > 0:
                indices.append(prevrow + j - 1)
                indices.append(prevrow + j)
                indices.append(thisrow + j - 1)

                indices.append(prevrow + j)
                indices.append(thisrow + j)
                indices.append(thisrow + j - 1)

        if i > 0:
            indices.append(prevrow + radial_segments - 1)
            indices.append(prevrow)
            indices.append(thisrow + radial_segments - 1)

            indices.append(prevrow)
            indices.append(prevrow + radial_segments)
            indices.append(thisrow + radial_segments - 1)

        prevrow = thisrow
        thisrow = point

  # Insert committing to the ArrayMesh here.

Збереження

Нарешті, ми можемо використати клас ResourceSaver, щоб зберегти ArrayMesh. Це корисно, коли ви хочете створити меш, а потім використовувати його пізніше без необхідності повторно генерувати.

# Saves mesh to a .tres file with compression enabled.
ResourceSaver.save("res://sphere.tres", mesh, ResourceSaver.FLAG_COMPRESS)