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...
MeshDataTool 사용하기
:ref:`MeshDataTool <class_meshdatatool>`은 형상을 생성하는 데 사용되지 않습니다. 그러나 예를 들어 메시를 테셀레이션, 단순화 또는 변형하기 위해 스크립트를 작성하려는 경우 지오메트리를 동적으로 변경하는 데 도움이 됩니다.
MeshDataTool은 :ref:`ArrayMesh <class_arraymesh>`을 사용하여 배열을 직접 변경하는 것만큼 빠르지 않습니다. 그러나 ArrayMesh보다 메쉬 작업에 더 많은 정보와 도구를 제공합니다. MeshDataTool을 사용하면 특정 메시 알고리즘에 필요한 면, 모서리 등 ArrayMesh에서 사용할 수 없는 메시 데이터를 계산합니다. 이 추가 정보가 필요하지 않으면 ArrayMesh를 사용하는 것이 더 나을 수 있습니다.
참고
MeshDataTool은 PrimitiveType ``Mesh.PRIMITIVE_TRIANGLES``를 사용하는 메시에서만 사용할 수 있습니다.
:ref:`create_from_surface() <class_meshdatatool_method_create_from_surface>`를 호출하여 ArrayMesh에서 MeshDataTool을 초기화합니다. MeshDataTool에 이미 초기화된 데이터가 있는 경우 ``create_from_surface()``를 호출하면 해당 데이터가 지워집니다. 또는 MeshDataTool을 재사용하기 전에 :ref:`clear() <class_meshdatatool_method_clear>`을 직접 호출할 수 있습니다.
아래 예에서는 ``mesh``라는 ArrayMesh가 이미 생성되었다고 가정합니다. 메시 생성의 예는 :ref:`ArrayMesh 튜토리얼 <doc_arraymesh>`을 참조하세요.
var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh, 0)
var mdt = new MeshDataTool();
mdt.CreateFromSurface(mesh, 0);
``create_from_surface()``는 ArrayMesh의 정점 배열을 사용하여 두 개의 추가 배열(가장자리용으로 하나, 면용으로 하나)을 계산하여 총 3개의 배열을 만듭니다.
모서리는 두 정점 사이의 연결입니다. 가장자리 배열의 각 가장자리에는 해당 가장자리를 구성하는 두 개의 꼭지점과 그 안에 포함된 최대 두 개의 면에 대한 참조가 포함되어 있습니다.
면은 3개의 꼭지점과 3개의 해당 모서리로 구성된 삼각형입니다. 면 배열의 각 면에는 해당 면을 구성하는 세 개의 정점과 세 개의 가장자리에 대한 참조가 포함되어 있습니다.
정점 배열에는 각 정점과 연결된 가장자리, 면, 법선, 색상, 접선, uv, uv2, 뼈 및 가중치 정보가 포함됩니다.
이러한 배열의 정보에 액세스하려면 get_****() 형식의 함수를 사용합니다.
mdt.get_vertex_count() # Returns the number of vertices in the vertex array.
mdt.get_vertex_faces(0) # Returns an array of faces that contain vertex[0].
mdt.get_face_normal(1) # Calculates and returns the face normal of the second face.
mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.
mdt.GetVertexCount(); // Returns the number of vertices in the vertex array.
mdt.GetVertexFaces(0); // Returns an array of faces that contain vertex[0].
mdt.GetFaceNormal(1); // Calculates and returns the face normal of the second face.
mdt.GetEdgeVertex(10, 1); // Returns the second vertex comprising the edge at index 10.
이러한 기능을 사용하여 수행할 작업은 귀하에게 달려 있습니다. 일반적인 사용 사례는 모든 정점을 반복하고 어떤 방식으로든 변환하는 것입니다.
for i in range(mdt.get_vertex_count()):
var vert = mdt.get_vertex(i)
vert *= 2.0 # Scales the vertex by doubling its size.
mdt.set_vertex(i, vert)
for (var i = 0; i < mdt.GetVertexCount(); i++)
{
Vector3 vert = mdt.GetVertex(i);
vert *= 2.0f; // Scales the vertex by doubling its size.
mdt.SetVertex(i, vert);
}
이러한 수정은 ArrayMesh에서는 수행되지 않습니다. 기존 ArrayMesh를 동적으로 업데이트하는 경우 :ref:`commit_to_surface() <class_meshdatatool_method_commit_to_surface>`를 사용하여 새 표면을 추가하기 전에 먼저 기존 표면을 삭제하십시오.
mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
mdt.commit_to_surface(mesh)
mesh.ClearSurfaces(); // Deletes all of the mesh's surfaces.
mdt.CommitToSurface(mesh);
다음은 ``mesh``라는 구형 메시를 업데이트된 법선과 정점 색상을 갖춘 무작위로 변형된 얼룩으로 바꾸는 완전한 예입니다. 기본 메시를 생성하는 방법은 :ref:`ArrayMesh 튜토리얼 <doc_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()
# Scale the vertices using noise.
vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
mdt.set_vertex(i, vertex)
# Calculate the 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 the vertex position using the vertex index.
var ap = mdt.get_vertex(a)
var bp = mdt.get_vertex(b)
var cp = mdt.get_vertex(c)
# Calculate the normal of the face.
var n = (bp - cp).cross(ap - bp).normalized()
# Add this face normal to the current vertex normals.
# 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 the vertices one last time to normalize their normals and
# set the vertex colors to these new normals.
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)
using Godot;
public partial class MyMeshInstance3D : MeshInstance3D
{
MeshDataTool mdt = new MeshDataTool();
FastNoiseLite fnl = new FastNoiseLite();
public override void _Ready()
{
fnl.Frequency = 0.7f;
ArrayMesh mesh = Mesh as ArrayMesh; // The mesh assigned the MeshInstance3D needs to be an ArrayMesh.
mdt.CreateFromSurface(mesh, 0);
for (var i = 0; i < mdt.GetVertexCount(); i++)
{
Vector3 vertex = mdt.GetVertex(i).Normalized();
// Scale the vertices using noise.
vertex = vertex * (fnl.GetNoise3Dv(vertex) * 0.5f + 0.75f);
mdt.SetVertex(i, vertex);
}
// Calculate the vertex normals, face-by-face.
for (var i = 0; i < mdt.GetFaceCount(); i++)
{
// Get the index in the vertex array.
var a = mdt.GetFaceVertex(i, 0);
var b = mdt.GetFaceVertex(i, 1);
var c = mdt.GetFaceVertex(i, 2);
// Get the vertex position using the vertex index.
var ap = mdt.GetVertex(a);
var bp = mdt.GetVertex(b);
var cp = mdt.GetVertex(c);
// Calculate the normal of the face.
var n = (bp - cp).Cross(ap - bp).Normalized();
// Add this face normal to the current vertex normals.
// This will not result in perfect normals, but it will be close.
mdt.SetVertexNormal(a, n + mdt.GetVertexNormal(a));
mdt.SetVertexNormal(b, n + mdt.GetVertexNormal(b));
mdt.SetVertexNormal(c, n + mdt.GetVertexNormal(c));
}
// Run through the vertices one last time to normalize their normals and
// set the vertex colors to these new normals.
for (var i = 0; i < mdt.GetVertexCount(); i++)
{
var v = mdt.GetVertexNormal(i).Normalized();
mdt.SetVertexNormal(i, v);
mdt.SetVertexColor(i, new Color(v.X, v.Y, v.Z));
}
mesh.ClearSurfaces();
mdt.CommitToSurface(mesh);
}
}