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.
Checking the stable version of the documentation...
결과 시험하기
이 튜토리얼에서는 ArrayMesh 사용의 기본 사항을 제시합니다.
이를 위해 최대 5개의 매개변수를 사용하는 add_surface_from_arrays() 함수를 사용합니다. 처음 두 개는 필수이고 마지막 세 개는 선택 사항입니다.
첫 번째 매개변수는 주어진 정점을 기반으로 프리미티브를 정렬하는 방법(예: 삼각형, 선, 점 등을 나타내는지 여부)을 GPU에 지시하는 OpenGL 개념인 ``PrimitiveType``입니다. 사용 가능한 옵션은 :ref:`Mesh.PrimitiveType <enum_Mesh_PrimitiveType>`을 참조하세요.
두 번째 파라미터 ``arrays``는 메쉬 정보를 저장하는 실제 Array입니다. 배열은 빈 괄호 ``[]``로 구성된 일반 Godot 배열입니다. 표면을 구축하는 데 사용될 각 정보 유형에 대해 ``Packed**Array``(예: PackedVector3Array, PackedInt32Array 등)를 저장합니다.
arrays``의 공통 요소는 ``arrays 내에서 가져야 하는 위치와 함께 아래에 나열되어 있습니다. 전체 목록은 :ref:`Mesh.ArrayType <enum_Mesh_ArrayType>`을 참조하세요.
인덱스 |
Mesh.ArrayType 열거형 |
배열 패턴(Array pattern) |
|---|---|---|
0 |
|
PoolVector2Array: Vector2 오브젝트의 배열. |
1 |
|
|
2 |
|
PackedFloat32Array 또는 PackedFloat64Array 플로트 4개 그룹. 처음 3개의 부동 소수점은 접선을 결정하고 마지막 부동 소수점은 종법선 방향을 -1 또는 1로 결정합니다. |
3 |
|
|
4 |
|
PoolVector2Array: Vector2 오브젝트의 배열. |
5 |
|
PoolVector2Array: Vector2 오브젝트의 배열. |
10 |
|
PackedFloat32Array 4개 부동소수점 그룹 또는 PackedInt32Array 4개 정수 그룹. 각 그룹은 특정 정점에 영향을 미치는 4개 뼈의 인덱스를 나열합니다. |
11 |
|
PackedFloat32Array 또는 PackedFloat64Array 플로트 4개 그룹. 각 부동 소수점은 지정된 정점에서 ``ARRAY_BONES``의 해당 뼈대가 갖는 가중치의 양을 나열합니다. |
12 |
|
대부분의 경우 메시를 생성할 때 정점 위치로 정의합니다. 따라서 일반적으로 정점 배열(인덱스 0)은 필수인 반면, 인덱스 배열(인덱스 12)은 선택 사항이며 포함된 경우에만 사용됩니다. 정점 배열 없이 인덱스 배열만 사용하여 메쉬를 만드는 것도 가능하지만 이는 이 튜토리얼의 범위를 벗어납니다.
다른 모든 배열은 정점에 대한 정보를 전달합니다. 이는 선택 사항이며 포함된 경우에만 사용됩니다. 이러한 배열 중 일부(예: ARRAY_COLOR)는 정점에 대한 추가 정보를 제공하기 위해 정점당 하나의 항목을 사용합니다. 정점 배열과 크기가 동일해야 합니다. 다른 배열(예: ARRAY_TANGENT)은 4개의 항목을 사용하여 단일 정점을 설명합니다. 이는 정점 배열보다 정확히 4배 커야 합니다.
일반적인 사용의 경우 :ref:`add_surface_from_arrays() <class_arraymesh_method_add_surface_from_arrays>`의 마지막 세 매개 변수는 일반적으로 비어 있습니다.
결과 시험하기
편집기에서 :ref:`MeshInstance3D <class_meshinstance3d>`을 생성하고 인스펙터에 :ref:`ArrayMesh <class_arraymesh>`를 추가합니다. 일반적으로 편집기에서 ArrayMesh를 추가하는 것은 유용하지 않지만 이 경우 ArrayMesh를 생성하지 않고도 코드에서 액세스할 수 있습니다.
노드에 스크립트를 추가하기.
_ready() 아래에서 새 어레이를 생성합니다.
var surface_array = []
Godot.Collections.Array surfaceArray = [];
이는 표면 정보를 보관하는 배열이 됩니다. 표면에 필요한 모든 데이터 배열을 보관하게 됩니다. Godot는 크기가 ``Mesh.ARRAY_MAX``일 것으로 예상하므로 그에 맞게 크기를 조정하세요.
var surface_array = []
surface_array.resize(Mesh.ARRAY_MAX)
Godot.Collections.Array surfaceArray = [];
surfaceArray.Resize((int)Mesh.ArrayType.Max);
다음으로 사용할 각 데이터 유형에 대한 배열을 만듭니다.
var verts = PackedVector3Array()
var uvs = PackedVector2Array()
var normals = PackedVector3Array()
var indices = PackedInt32Array()
List<Vector3> verts = [];
List<Vector2> uvs = [];
List<Vector3> normals = [];
List<int> indices = [];
데이터 배열을 형상으로 채웠으면 각 배열을 ``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
# No blendshapes, lods, or compression used.
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
surfaceArray[(int)Mesh.ArrayType.Vertex] = verts.ToArray();
surfaceArray[(int)Mesh.ArrayType.TexUV] = uvs.ToArray();
surfaceArray[(int)Mesh.ArrayType.Normal] = normals.ToArray();
surfaceArray[(int)Mesh.ArrayType.Index] = indices.ToArray();
var arrMesh = Mesh as ArrayMesh;
if (arrMesh != null)
{
// No blendshapes, lods, or compression used.
arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, surfaceArray);
}
참고
이 예에서는 ``Mesh.PRIMITIVE_TRIANGLES``를 사용했지만 메시에서 사용 가능한 모든 기본 유형을 사용할 수 있습니다.
전체 코드를 종합하면 다음과 같습니다.
extends MeshInstance3D
func _ready():
var surface_array = []
surface_array.resize(Mesh.ARRAY_MAX)
# PackedVector**Arrays for mesh construction.
var verts = PackedVector3Array()
var uvs = PackedVector2Array()
var normals = PackedVector3Array()
var indices = PackedInt32Array()
#######################################
## Insert code here to generate mesh ##
#######################################
# Assign arrays to 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
# Create mesh surface from mesh array.
# No blendshapes, lods, or compression used.
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
public partial class MyMeshInstance3D : MeshInstance3D
{
public override void _Ready()
{
Godot.Collections.Array surfaceArray = [];
surfaceArray.Resize((int)Mesh.ArrayType.Max);
// C# arrays cannot be resized or expanded, so use Lists to create geometry.
List<Vector3> verts = [];
List<Vector2> uvs = [];
List<Vector3> normals = [];
List<int> indices = [];
/***********************************
* Insert code here to generate mesh.
* *********************************/
// Convert Lists to arrays and assign to surface array
surfaceArray[(int)Mesh.ArrayType.Vertex] = verts.ToArray();
surfaceArray[(int)Mesh.ArrayType.TexUV] = uvs.ToArray();
surfaceArray[(int)Mesh.ArrayType.Normal] = normals.ToArray();
surfaceArray[(int)Mesh.ArrayType.Index] = indices.ToArray();
var arrMesh = Mesh as ArrayMesh;
if (arrMesh != null)
{
// Create mesh surface from mesh array
// No blendshapes, lods, or compression used.
arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, surfaceArray);
}
}
}
중간에 들어가는 코드는 원하는 대로 지정할 수 있습니다. 아래에서는 직사각형으로 시작하여 모양을 생성하는 몇 가지 예제 코드를 제시합니다.
PCK 파일 생성하기
``Mesh.PRIMITIVE_TRIANGLES``를 사용하여 렌더링하므로 삼각형으로 직사각형을 구성합니다.
직사각형은 4개의 꼭지점을 공유하는 두 개의 삼각형으로 구성됩니다. 이 예에서는 아래와 같이 너비와 길이가 1인 ``(0, 0, 0)``에 왼쪽 상단 지점이 있는 직사각형을 만듭니다.
이 직사각형을 그리려면 verts 배열에서 각 꼭지점의 좌표를 정의하십시오.
verts = PackedVector3Array([
Vector3(0, 0, 0),
Vector3(0, 0, 1),
Vector3(1, 0, 0),
Vector3(1, 0, 1),
])
verts.AddRange(new Vector3[]
{
new Vector3(0, 0, 0),
new Vector3(0, 0, 1),
new Vector3(1, 0, 0),
new Vector3(1, 0, 1),
});
uvs 배열은 텍스처의 일부가 메시에 들어가야 하는 위치를 설명하는 데 도움이 됩니다. 값 범위는 0에서 1까지입니다. 텍스처에 따라 이 값을 변경할 수 있습니다.
uvs = PackedVector2Array([
Vector2(0, 0),
Vector2(1, 0),
Vector2(0, 1),
Vector2(1, 1),
])
uvs.AddRange(new Vector2[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1),
});
normals 배열은 정점이 향하는 방향을 설명하는 데 사용되며 조명 계산에 사용됩니다. 이 예에서는 기본적으로 Vector3.UP 방향을 사용합니다.
normals = PackedVector3Array([
Vector3.UP,
Vector3.UP,
Vector3.UP,
Vector3.UP,
])
normals.AddRange(new Vector3[]
{
Vector3.Up,
Vector3.Up,
Vector3.Up,
Vector3.Up,
});
indices 배열은 정점이 그려지는 순서를 정의합니다. Godot는 시계 방향 방향으로 렌더링합니다. 이는 우리가 그리려는 삼각형의 꼭지점을 시계 방향 순서로 지정해야 한다는 의미입니다.
예를 들어, 첫 번째 삼각형을 그리려면 정점 (0, 0, 0), (1, 0, 0), (0, 0, 1)``를 순서대로 그려야 합니다. 이는 ``verts 배열에 vert[0], vert[2], vert[1], 즉 인덱스 0, 2, 1을 그리는 것과 같습니다. 이러한 인덱스 값은 indices 배열이 정의하는 것입니다.
인덱스 |
|
|
|
|---|---|---|---|
0 |
(0, 0, 0) |
(0, 0) |
벡터 |
1 |
(0, 0, 1) |
(1, 0) |
벡터 |
2 |
(1, 0, 0) |
(0, 1) |
벡터 |
3 |
(1, 0, 1) |
(1, 1) |
벡터 |
indices = PackedInt32Array([
0, 2, 1, # Draw the first triangle.
2, 3, 1, # Draw the second triangle.
])
indices.AddRange(new int[]
{
0, 2, 1, // Draw the first triangle.
2, 3, 1, // Draw the second triangle.
});
종합하면 직사각형 생성 코드는 다음과 같습니다.
extends MeshInstance3D
func _ready():
# Insert setting up the PackedVector**Arrays here.
verts = PackedVector3Array([
Vector3(0, 0, 0),
Vector3(0, 0, 1),
Vector3(1, 0, 0),
Vector3(1, 0, 1),
])
uvs = PackedVector2Array([
Vector2(0, 0),
Vector2(1, 0),
Vector2(0, 1),
Vector2(1, 1),
])
normals = PackedVector3Array([
Vector3.UP,
Vector3.UP,
Vector3.UP,
Vector3.UP,
])
indices = PackedInt32Array([
0, 2, 1,
2, 3, 1,
])
# Insert committing to the ArrayMesh here.
using System.Collections.Generic;
public partial class MeshInstance3d : MeshInstance3D
{
public override void _Ready()
{
// Insert setting up the surface array and lists here.
verts.AddRange(new Vector3[]
{
new Vector3(0, 0, 0),
new Vector3(0, 0, 1),
new Vector3(1, 0, 0),
new Vector3(1, 0, 1),
});
uvs.AddRange(new Vector2[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1),
});
normals.AddRange(new Vector3[]
{
Vector3.Up,
Vector3.Up,
Vector3.Up,
Vector3.Up,
});
indices.AddRange(new int[]
{
0, 2, 1,
2, 3, 1,
});
// Insert committing to the ArrayMesh here.
}
}
더 복잡한 예를 보려면 아래의 구 생성 섹션을 참조하세요.
스프라이트 만들기
다음은 구를 생성하기 위한 샘플 코드입니다. 코드는 GDScript로 제공되지만 코드를 생성하는 접근 방식에 있어 Godot의 특별한 내용은 없습니다. 이 구현은 특별히 ArrayMesh와 관련이 없으며 구를 생성하는 일반적인 접근 방식일 뿐입니다. 이해하는 데 어려움이 있거나 일반적인 절차 형상에 대해 자세히 알아보고 싶다면 온라인에서 찾을 수 있는 튜토리얼을 사용할 수 있습니다.
extends MeshInstance3D
var rings = 50
var radial_segments = 50
var radius = 1
func _ready():
# Insert setting up the PackedVector**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 + 1):
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 * radius, 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)
prevrow = thisrow
thisrow = point
# Insert committing to the ArrayMesh here.
public partial class MyMeshInstance3D : MeshInstance3D
{
private int _rings = 50;
private int _radialSegments = 50;
private float _radius = 1;
public override void _Ready()
{
// Insert setting up the surface array and lists here.
// Vertex indices.
var thisRow = 0;
var prevRow = 0;
var point = 0;
// Loop over rings.
for (var i = 0; i < _rings + 1; i++)
{
var v = ((float)i) / _rings;
var w = Mathf.Sin(Mathf.Pi * v);
var y = Mathf.Cos(Mathf.Pi * v);
// Loop over segments in ring.
for (var j = 0; j < _radialSegments + 1; j++)
{
var u = ((float)j) / _radialSegments;
var x = Mathf.Sin(u * Mathf.Pi * 2);
var z = Mathf.Cos(u * Mathf.Pi * 2);
var vert = new Vector3(x * _radius * w, y * _radius, z * _radius * w);
verts.Add(vert);
normals.Add(vert.Normalized());
uvs.Add(new Vector2(u, v));
point += 1;
// Create triangles in ring using indices.
if (i > 0 && j > 0)
{
indices.Add(prevRow + j - 1);
indices.Add(prevRow + j);
indices.Add(thisRow + j - 1);
indices.Add(prevRow + j);
indices.Add(thisRow + j);
indices.Add(thisRow + j - 1);
}
}
prevRow = thisRow;
thisRow = point;
}
// Insert committing to the ArrayMesh here.
}
}
저장하기
마지막으로 ResourceSaver 클래스를 사용하여 ArrayMesh를 저장할 수 있습니다. 이는 메시를 생성한 다음 나중에 다시 생성할 필요 없이 사용하려는 경우에 유용합니다.
# Saves mesh to a .tres file with compression enabled.
ResourceSaver.save(mesh, "res://sphere.tres", ResourceSaver.FLAG_COMPRESS)
// Saves mesh to a .tres file with compression enabled.
ResourceSaver.Save(Mesh, "res://sphere.tres", ResourceSaver.SaverFlags.Compress);