ArrayMeshの使用

このチュートリアルでは、ArrayMesh の使用法の基本を紹介します

そのためには、関数 add_surface_from_arrays() を使用します。これは最大4つのパラメーターを取ります。最初の2つは必須ですが、残りの2つはオプションです。

1つ目は PrimitiveType です。これは、三角形、線、点などであるかどうかにかかわらず、頂点に基づいてプリミティブを配置する方法をGPUに指示するOpenGLの概念です。完全なリストは下の Mesh クラスのリファレンスページにあります。

2番目は、メッシュ情報を格納する実際の配列です。配列は、空のブラケット [] で構成される通常のGodot配列です。情報の種類ごとに Pool**Array (PoolVector3Array、PoolIntArrayなど)を格納します。

  • ARRAY_VERTEX = 0 | PoolVector3ArrayまたはPoolVector2Array
  • ARRAY_NORMAL = 1 | PoolVector3Array
  • ARRAY_TANGENT = 2 | 4つのfloatが一組になったPoolRealArray。最初の3つのfloatは接線を決定し、最後の従法線の方向は-1または1です。
  • ARRAY_COLOR = 3 | PoolColorArray
  • ARRAY_TEX_UV = 4 | PoolVector2ArrayまたはPoolVector3Array
  • ARRAY_TEX_UV2 = 5 | PoolVector2ArrayまたはPoolVector3Array
  • ARRAY_BONES = 6 | 4つのfloatが一組になったPoolRealArrayまたは4つのintが一組になったPoolIntArray
  • ARRAY_WEIGHTS = 7 | 4つのfloatが一組になったPoolRealArray
  • ARRAY_INDEX = 8 | PoolIntArray

頂点の配列は常に必要です。他のすべてはオプションであり、含まれている場合にのみ使用されます。

各配列は、インデックス配列を除き、頂点配列と同じ数の要素を持つ必要があります。接線のような配列の場合、要素は4つのfloatが一組です。したがって、配列のサイズは頂点配列のサイズの4倍になりますが、要素の数は同じになります

インデックス配列は一意です。

3番目のパラメーターは、使用するMeshのblendshapeの配列です。このチュートリアルではブレンドシェイプの使用については説明しませんが、配列からサーフェスを作成するときにそれらを指定することは可能です。

最後のパラメーターは、半分のビット数で格納する配列を指定する圧縮フラグです。値は、ArrayFormat の下の VisualServer のクラスリファレンスにあります。

通常の使用法では、最後の2つのパラメーターを空のままにしておくのが最善です。

ArrayMesh

ArrayMesh をMeshInstanceに追加します。通常、エディタにArrayMeshを追加することは有用ではありませんが、この場合、コードを作成せずにコードからArrayMeshにアクセスできます。

次に、MeshInstanceにスクリプトを追加します。

_ready() 下に、新しい配列を作成します。

var arr = []

これは、サーフェス情報を保持する配列になり、サーフェスに必要なすべてのデータ配列を保持します。 Godotは、サイズが Mesh.ARRAY_MAX であることを期待するため、それに応じてサイズを変更します。

var arr = []
arr.resize(Mesh.ARRAY_MAX)

次に、使用する各データ型の配列を作成します。

var verts = PoolVector3Array()
var uvs = PoolVector2Array()
var normals = PoolVector3Array()
var indices = PoolIntArray()

データ配列にジオメトリを入力したら、各配列を surface_array に追加し、メッシュにコミットすることでメッシュを作成できます。

arr[Mesh.ARRAY_VERTEX] = verts
arr[Mesh.ARRAY_TEX_UV] = uvs
arr[Mesh.ARRAY_NORMAL] = normals
arr[Mesh.ARRAY_INDEX] = indices

mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr) # No blendshapes or compression used.

注釈

この例では、Mesh.PRIMITIVE_TRIANGLES を使用しましたが、メッシュから利用可能な任意のプリミティブタイプを使用できます。

完全なコードをまとめると次のようになります:

extends MeshInstance

func _ready():
    var arr = []
    arr.resize(Mesh.ARRAY_MAX)

    # PoolVectorXXArrays for mesh construction.
    var verts = PoolVector3Array()
    var uvs = PoolVector2Array()
    var normals = PoolVector3Array()
    var indices = PoolIntArray()

    #######################################
    ## Insert code here to generate mesh ##
    #######################################

    # 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

    # Create mesh surface from mesh array.
    mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr) # No blendshapes or compression used.

中間にあるコードは、あなたが望むものなら何でも構いません。以下に、途中で実行できるコード例を示します。

ジオメトリの生成

球を生成するためのサンプルコードを次に示します。コードはGDScriptで表示されますが、コードを生成する方法についてGodot固有のものはありません。この実装は、ArrayMeshとは特に関係がなく、球体を生成するための一般的なアプローチです。理解に問題がある場合、またはプロシージャジオメトリ全般について詳しく知りたい場合は、オンラインで見つけたチュートリアルを使用できます。

extends MeshInstance

var rings = 50
var radial_segments = 50
var height = 1
var radius = 1

func _ready():

    # Set up the PoolVectorXArrays.

    # 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):
            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, 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)

        if i > 0:
            indices.append(prevrow + radial_segments - 1)
            indices.append(prevrow)
            indices.append(thisrow + radial_segments - 1)

            indices.append(prevrow)
            indices.append(prevrow + radial_segments)
            indices.append(thisrow + radial_segments - 1)

        prevrow = thisrow
        thisrow = point

  # Commit to the ArrayMesh.

上記のコードと組み合わせて、このコードは球体を生成します。

ArrayMeshを使用してジオメトリを生成する場合は、各配列の内容を理解する必要があります。その後、任意の言語/エンジンのチュートリアルに従ってGodotに変換できます。

保存

最後に、Godotは ResourceSaver クラスを使用してArrayMeshを保存する単一のメソッドを提供します。これは、メッシュを生成し、後で再生成することなく再利用する場合に便利です。

# Saves mesh to a .tres file with compression enabled.
ResourceSaver.save("res://sphere.tres", mesh, 32)