浏览代码

Improve clarity in procedural generation tutorials (#6004)

snailrhymer 3 年之前
父节点
当前提交
9e4a0351b0

+ 87 - 61
tutorials/3d/procedural_geometry/arraymesh.rst

@@ -3,53 +3,84 @@
 Using the ArrayMesh
 ===================
 
-This tutorial will present the basics of using an :ref:`ArrayMesh <class_arraymesh>`
+This tutorial will present the basics of using an :ref:`ArrayMesh <class_arraymesh>`.
 
 To do so, we will use the function :ref:`add_surface_from_arrays() <class_ArrayMesh_method_add_surface_from_arrays>`,
 which takes up to four parameters. The first two are required, while the second two are optional.
 
-The first is the ``PrimitiveType``, this is an OpenGL concept that instructs the GPU
-how to arrange the primitive based on the vertices given whether it is triangles,
-lines, points, etc. A complete list can be found under the :ref:`Mesh <class_mesh>`
-class reference page.
+The first parameter is the ``PrimitiveType``, an OpenGL concept that instructs the GPU
+how to arrange the primitive based on the vertices given, i.e. whether they represent triangles,
+lines, points, etc. See :ref:`Mesh.PrimitiveType <enum_Mesh_PrimitiveType>` for the options available.
 
-The second is the actual Array that stores the mesh information. The array is a normal Godot array that
-is constructed with empty brackets ``[]``. It stores a ``Pool**Array`` (e.g. PoolVector3Array,
-PoolIntArray, etc.) for each type of information.
+The second parameter, ``arrays``, is the actual Array that stores the mesh information. The array is a
+normal Godot array that is constructed with empty brackets ``[]``. It stores a ``Pool**Array``
+(e.g. PoolVector3Array, PoolIntArray, etc.) for each type of information that will be used to build the surface.
 
-- ``ARRAY_VERTEX`` = 0 | PoolVector3Array or PoolVector2Array
-- ``ARRAY_NORMAL`` = 1 | PoolVector3Array
-- ``ARRAY_TANGENT`` = 2 | PoolRealArray of groups of 4 floats. First 3 floats determine the tangent, and
-  the last the binormal direction as -1 or 1.
-- ``ARRAY_COLOR`` = 3 | PoolColorArray
-- ``ARRAY_TEX_UV`` = 4 | PoolVector2Array or PoolVector3Array
-- ``ARRAY_TEX_UV2`` = 5 | PoolVector2Array or PoolVector3Array
-- ``ARRAY_BONES`` = 6 | PoolRealArray of groups of 4 floats or PoolIntArray of groups of 4 ints. Each group lists indexes of 4 bones that affects a given vertex.
-- ``ARRAY_WEIGHTS`` = 7 | PoolRealArray of groups of 4 floats. Each float lists the amount of weight an determined bone on ``ARRAY_BONES`` has on a given vertex.
-- ``ARRAY_INDEX`` = 8 | PoolIntArray
+The possible elements of ``arrays`` are listed below, together with the position they must have within ``arrays``.
+See also :ref:`Mesh.ArrayType <enum_Mesh_ArrayType>`.
 
-The Array of vertices is always required. All the others are optional and will only be used if included.
 
-Each array needs to have the same number of elements as the vertex array except for the index array.
-For arrays like tangents, an element is a group of 4 floats. So the array size will be four times
-the size of the vertex array size, but they will have the same number of elements
+.. list-table::
+    :class: wrap-normal
+    :width: 100%
+    :widths: auto
+    :header-rows: 1
 
-The index array is unique.
+    * - Index
+      - Mesh.ArrayType Enum
+      - Array type
 
-The third parameter is an array of blendshapes for the Mesh to use. While this tutorial does not cover
-using blendshapes, it is possible to specify them when creating a surface from arrays.
+    * - 0
+      - ``ARRAY_VERTEX``
+      - :ref:`PoolVector3Array <class_PoolVector3Array>` or :ref:`PoolVector2Array <class_PoolVector2Array>`
 
-The last parameter is the compress flags which specifies which arrays to store with half as many bits. The
-values can be found in the classref for :ref:`VisualServer <class_visualserver>` under :ref:`ArrayFormat <enum_visualserver_arrayformat>`.
+    * - 1
+      - ``ARRAY_NORMAL``
+      - :ref:`PoolVector3Array <class_PoolVector3Array>`
 
-For normal usage you will find it is best to leave the last two parameters empty.
+    * - 2
+      - ``ARRAY_TANGENT``
+      - :ref:`PoolRealArray <class_PoolRealArray>` of groups of 4 floats. First 3 floats determine the tangent, and
+        the last the binormal direction as -1 or 1.
+
+    * - 3
+      - ``ARRAY_COLOR``
+      - :ref:`PoolColorArray <class_PoolColorArray>`
+
+    * - 4
+      - ``ARRAY_TEX_UV``
+      - :ref:`PoolVector2Array <class_PoolVector2Array>` or :ref:`PoolVector3Array <class_PoolVector3Array>`
+
+    * - 5
+      - ``ARRAY_TEX_UV2``
+      - :ref:`PoolVector2Array <class_PoolVector2Array>` or :ref:`PoolVector3Array <class_PoolVector3Array>`
+
+    * - 6
+      - ``ARRAY_BONES``
+      - :ref:`PoolRealArray <class_PoolRealArray>` of groups of 4 floats or :ref:`PoolIntArray <class_PoolIntArray>` of groups of 4 ints. Each group lists indexes of 4 bones that affects a given vertex.
+
+    * - 7
+      - ``ARRAY_WEIGHTS``
+      - :ref:`PoolRealArray <class_PoolRealArray>` of groups of 4 floats. Each float lists the amount of weight an determined bone on ``ARRAY_BONES`` has on a given vertex.
+
+    * - 8
+      - ``ARRAY_INDEX``
+      - :ref:`PoolIntArray <class_PoolIntArray>`
+
+The array of vertices (at index 0) is always required. The index array is optional and will only be used if included. We won't use it in this tutorial.
+
+All the other arrays carry information about the vertices. They are also optional and will only be used if included. Some of these arrays (e.g. ``ARRAY_COLOR``)
+use one entry per vertex to provide extra information about vertices. They must have the same size as the vertex array. Other arrays (e.g. ``ARRAY_TANGENT``) use
+four entries to describe a single vertex. These must be exactly four times larger than the vertex array.
+
+For normal usage, the last two parameters in :ref:`add_surface_from_arrays() <class_arraymesh_method_add_surface_from_arrays>` are typically left empty.
 
 ArrayMesh
 ---------
 
-Add an :ref:`ArrayMesh <class_arraymesh>` to a MeshInstance. Normally, adding an ArrayMesh in
-the editor is not useful, but in this case it allows as to access the ArrayMesh from code
-without creating one.
+In the editor, create a :ref:`MeshInstance <class_meshinstance>` and add an :ref:`ArrayMesh <class_arraymesh>` to it in the Inspector.
+Normally, adding an ArrayMesh in the editor is not useful, but in this case it allows us to access the ArrayMesh
+from code without creating one.
 
 Next, add a script to the MeshInstance.
 
@@ -58,17 +89,17 @@ Under ``_ready()``, create a new Array.
 .. tabs::
   .. code-tab:: gdscript GDScript
 
-    var arr = []
+    var surface_array = []
 
-This will be the array that we keep our surface information in, it will hold
+This will be the array that we keep our surface information in - it will hold
 all the arrays of data that the surface needs. Godot will expect it to be of
 size ``Mesh.ARRAY_MAX``, so resize it accordingly.
 
 .. tabs::
  .. code-tab:: gdscript GDScript
 
-    var arr = []
-    arr.resize(Mesh.ARRAY_MAX)
+    var surface_array = []
+    surface_array.resize(Mesh.ARRAY_MAX)
 
 Next create the arrays for each data type you will use.
 
@@ -86,17 +117,17 @@ by adding each array to ``surface_array`` and then committing to the mesh.
 .. tabs::
  .. code-tab:: gdscript GDScript
 
-    arr[Mesh.ARRAY_VERTEX] = verts
-    arr[Mesh.ARRAY_TEX_UV] = uvs
-    arr[Mesh.ARRAY_NORMAL] = normals
-    arr[Mesh.ARRAY_INDEX] = indices
+    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, arr) # No blendshapes or compression used.
+    mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) # No blendshapes or compression used.
 
 .. note:: In this example, we used ``Mesh.PRIMITIVE_TRIANGLES``, but you can use any primitive type
           available from mesh.
 
-Put together the full code looks like:
+Put together, the full code looks like:
 
 .. tabs::
  .. code-tab:: gdscript GDScript
@@ -104,10 +135,10 @@ Put together the full code looks like:
     extends MeshInstance
 
     func _ready():
-        var arr = []
-        arr.resize(Mesh.ARRAY_MAX)
+        var surface_array= []
+        surface_array.resize(Mesh.ARRAY_MAX)
 
-        # PoolVectorXXArrays for mesh construction.
+        # PoolVector**Arrays for mesh construction.
         var verts = PoolVector3Array()
         var uvs = PoolVector2Array()
         var normals = PoolVector3Array()
@@ -118,17 +149,17 @@ Put together the full code looks like:
         #######################################
 
         # Assign arrays to mesh array.
-        arr[Mesh.ARRAY_VERTEX] = verts
-        arr[Mesh.ARRAY_TEX_UV] = uvs
-        arr[Mesh.ARRAY_NORMAL] = normals
-        arr[Mesh.ARRAY_INDEX] = indices
+        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, arr) # No blendshapes or compression used.
+        mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) # No blendshapes or compression used.
 
 
-The code that goes in the middle can be whatever you want. Below we will present some example code that
-could go in the middle.
+The code that goes in the middle can be whatever you want. Below we will present some example code
+for generating a sphere.
 
 Generating geometry
 -------------------
@@ -152,7 +183,7 @@ that you find online.
 
     func _ready():
 
-        # Set up the PoolVectorXArrays.
+        # Insert setting up the PoolVector**Arrays here.
 
         # Vertex indices.
         var thisrow = 0
@@ -198,21 +229,16 @@ that you find online.
             prevrow = thisrow
             thisrow = point
 
-      # Commit to the ArrayMesh.
-
-Combined with the code above, this code will generate a sphere.
-
-When it comes to generating geometry with the ArrayMesh you need to understand what goes
-in each array and then you can follow tutorials for any language/engine and convert it into Godot.
+      # Insert committing to the ArrayMesh here.
 
 Saving
 ------
 
-Finally, Godot provides a single method to save ArrayMeshes using the :ref:`ResourceSaver <class_resourcesaver>`
-class. This is useful when you want to generate a mesh and then use it later without having to re-generate.
+Finally, we can use the :ref:`ResourceSaver <class_resourcesaver>` class to save the ArrayMesh.
+This is useful when you want to generate a mesh and then use it later without having to re-generate it.
 
 .. tabs::
  .. code-tab:: gdscript GDScript
 
     # Saves mesh to a .tres file with compression enabled.
-    ResourceSaver.save("res://sphere.tres", mesh, 32)
+    ResourceSaver.save("res://sphere.tres", mesh, ResourceSaver.FLAG_COMPRESS)

+ 14 - 13
tutorials/3d/procedural_geometry/index.rst

@@ -36,11 +36,11 @@ to draw it in different parts of your scene with different materials or transfor
 rotation, position etc.).
 
 If you are going to draw the same object many times, it can be helpful to use a MultiMesh with
-a MultiMeshInstance. The MultiMeshInstance draws meshes thousands of times very
-cheaply. It takes advantage of hardware instancing in order to do so. The drawback with
-using a MultiMeshInstance is that you are limited to one material for all instances. It uses an
-instance array to store different colors and transformations for each instance, but all the
-instances use the same material.
+a MultiMeshInstance. MultiMeshInstances draw meshes thousands of times very
+cheaply by taking advantage of hardware instancing. The drawback with
+using a MultiMeshInstance is that each of your mesh's surfaces are limited to one material for
+all instances. It uses an instance array to store different colors and transformations for each
+instance, but all the instances of each surface use the same material.
 
 What a Mesh is
 --------------
@@ -54,7 +54,7 @@ Surfaces
 ^^^^^^^^
 
 Each surface has its own material. Alternatively, you can override the material for all surfaces
-in the Mesh when you use a MeshInstance using ``MeshInstance.override_material``.
+in the Mesh when you use a MeshInstance using the :ref:`material_override <class_GeometryInstance_property_material_override>` property.
 
 Surface array
 ^^^^^^^^^^^^^
@@ -62,6 +62,7 @@ Surface array
 The surface array is an array of length ``ArrayMesh.ARRAY_MAX``. Each position in the array is
 filled with a sub-array containing per-vertex information. For example, the array located at
 ``ArrayMesh.ARRAY_NORMAL`` is a :ref:`PoolVector3Array <class_PoolVector3Array>` of vertex normals.
+See :ref:`Mesh.ArrayType <enum_Mesh_ArrayType>` for more information.
 
 The surface array can be indexed or non-indexed. Creating a non-indexed array is as easy as not assigning
 an array at the index ``ArrayMesh.ARRAY_INDEX``. A non-indexed array stores unique vertex information for
@@ -80,7 +81,7 @@ be provided in the following tutorials.
 ArrayMesh
 ^^^^^^^^^
 
-The ArrayMesh resource extends Mesh to add a few different quality of life functions, and most
+The ArrayMesh resource extends Mesh to add a few different quality of life functions and, most
 importantly, the ability to construct a Mesh surface through scripting.
 
 For more information about the ArrayMesh, please see the :ref:`ArrayMesh tutorial <doc_arraymesh>`.
@@ -105,11 +106,11 @@ ImmediateGeometry
 
 ImmediateGeometry is a node that uses an immediate mode style interface (like SurfaceTool) to draw objects. The
 difference between ImmediateGeometry and the SurfaceTool is that ImmediateGeometry is a node itself that can be
-added to the scene tree and is drawn directly from the code. The SurfaceTool generates a Mesh that needs to be added
-a MeshInstance to be seen.
+added to the scene tree and is drawn directly from the code, while the SurfaceTool generates a Mesh that needs to be added
+to a MeshInstance to be seen.
 
-ImmediateGeometry is useful for prototyping because of the straightforward API, but it is slow because the geometry
-is rebuilt every frame. It is most useful for quickly adding simple geometry to debug visually (e.g. by drawing lines to
+ImmediateGeometry is useful for prototyping because of its straightforward API, but it is slow because the geometry
+is rebuilt every frame. It is most useful for adding simple geometry for visual debugging (e.g. by drawing lines to
 visualize physics raycasts etc.).
 
 For more information about ImmediateGeometry, please see the :ref:`ImmediateGeometry tutorial <doc_immediategeometry>`.
@@ -117,7 +118,7 @@ For more information about ImmediateGeometry, please see the :ref:`ImmediateGeom
 Which one should I use?
 -----------------------
 
-Which method you use depends on what you are trying to do and what kind of procedure you are comfortable with.
+Which approach you use depends on what you are trying to do and what kind of procedure you are comfortable with.
 
 Both SurfaceTool and ArrayMesh are excellent for generating static geometry (meshes) that don't change over time.
 
@@ -130,5 +131,5 @@ an ArrayMesh every frame.
 
 The MeshDataTool is not fast, but it gives you access to all kinds of properties of the mesh that you don't get with the others
 (edges, faces, etc.). It is incredibly useful when you need that sort of data to transform the mesh, but it is not a good idea
-to use it if that information is not needed. The MeshDataTool is best used if you are going to be using an algorithm that requires
+to use it if that extra information is not needed. The MeshDataTool is best used if you are going to be using an algorithm that requires
 access to the face or edge array.

+ 11 - 12
tutorials/3d/procedural_geometry/meshdatatool.rst

@@ -13,21 +13,19 @@ for certain mesh algorithms. If you do not need this extra information then it m
 
 .. note:: MeshDataTool can only be used on Meshes that use the PrimitiveType ``Mesh.PRIMITIVE_TRIANGLES``.
 
-As an example, let's walk through the process of deforming the mesh generated in the :ref:`ArrayMesh tutorial <doc_arraymesh>`.
+We initialize the MeshDataTool from an ArrayMesh by calling ``create_from_surface()``. If there is already data initialized in the MeshDataTool,
+calling ``create_from_surface()`` will clear it for you. Alternatively, you can call ``clear()`` yourself before re-using the MeshDataTool.
 
-Assume the mesh is stored in an ArrayMesh named ``mesh``. We then initialize the MeshDataTool from
-``mesh`` by calling ``create_from_surface()``. If there is already data initialized in the MeshDataTool
-calling ``create_from_surface()`` will clear it for you. Alternatively, you can call ``clear()`` yourself
-before re-using the MeshDataTool
+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.
 
 .. tabs::
  .. code-tab:: gdscript GDScript
 
     var mdt = MeshDataTool.new()
-    mdt.create_from_surface(mesh)
+    mdt.create_from_surface(mesh, 0)
 
 ``create_from_surface()`` uses the vertex arrays from the ArrayMesh to calculate two additional arrays,
-one for edges and one for faces.
+one for edges and one for faces, for a total of three arrays.
 
 An edge is a connection between any two vertices. Each edge in the edge array contains a reference to
 the two vertices it is composed of, and up to two faces that it is contained within.
@@ -35,7 +33,7 @@ the two vertices it is composed of, and up to two faces that it is contained wit
 A face is a triangle made up of three vertices and three corresponding edges. Each face in the face array contains
 a reference to the three vertices and three edges it is composed of.
 
-The vertex array contains edges, faces, normals, color, tangent, uv, uv2, bones, and weight information connected
+The vertex array contains edge, face, normal, color, tangent, uv, uv2, bone, and weight information connected
 with each vertex.
 
 To access information from these arrays you use a function of the form ``get_****()``:
@@ -45,7 +43,7 @@ To access information from these arrays you use a function of the form ``get_***
 
     mdt.get_vertex_count() # Returns number of vertices in vertex array.
     mdt.get_vertex_faces(0) # Returns array of faces that contain vertex[0].
-    mdt.get_face_normal(1) # Calculates and returns face normal.
+    mdt.get_face_normal(1) # Calculates and returns face normal of the second face.
     mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.
 
 What you choose to do with these functions is up to you. A common use case is to iterate over all vertices
@@ -59,8 +57,8 @@ and transform them in some way:
         vert *= 2.0 # Scales the vertex by doubling size.
         mdt.set_vertex(i, vert)
 
-Finally, ``commit_to_surface()`` adds a new surface to the ArrayMesh. So if you are dynamically
-updating an existing ArrayMesh, first delete the existing surface before adding a new one.
+These modifications are not done in place on the ArrayMesh. If you are dynamically updating an existing ArrayMesh,
+first delete the existing surface before adding a new one using :ref:`commit_to_surface() <class_meshdatatool_method_commit_to_surface>`:
 
 .. tabs::
  .. code-tab:: gdscript GDScript
@@ -68,7 +66,8 @@ updating an existing ArrayMesh, first delete the existing surface before adding
     mesh.surface_remove(0) # Deletes the first surface of the mesh.
     mdt.commit_to_surface(mesh)
 
-Below is a complete example that creates a pulsing blob complete with new normals and vertex colors.
+Below is a complete example that turns a spherical mesh called ``mesh`` into a randomly deformed blob complete with updated normals and vertex colors.
+See :ref:`ArrayMesh tutorial <doc_arraymesh>` for how to generate the base mesh.
 
 .. tabs::
  .. code-tab:: gdscript GDScript