プログラミング

Unityでメッシュをさわるノウハウ

投稿日:2018年5月2日 更新日:

ヒマなので覚書。ウラを取っていない経験則なので話半分で読んでください。
あと、3Dの基本概念とUnity固有の話の区別が付いていないのでごめんなさい。

もくじ

Meshクラスの基本

Unityでポリゴンをガッツリいじろうと思うとMeshクラスを読む必要がある。
可動モデルの場合、SkinnedMeshRendererクラスのBakeMeshを使ってベイクしてやるとボーン変形後の情報を持ったメッシュが取れる。
可動させないならSkinnedMeshRenderer.sharedMeshで良いと思う。

だいたい以下のメンバーを読むことになる。

  • Mesh.vertices(頂点一覧)
  • Mesh.triangles(三角形を形成する頂点のインデクス)
  • Mesh.uv(UVマップ上の頂点の座標)

ポリゴンの読み方

Mesh.trianglesはヘンな構成で、配列の要素3個で三角形をつくる。例えば{0,1,2,1,2,3}という配列の場合、最初の3つ「0,1,2」が1つ目の三角形、次の3つ「1,2,3」が2つ目の三角形になる。数字は、Mesh.verticesの添字に使う。

なので簡単には、以下のようなコードで三角形の座標を取得できる。

for (int i = 0; i < mesh.triangles.Length; i += 3)
{
Vector3 A = mesh.vertices[mesh.triangles[i]];
Vector3 B = mesh.vertices[mesh.triangles[i + 1]];
Vector3 C = mesh.vertices[mesh.triangles[i + 2]];
/* 三角形ABCへの処理*/
}

しかしこのコードには実用上いくつか問題がある。

マテリアルを気にするならMesh.trianglesを使ってはいけない

Mesh.trianglesは、マテリアルの区別なく全ての三角形を返す。
したがって、これで取り出した情報はマテリアルと紐付けられない。
Meshクラスは、サブメッシュという区分けでマテリアルを区別している。
サブメッシュ単位の三角形を取得するmesh.GetTriangles関数を使って、マテリアルごとに三角形を処理すると良い。引数としてサブメッシュ番号を指定する。
サブメッシュの個数は、mesh.subMeshCountから取得できる。
マテリアル自身はRenderer.materials配列から取得できる。配列の添字はサブメッシュ番号と一致する。

Meshクラスの配列を直接読んではいけない

理由は知らないけど、verticesなどの配列は、書き込みはもちろん読み込みすら馬鹿みたいに重い。
for文の中で毎回参照なんてやっているととてもマトモな速度では動いてくれなくなる。
したがって一度ローカルにおいてしまって、そこから読み出すと良い。

以上をもとに、マテリアルごと、かつ常識的な速度で動作するように改造したコードは以下のとおり。

Vector3[] meshVertices = mesh.vertices;

for (int subMesh = 0; subMesh < mesh.subMeshCount; subMesh++) {
int[] submeshTriangles = mesh.GetTriangles(subMesh);
for (int i = 0; i < submeshTriangles.Length; i += 3)
{
Vector3 A = meshVertices[submeshTriangles[i]];
Vector3 B = meshVertices[submeshTriangles[i + 1]];
Vector3 C = meshVertices[submeshTriangles[i + 2]];
/* 三角形ABCへの処理*/
}
}

とにかくMeshクラスのメンバへのアクセスは異様に重たいので、配列を個々にアクセスするような真似は避けて作業しないといけない。
ほんだらまた。

-プログラミング

執筆者:

関連記事

GeoJSONで市町村境界をマージして都道府県境界にしたい(その2)

GeoJSONのPolygonをマージしたい第2回です。 前回、純粋な多角形の統合ではなくて、領域が被らない多角形の統合になるのでグラフ問題として解くことができるという説明をしました。 今回はどうやっ …

no image

M5StickC Plusの明るさ(M5.Axp.ScreenBreath)、0~100かもしれない

M5StickC Plusで画面の明るさを調整するM5.Axp.ScreenBreath()という関数があります。 日本語リファレンスでは指定値7~12ということになっています。 また、公式ドキュメン …

no image

[python]Windows環境でsubprocessするときは文字コードに気をつけて

pythonは内部の文字コードと実行環境の文字コードが色々絡み合っていて、いろんなところで悪さをする。 特にWindows環境だと、内部はUTF-8で動いているのに実行環境はShift-JIS(正確に …

no image

C言語のポインタに関する補足説明

前回、C言語のポインタに関する解説記事を書きまして、そこそこの反響を貰うとともにいくつかの指摘を受けました。 前回の記事では幾つか「ウソではないけど真実と違う」記述がありまして、その点を補足としていく …

SHOWROOMのガチイベをGoogleスプレッドシートでグラフにしよう

まえがき SHOWROOMのガチイベ、と言えば配信者が獲得ポイント数でランキングされ、最終的にファンの札束で殴り合って勝者を競う札束タワーバトルなわけです。 数日~数週間にわたって配信者同士でランキン …