Использование ArrayMesh¶
В этом уроке будут представлены основы использования ArrayMesh.
Для этого мы будем использовать функцию add_surface_from_arrays(), которая принимает до четырех параметров. Первые два являются обязательными, а вторые два - необязательными.
Первым параметром является PrimitiveType
, концепция OpenGL, которая указывает GPU, как расположить примитив на основе заданных вершин, т.е. представляют ли они треугольники, линии, точки и т.д. Доступные варианты см. в Mesh.PrimitiveType.
Второй параметр, arrays
, является фактическим массивом, который хранит информацию о сетке. Массив представляет собой обычный массив Godot, построенный с помощью пустых скобок []
. Он хранит Pool**Array
(например, PoolVector3Array, PoolIntArray и т.д.) для каждого типа информации, которая будет использоваться для построения поверхности.
Возможные элементы arrays
перечислены ниже, вместе с позицией, которую они должны иметь в пределах arrays
. См. также Mesh.ArrayType.
Индекс |
Mesh.ArrayType - перечисление |
Тип массива |
---|---|---|
0 |
|
|
1 |
|
|
2 |
|
PoolRealArray группа из 4 вещественных чисел. Первые 3 числа определяют тангенс, а последний - бинормальное направление как -1 или 1. |
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
PoolRealArray группа из 4 вещественных чисел или PoolIntArray групп из 4 целых чисел. Каждая группа перечисляет индексы 4 костей, которые влияют на данную вершину. |
7 |
|
PoolRealArray группа из 4 вещественных числе. Каждое число перечисляет количество веса, которое определенная кость на |
8 |
|
Массив вершин (с индексом 0) всегда обязателен. Массив индексов является необязательным и будет использоваться только в том случае, если он включен. Мы не будем использовать его в этом уроке.
Все остальные массивы несут информацию о вершинах. Они также являются необязательными и будут использоваться только в том случае, если они включены. Некоторые из этих массивов (например, ARRAY_COLOR
) используют по одной записи на вершину, чтобы предоставить дополнительную информацию о вершинах. Они должны иметь тот же размер, что и массив вершин. Другие массивы (например, ARRAY_TANGENT
) используют четыре записи для описания одной вершины. Они должны быть ровно в четыре раза больше, чем массив вершин.
Для обычного использования последние два параметра в add_surface_from_arrays() обычно оставляют пустыми.
ArrayMеsh¶
В редакторе создайте 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. Эта реализация не имеет ничего общего с ArrayMeshes и является просто общим подходом к генерации сферы. Если у вас возникли трудности с пониманием или вы хотите узнать больше о процедурной геометрии в целом, вы можете воспользоваться любым учебником, который найдете в Интернете.
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)