Skip to content

Commit ac93bdc

Browse files
committed
Update MeshDataTool tutorial
Adds C# code examples, links to the class reference and minor changes to the GDScript examples
1 parent 685d2ee commit ac93bdc

File tree

1 file changed

+99
-15
lines changed

1 file changed

+99
-15
lines changed

tutorials/3d/procedural_geometry/meshdatatool.rst

Lines changed: 99 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ Using the MeshDataTool
66
The :ref:`MeshDataTool <class_meshdatatool>` is not used to generate geometry. But it is helpful for dynamically altering geometry, for example
77
if you want to write a script to tessellate, simplify, or deform meshes.
88

9-
The MeshDataTool is not as fast as altering arrays directly using ArrayMesh. However, it provides more information
9+
The MeshDataTool is not as fast as altering arrays directly using :ref:`ArrayMesh <class_arraymesh>`. However, it provides more information
1010
and tools to work with meshes than the ArrayMesh does. When the MeshDataTool
1111
is used, it calculates mesh data that is not available in ArrayMeshes such as faces and edges, which are necessary
1212
for certain mesh algorithms. If you do not need this extra information then it may be better to use an ArrayMesh.
1313

1414
.. note:: MeshDataTool can only be used on Meshes that use the PrimitiveType ``Mesh.PRIMITIVE_TRIANGLES``.
1515

16-
We initialize the MeshDataTool from an ArrayMesh by calling ``create_from_surface()``. If there is already data initialized in the MeshDataTool,
17-
calling ``create_from_surface()`` will clear it for you. Alternatively, you can call ``clear()`` yourself before re-using the MeshDataTool.
16+
We initialize the MeshDataTool from an ArrayMesh by calling :ref:`create_from_surface() <class_meshdatatool_method_create_from_surface>`. If there is already data initialized in the MeshDataTool,
17+
calling ``create_from_surface()`` will clear it for you. Alternatively, you can call :ref:`clear() <class_meshdatatool_method_clear>` yourself before re-using the MeshDataTool.
1818

1919
In the examples below, assume an ArrayMesh called ``mesh`` has already been created. See :ref:`ArrayMesh tutorial <doc_arraymesh>` for an example of mesh generation.
2020

@@ -24,6 +24,11 @@ In the examples below, assume an ArrayMesh called ``mesh`` has already been crea
2424
var mdt = MeshDataTool.new()
2525
mdt.create_from_surface(mesh, 0)
2626

27+
.. code-tab:: csharp C#
28+
29+
var mdt = new MeshDataTool();
30+
mdt.CreateFromSurface(mesh, 0);
31+
2732
``create_from_surface()`` uses the vertex arrays from the ArrayMesh to calculate two additional arrays,
2833
one for edges and one for faces, for a total of three arrays.
2934

@@ -41,22 +46,38 @@ To access information from these arrays you use a function of the form ``get_***
4146
.. tabs::
4247
.. code-tab:: gdscript GDScript
4348

44-
mdt.get_vertex_count() # Returns number of vertices in vertex array.
45-
mdt.get_vertex_faces(0) # Returns array of faces that contain vertex[0].
46-
mdt.get_face_normal(1) # Calculates and returns face normal of the second face.
49+
mdt.get_vertex_count() # Returns the number of vertices in the vertex array.
50+
mdt.get_vertex_faces(0) # Returns an array of faces that contain vertex[0].
51+
mdt.get_face_normal(1) # Calculates and returns the face normal of the second face.
4752
mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.
4853

54+
.. code-tab:: csharp C#
55+
56+
mdt.GetVertexCount(); // Returns the number of vertices in the vertex array.
57+
mdt.GetVertexFaces(0); // Returns an array of faces that contain vertex[0].
58+
mdt.GetFaceNormal(1); // Calculates and returns the face normal of the second face.
59+
mdt.GetEdgeVertex(10, 1); // Returns the second vertex comprising the edge at index 10.
60+
4961
What you choose to do with these functions is up to you. A common use case is to iterate over all vertices
5062
and transform them in some way:
5163

5264
.. tabs::
5365
.. code-tab:: gdscript GDScript
5466

55-
for i in range(get_vertex_count):
67+
for i in range(mdt.get_vertex_count()):
5668
var vert = mdt.get_vertex(i)
57-
vert *= 2.0 # Scales the vertex by doubling size.
69+
vert *= 2.0 # Scales the vertex by doubling its size.
5870
mdt.set_vertex(i, vert)
5971
72+
.. code-tab:: csharp C#
73+
74+
for (var i = 0; i < mdt.GetVertexCount(); i++)
75+
{
76+
Vector3 vert = mdt.GetVertex(i);
77+
vert *= 2.0f; // Scales the vertex by doubling its size.
78+
mdt.SetVertex(i, vert);
79+
}
80+
6081
These modifications are not done in place on the ArrayMesh. If you are dynamically updating an existing ArrayMesh,
6182
first delete the existing surface before adding a new one using :ref:`commit_to_surface() <class_meshdatatool_method_commit_to_surface>`:
6283

@@ -66,6 +87,11 @@ first delete the existing surface before adding a new one using :ref:`commit_to_
6687
mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
6788
mdt.commit_to_surface(mesh)
6889

90+
.. code-tab:: csharp C#
91+
92+
mesh.ClearSurfaces(); // Deletes all of the mesh's surfaces.
93+
mdt.CommitToSurface(mesh);
94+
6995
Below is a complete example that turns a spherical mesh called ``mesh`` into a randomly deformed blob complete with updated normals and vertex colors.
7096
See :ref:`ArrayMesh tutorial <doc_arraymesh>` for how to generate the base mesh.
7197

@@ -84,34 +110,92 @@ See :ref:`ArrayMesh tutorial <doc_arraymesh>` for how to generate the base mesh.
84110

85111
for i in range(mdt.get_vertex_count()):
86112
var vertex = mdt.get_vertex(i).normalized()
87-
# Push out vertex by noise.
113+
# Scale the vertices using noise.
88114
vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
89115
mdt.set_vertex(i, vertex)
90116

91-
# Calculate vertex normals, face-by-face.
117+
# Calculate the vertex normals, face-by-face.
92118
for i in range(mdt.get_face_count()):
93119
# Get the index in the vertex array.
94120
var a = mdt.get_face_vertex(i, 0)
95121
var b = mdt.get_face_vertex(i, 1)
96122
var c = mdt.get_face_vertex(i, 2)
97-
# Get vertex position using vertex index.
123+
# Get the vertex position using the vertex index.
98124
var ap = mdt.get_vertex(a)
99125
var bp = mdt.get_vertex(b)
100126
var cp = mdt.get_vertex(c)
101-
# Calculate face normal.
127+
# Calculate the normal of the face.
102128
var n = (bp - cp).cross(ap - bp).normalized()
103-
# Add face normal to current vertex normal.
129+
# Add this face normal to the current vertex normals.
104130
# This will not result in perfect normals, but it will be close.
105131
mdt.set_vertex_normal(a, n + mdt.get_vertex_normal(a))
106132
mdt.set_vertex_normal(b, n + mdt.get_vertex_normal(b))
107133
mdt.set_vertex_normal(c, n + mdt.get_vertex_normal(c))
108134

109-
# Run through vertices one last time to normalize normals and
110-
# set color to normal.
135+
# Run through the vertices one last time to normalize their normals and
136+
# set the vertex colors to these new normals.
111137
for i in range(mdt.get_vertex_count()):
112138
var v = mdt.get_vertex_normal(i).normalized()
113139
mdt.set_vertex_normal(i, v)
114140
mdt.set_vertex_color(i, Color(v.x, v.y, v.z))
115141

116142
mesh.clear_surfaces()
117143
mdt.commit_to_surface(mesh)
144+
145+
.. code-tab:: csharp C#
146+
147+
using Godot;
148+
149+
public partial class MyMeshInstance3D : MeshInstance3D
150+
{
151+
MeshDataTool mdt = new MeshDataTool();
152+
FastNoiseLite fnl = new FastNoiseLite();
153+
154+
public override void _Ready()
155+
{
156+
fnl.Frequency = 0.7f;
157+
158+
ArrayMesh mesh = Mesh as ArrayMesh; // The mesh assigned the MeshInstance3D needs to be an ArrayMesh.
159+
mdt.CreateFromSurface(mesh, 0);
160+
161+
for (var i = 0; i < mdt.GetVertexCount(); i++)
162+
{
163+
Vector3 vertex = mdt.GetVertex(i).Normalized();
164+
// Scale the vertices using noise.
165+
vertex = vertex * (fnl.GetNoise3Dv(vertex) * 0.5f + 0.75f);
166+
mdt.SetVertex(i, vertex);
167+
}
168+
169+
// Calculate the vertex normals, face-by-face.
170+
for (var i = 0; i < mdt.GetFaceCount(); i++)
171+
{
172+
// Get the index in the vertex array.
173+
var a = mdt.GetFaceVertex(i, 0);
174+
var b = mdt.GetFaceVertex(i, 1);
175+
var c = mdt.GetFaceVertex(i, 2);
176+
// Get the vertex position using the vertex index.
177+
var ap = mdt.GetVertex(a);
178+
var bp = mdt.GetVertex(b);
179+
var cp = mdt.GetVertex(c);
180+
// Calculate the normal of the face.
181+
var n = (bp - cp).Cross(ap - bp).Normalized();
182+
// Add this face normal to the current vertex normals.
183+
// This will not result in perfect normals, but it will be close.
184+
mdt.SetVertexNormal(a, n + mdt.GetVertexNormal(a));
185+
mdt.SetVertexNormal(b, n + mdt.GetVertexNormal(b));
186+
mdt.SetVertexNormal(c, n + mdt.GetVertexNormal(c));
187+
}
188+
189+
// Run through the vertices one last time to normalize their normals and
190+
// set the vertex colors to these new normals.
191+
for (var i = 0; i < mdt.GetVertexCount(); i++)
192+
{
193+
var v = mdt.GetVertexNormal(i).Normalized();
194+
mdt.SetVertexNormal(i, v);
195+
mdt.SetVertexColor(i, new Color(v.X, v.Y, v.Z));
196+
}
197+
198+
mesh.ClearSurfaces();
199+
mdt.CommitToSurface(mesh);
200+
}
201+
}

0 commit comments

Comments
 (0)