Використання ArrayMesh¶
Цей урок дасть основи використання ArrayMesh.
Ми будемо використовувати функцію add_surface_from_arrays(), яка приймає до чотирьох параметрів. Перші два обов'язкові, а другі два - необов'язкові.
Перший параметр - PrimitiveType
, це концепція OpenGL, яка інструктує графічний процесор, як розташувати примітив на основі вершин, враховуючи, чи це трикутники, лінії, точки тощо. Повний список варіантів дивіться в Mesh.PrimitiveType.
Другий - arrays
,це фактичний Масив, який зберігає інформацію про меш. Це звичайний масив Godot, побудований порожніми дужками []
. Він зберігає Pool**Array
(наприклад, PoolVector3Array, PoolIntArray тощо) для кожного типу інформації, яка буде використовуватися для побудови поверхні.
Можливі елементи arrays
перераховані нижче, разом з позицією, яку вони повинні мати в межах arrays
. Дивіться також Mesh.ArrayType.
Індекс |
Mesh.ArrayType Enum |
Тип масиву |
---|---|---|
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() зазвичай залишаються порожніми.
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)