| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 | .. _doc_arraymesh:Using the 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 five parameters. The first two are required, while the last three are optional.The first parameter is the ``PrimitiveType``, an OpenGL concept that instructs the GPUhow 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 parameter, ``arrays``, is the actual Array that stores the mesh information. The array is a normal Godot array thatis constructed with empty brackets ``[]``. It stores a ``Packed**Array`` (e.g. PackedVector3Array,PackedInt32Array, etc.) for each type of information that will be used to build the surface.Common elements of ``arrays`` are listed below, together with the position they must have within ``arrays``.See :ref:`Mesh.ArrayType <enum_Mesh_ArrayType>` for a full list... list-table::    :class: wrap-normal    :width: 100%    :widths: auto    :header-rows: 1    * - Index      - Mesh.ArrayType Enum      - Array type        * - 0      - ``ARRAY_VERTEX``      - :ref:`PackedVector3Array <class_PackedVector3Array>` or :ref:`PackedVector2Array <class_PackedVector2Array>`        * - 1      - ``ARRAY_NORMAL``      - :ref:`PackedVector3Array <class_PackedVector3Array>`        * - 2      - ``ARRAY_TANGENT``      - :ref:`PackedFloat32Array <class_PackedFloat32Array>` or :ref:`PackedFloat64Array <class_PackedFloat64Array>` of groups of 4 floats. The first 3 floats determine the tangent, and the last float the binormal         direction as -1 or 1.        * - 3      - ``ARRAY_COLOR``      - :ref:`PackedColorArray <class_PackedColorArray>`        * - 4      - ``ARRAY_TEX_UV``      - :ref:`PackedVector2Array <class_PackedVector2Array>` or :ref:`PackedVector3Array <class_PackedVector3Array>`        * - 5      - ``ARRAY_TEX_UV2``      - :ref:`PackedVector2Array <class_PackedVector2Array>` or :ref:`PackedVector3Array <class_PackedVector3Array>`        * - 10      - ``ARRAY_BONES``      - :ref:`PackedFloat32Array <class_PackedFloat32Array>` of groups of 4 floats or :ref:`PackedInt32Array <class_PackedInt32Array>` of groups of 4 ints. Each group lists indexes of 4 bones that affects a given vertex.        * - 11      - ``ARRAY_WEIGHTS``      - :ref:`PackedFloat32Array <class_PackedFloat32Array>` or :ref:`PackedFloat64Array <class_PackedFloat64Array>` of groups of 4 floats. Each float lists the amount of weight the corresponding bone in ``ARRAY_BONES`` has on a given vertex.        * - 12      - ``ARRAY_INDEX``      - :ref:`PackedInt32Array <class_PackedInt32Array>`In most cases when creating a mesh, we define it by its vertex positions. So usually, the array of vertices (at index 0) is required, while the index array (at index 12) is optional andwill only be used if included. It is also possible to create a mesh with only the index array and no vertex array, but that's beyond the scope of this tutorial.All the other arrays carry information about the vertices. They are 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``) usefour entries to describe a single vertex. These must be exactly four times larger than the vertex array.For normal usage, the last three parameters in :ref:`add_surface_from_arrays() <class_arraymesh_method_add_surface_from_arrays>` are typically left empty.Setting up the ArrayMesh------------------------In the editor, create a :ref:`MeshInstance3D <class_meshinstance3d>` 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 ArrayMeshfrom code without creating one.Next, add a script to the MeshInstance3D.Under ``_ready()``, create a new Array... tabs::  .. code-tab:: gdscript GDScript    var surface_array = []    .. code-tab:: csharp C#    Godot.Collections.Array surfaceArray = [];This will be the array that we keep our surface information in - it will holdall the arrays of data that the surface needs. Godot will expect it to be ofsize ``Mesh.ARRAY_MAX``, so resize it accordingly... tabs:: .. code-tab:: gdscript GDScript    var surface_array = []    surface_array.resize(Mesh.ARRAY_MAX)   .. code-tab:: csharp C#    Godot.Collections.Array surfaceArray = [];    surfaceArray.Resize((int)Mesh.ArrayType.Max);Next create the arrays for each data type you will use... tabs:: .. code-tab:: gdscript GDScript    var verts = PackedVector3Array()    var uvs = PackedVector2Array()    var normals = PackedVector3Array()    var indices = PackedInt32Array() .. code-tab:: csharp C#    List<Vector3> verts = [];    List<Vector2> uvs = [];    List<Vector3> normals = [];    List<int> indices = [];Once you have filled your data arrays with your geometry you can create a meshby adding each array to ``surface_array`` and then committing to the mesh... tabs:: .. code-tab:: gdscript GDScript    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) .. code-tab:: csharp C#    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);     }.. 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:.. tabs:: .. code-tab:: gdscript GDScript    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) .. code-tab:: csharp C#    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);            }        }    }The code that goes in the middle can be whatever you want. Below we will present someexample code for generating shapes, starting with a rectangle.Generating a rectangle----------------------Since we are using ``Mesh.PRIMITIVE_TRIANGLES`` to render, we will construct a rectanglewith triangles.A rectangle is formed by two triangles sharing four vertices. For our example, we will createa rectangle with its top left point at ``(0, 0, 0)`` with a width and length of one as shown below:.. image:: img/array_mesh_rectangle_as_triangles.webp  :scale: 33%  :alt: A rectangle made of two triangles sharing four vertices.To draw this rectangle, define the coordinates of each vertex in the ``verts`` array... tabs::  .. code-tab:: gdscript GDScript    verts = PackedVector3Array([            Vector3(0, 0, 0),            Vector3(0, 0, 1),            Vector3(1, 0, 0),            Vector3(1, 0, 1),        ])  .. code-tab:: csharp C#    verts.AddRange(new Vector3[]    {        new Vector3(0, 0, 0),        new Vector3(0, 0, 1),        new Vector3(1, 0, 0),        new Vector3(1, 0, 1),    });The ``uvs`` array helps describe where parts of a texture should go onto the mesh. The valuesrange from 0 to 1. Depending on your texture, you may want to change these values... tabs::  .. code-tab:: gdscript GDScript    uvs = PackedVector2Array([            Vector2(0, 0),            Vector2(1, 0),            Vector2(0, 1),            Vector2(1, 1),        ])  .. code-tab:: csharp C#    uvs.AddRange(new Vector2[]    {        new Vector2(0, 0),        new Vector2(1, 0),        new Vector2(0, 1),        new Vector2(1, 1),    });The ``normals`` array is used to describe the direction the vertices face and isused in lighting calculations. For this example, we will default to the ``Vector3.UP``direction... tabs::  .. code-tab:: gdscript GDScript    normals = PackedVector3Array([            Vector3.UP,            Vector3.UP,            Vector3.UP,            Vector3.UP,        ])  .. code-tab:: csharp C#    normals.AddRange(new Vector3[]    {        Vector3.Up,        Vector3.Up,        Vector3.Up,        Vector3.Up,    });The ``indices`` array defines the order vertices are drawn. Godotrenders in a *clockwise* direction, meaning that we must specify the verticesof a triangle we want to draw in clockwise order.For example, to draw the first triangle, we will want to draw the vertices ``(0, 0, 0)``,``(1, 0, 0)``, and ``(0, 0, 1)`` in that order. This is the same as drawing ``vert[0]``, ``vert[2]``, and``vert[1]``, i.e., indices 0, 2, and 1, in the ``verts`` array. These index values are what the``indices`` array defines... list-table::   :header-rows: 1   :widths: auto   * - Index     - ``verts[Index]``     - ``uvs[Index]``     - ``normals[Index]``   * - 0     - (0, 0, 0)     - (0, 0)     - Vector3.UP   * - 1     - (0, 0, 1)     - (1, 0)     - Vector3.UP   * - 2     - (1, 0, 0)     - (0, 1)     - Vector3.UP   * - 3     - (1, 0, 1)     - (1, 1)     - Vector3.UP.. tabs::  .. code-tab:: gdscript GDScript    indices = PackedInt32Array([            0, 2, 1, # Draw the first triangle.            2, 3, 1, # Draw the second triangle.        ])  .. code-tab:: csharp C#    indices.AddRange(new int[]    {        0, 2, 1, // Draw the first triangle.        2, 3, 1, // Draw the second triangle.    });Put together, the rectangle generation code looks like:.. tabs::  .. code-tab:: gdscript GDScript    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.  .. code-tab:: csharp C#    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.      }    }For a more complex example, see the sphere generation section below.Generating a sphere-------------------Here is sample code for generating a sphere. Although the code is presented inGDScript, there is nothing Godot specific about the approach to generating it.This implementation has nothing in particular to do with ArrayMeshes and is just ageneric approach to generating a sphere. If you are having trouble understanding itor want to learn more about procedural geometry in general, you can use any tutorialthat you find online... tabs:: .. code-tab:: gdscript GDScript    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. .. code-tab:: csharp C#    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.        }    }Saving------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(mesh, "res://sphere.tres", ResourceSaver.FLAG_COMPRESS) .. code-tab:: csharp C#    // Saves mesh to a .tres file with compression enabled.    ResourceSaver.Save(Mesh, "res://sphere.tres", ResourceSaver.SaverFlags.Compress);
 |