1。概要
Unity3D 学習ノート 4 - メッシュの高度なインターフェイスの作成 の記事では、メッシュは高度な API を通じて作成され、サブメッシュの概念についても言及されています。メッシュは 3 次元オブジェクトのカプセル化の概念です。簡単な要件は、ある場所ではマテリアル A を使用し、ある場所ではマテリアル B を使用することです。このメッシュを分割したくないので、非常に簡単で、このメッシュ内の 2 つのサブメッシュを分割するだけです。
2. 詳細な議論
2.1. 実装
次のスクリプトを作成し、プロパティmaterial1とプロパティmaterial2に2つの異なるマテリアルをフックします。
using UnityEngine;
using UnityEngine.Rendering;
[ExecuteInEditMode]
public class Note5Main : MonoBehaviour
{
public Material material1;
public Material material2;
// Start is called before the first frame update
void Start()
{
Mesh mesh = CreateMesh();
MeshFilter mf = gameObject.GetComponent<MeshFilter>();
if (mf == null)
{
mf = gameObject.AddComponent<MeshFilter>();
}
mf.sharedMesh = mesh;
MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
if (meshRenderer == null)
{
meshRenderer = gameObject.AddComponent<MeshRenderer>();
}
Material[] materials = new Material[2];
materials[0] = material1;
materials[1] = material2;
meshRenderer.materials = materials;
}
Mesh CreateMesh()
{
Mesh mesh = new Mesh();
const int vertexCount = 8;
Vector3[] vertices = new Vector3[vertexCount]
{
new Vector3(-5, 0, 0),
new Vector3(-5, 5, 0),
new Vector3(5, 0, 0),
new Vector3(5, 5, 0),
new Vector3(-5, -5, 0),
new Vector3(-5, 0, 0),
new Vector3(5, -5, 0),
new Vector3(5, 0, 0),
};
Vector3[] normals = new Vector3[vertexCount]
{
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
};
Vector2[] uv = new Vector2[vertexCount]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0),
new Vector2(1, 1),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0),
new Vector2(1, 1),
};
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uv;
int[] triangles = new int[12] {
0, 1, 2, 1, 3, 2, 4, 5, 6, 5, 7, 6 };
MeshUpdateFlags flags = MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontResetBoneBounds
| MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds;
//MeshUpdateFlags flags = MeshUpdateFlags.Default;
int indexCount = triangles.Length;
mesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32);
mesh.SetIndexBufferData(triangles, 0, 0, indexCount, flags);
mesh.subMeshCount = 2;
SubMeshDescriptor subMeshDescriptor1 = new SubMeshDescriptor(0, 6);
mesh.SetSubMesh(0, subMeshDescriptor1, flags);
SubMeshDescriptor subMeshDescriptor2 = new SubMeshDescriptor(6, 6);
mesh.SetSubMesh(1, subMeshDescriptor2, flags);
return mesh;
}
// Update is called once per frame
void Update()
{
}
}
ここで私が得た効果は次のとおりです。
2.2. 分析
明らかに、ここでは 2 つの四角形を作成し、メッシュの下に配置しました。シンプルなインターフェイスを使用して頂点属性を作成し、高度なインターフェイスを使用して頂点インデックス属性情報を作成しました。重要なポイントは、SubMesh の説明です。
mesh.subMeshCount = 2;
SubMeshDescriptor subMeshDescriptor1 = new SubMeshDescriptor(0, 6);
mesh.SetSubMesh(0, subMeshDescriptor1, flags);
SubMeshDescriptor subMeshDescriptor2 = new SubMeshDescriptor(6, 6);
mesh.SetSubMesh(1, subMeshDescriptor2, flags);
SubMeshDescriptor クラスは、頂点インデックスからのサブメッシュのスペース、つまりメッシュの分割部分を定義します。さらに、ゲームオブジェクトにアタッチされているマテリアルの数も対応している必要があります。
MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
if (meshRenderer == null)
{
meshRenderer = gameObject.AddComponent<MeshRenderer>();
}
Material[] materials = new Material[2];
materials[0] = material1;
materials[1] = material2;
meshRenderer.materials = materials;
MeshRenderer には複数のマテリアルをアタッチできますが、マテリアルは SubMesh の数だけ存在し、1 対 1 対応する必要があります。数量が Unity エディターに対応していない場合、エラーが報告されます。
SubMesh を分割してメッシュを記述するのは通常、マテリアルが複数ある場合に使用されますが、同じマテリアルを使用する場合は SubMesh を分割しないほうがよいでしょう。Frame Debug を開くと、次のことが確認できます。
メッシュは 2 つのレンダリング命令に分割されて実現されます。その理由は、画像エンジンは通常ステート マシンであり、マテリアルはレンダリング コマンドに対応する必要があるためです。そのため、さまざまなマテリアルの数を減らすためにマテリアルを可能な限り再利用することがよくあります。