本日は Unity の調査枠です。
UnityEngine の Mesh クラスのドキュメントを理解のため、少しずつ読み進めていきます。
前回記事の続きです。
bluebirdofoz.hatenablog.com
Advanced Mesh APIクラスのドキュメント
今回は Mesh クラスで利用する Advanced Mesh API の以下の関数ドキュメントを読み進めていきます。
docs.unity3d.com
SetSubMesh
public void SetSubMesh (int index, Rendering.SubMeshDescriptor desc, Rendering.MeshUpdateFlags flags);
引数 | 説明 |
---|---|
index | サブメッシュインデックス(詳細は subMeshCount を参照) |
desc | サブメッシュデータ |
flags | 関数の動作を制御するフラグ(詳細は MeshUpdateFlags を参照) |
メッシュのサブメッシュに関する情報を設定します。
SubMeshDescriptor、および SetIndexBufferData は最大のパフォーマンスを目指す上級ユーザー向けに設計されています。
主にインデックスバッファ、頂点バッファ、メッシュサブセットデータの基本的なメッシュデータ構造で動作します。
この方法を使用すると、Unityはデータ検証をほとんど実行しないため、データが有効であることを確認する必要があります。
特に、以下の確認する必要があります。
・SubMesh インデックスの範囲外のデータが設定されていない事。
・トポロジが正しい値に設定されていること
Simple Mesh API と Advanced Mesh API の違いについては Mesh ページを参照してください。
・UnityEngineのMeshクラスを読み解く
https://bluebirdofoz.hatenablog.com/entry/2020/08/02/223528
SubMeshDescriptor のバウンドボックス、SubMeshDescriptor の firstVertex および vertexCount の値は SetSubMesh によって自動的に計算されます。
ただし MeshUpdateFlags.DontRecalculateBounds フラグが渡された場合は計算しません。
var mesh = new Mesh(); // setup vertex buffer data // 頂点バッファデータをセットアップする mesh.vertices = ...; // set index buffer // インデックスバッファを設定する mesh.SetIndexBufferParams(...); mesh.SetIndexBufferData(...); // setup information about mesh subsets // メッシュのサブセットに関する情報を設定する mesh.subMeshCount = ...; mesh.SetSubMesh(index, ...);
各サブメッシュに設定するデータの詳細については、SubMeshDescriptor を参照してください。
サンプルスクリプト例
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using Unity.Collections; public class AdvancedExample : MonoBehaviour { // FP32の座標を持つ頂点の定義 // 場合によっては StructLayout 属性が必要です // データレイアウトを正確に一致させるために使用します // https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.structlayoutattribute // https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.layoutkind [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] struct ExampleVertex { public Vector3 pos; } void Start() { Mesh mesh = new Mesh(); // specify vertex count and layout // 頂点の数とレイアウトを指定します var layout = new[] { new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3), }; int vertexCount = 4; mesh.SetVertexBufferParams(vertexCount, layout); // set vertex data // 頂点データを設定します NativeArray<ExampleVertex> verts = new NativeArray<ExampleVertex>(vertexCount, Allocator.Temp); // ... fill in vertex array data here... // ...ここで頂点配列データを入力... ExampleVertex vert0 = new ExampleVertex(); vert0.pos = new Vector3(0.0f, 1.0f, 0.0f); verts[0] = vert0; ExampleVertex vert1 = new ExampleVertex(); vert1.pos = new Vector3(1.0f, -1.0f, -1.0f); verts[1] = vert1; ExampleVertex vert2 = new ExampleVertex(); vert2.pos = new Vector3(-1.0f, -1.0f, -1.0f); verts[2] = vert2; ExampleVertex vert3 = new ExampleVertex(); vert3.pos = new Vector3(0.0f, -1.0f, 1.0f); verts[3] = vert3; // 頂点配列データをバッファに設定 mesh.SetVertexBufferData(verts, 0, 0, vertexCount); // インデックスバッファのサイズを設定 int indexCount = 12; mesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32); // ...ここでインデックスデータを入力... int[] indexlist = { 0, 1, 2, 0, 2, 3, 0, 3, 1, 3, 2, 1, }; // インデックス配列データをバッファに設定 mesh.SetIndexBufferData(indexlist, 0, 0, indexCount, MeshUpdateFlags.Default); // サブメッシュのサイズを設定 mesh.subMeshCount = 1; // メッシュのサブメッシュに関する情報を設定する SubMeshDescriptor desc = new SubMeshDescriptor(0, indexCount, MeshTopology.Triangles); mesh.SetSubMesh(0, desc, MeshUpdateFlags.Default); // 作成したメッシュをメッシュフィルターに設定する MeshFilter meshFilter = GetComponent<MeshFilter>(); meshFilter.mesh = mesh; } }
MeshUpdateFlags
メッシュデータの更新フラグです。
以下の Advanced Mesh API は関数の動作を制御するオプションとして本パラメータを取ります。
・SetVertexBufferData
・SetIndexBufferData
・SetSubMesh
本フラグを使用すると、メッシュのデータが更新されたときの動作を制御できます。
デフォルトではこれらのメソッドを使用するときに、指定されたデータのチェックと検証を実行します。
例えば、インデックス配列に範囲外の値があるかどうかをチェックします。
パフォーマンスを向上させる目的でフラグを使用すると、これらのチェックの一部または全てを省略できます。
これらのチェックを省略する場合は設定するデータが有効であることを確認する必要があります。
以下のように論理 OR 演算子を使用して、個々のフラグを組み合わせることができます。
MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontValidateIndices
変数
引数 | 説明 |
---|---|
Default | メッシュデータを変更するとき、デフォルトのチェックと検証を実行します |
DontValidateIndices | Mesh.SetIndexBufferData を使用してメッシュのデータを変更するとき、インデックス値をチェックしないことを示します |
DontResetBoneBounds | Mesh.SetVertexBufferData または Mesh.SetIndexBufferData を使用してメッシュデータを変更するとき、スキニングされたメッシュボーン境界をリセットしないことを示します |
DontNotifyMeshUsers | メッシュデータを変更するとき、可能性のあるメッシュ境界の変更についてレンダラーコンポーネントに通知しないことを示します |
DontRecalculateBounds | Mesh.SetSubMeshを使用してメッシュデータを設定するとき、境界を再計算しないことを示します |
SubMeshDescriptor
Mesh の単一のサブメッシュに関する情報が含まれています。
Simple Mesh API は Mesh.triangles、Mesh.vertices などの関数を使用します。
最大のパフォーマンスを必要とする Advanced Mesh API では、Mesh.SetSubMesh、Mesh.SetIndexBufferParams、Mesh.SetIndexBufferDataなどの関数を使用します。
Advanced Mesh API はインデックスバッファ、頂点バッファ、メッシュサブセットデータで機能する基本的なメッシュデータ構造へのアクセスを提供します。
1つのサブメッシュは、1つのマテリアルを使用しているメッシュの一部を表します。
多くのメッシュは1つのマテリアルのみを使用しますが、複数使用する場合もあります。
サブメッシュの情報は、次のもので構成されています。
indexStart
このサブセットの面インデックスデータが見つかるメッシュインデックスバッファ全体の開始点です。
Mesh.SetIndexBufferParams および Mesh.SetIndexBufferData を参照してください。
indexCount
このサブメッシュのインデックス数です。
例えば、三角形トポロジのメッシュではそれぞれの三角形の面に3つのインデックスが必要です。
topology
このサブメッシュのトポロジを示します。
最もよく利用されるのは三角形を示す MeshTopology.Triangles です。
baseVertex
最終的な頂点インデックスを計算するために、インデックスバッファの各値に追加されるオフセットです。
bounds
ローカル空間の頂点のバウンディングボックスです。
firstVertex and vertexCount
このサブメッシュのインデックスバッファによって参照される頂点の範囲です。
bounds、firstVertex、および vertexCount の値は Mesh.SetSubMesh によって自動的に計算されます。
ただし MeshUpdateFlags.DontRecalculateBounds フラグが渡された場合は計算しません。
変数
引数 | 説明 |
---|---|
baseVertex | 最終的な頂点インデックスを計算するため、インデックスバッファの各値に追加されるオフセット |
bounds | ローカル空間の頂点の境界ボックス |
firstVertex | サブメッシュのインデックスバッファーの最初の頂点 |
indexCount | サブメッシュの面データのインデックス数 |
indexStart | メッシュインデックスバッファ全体の開始点 |
topology | サブメッシュの面トポロジ |
vertexCount | サブメッシュのインデックスバッファーで使用される頂点の数 |