プログラミング

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

-プログラミング

執筆者:

関連記事

no image

SwitchBotの温湿度計、防水かどうかでBluetoothのデータの取り方違うぞ

SwitchBotは機器のAPIを公開していて、ユーザーの自作プログラムからBluetooth(BLE)越しにデータが取れたりします。 特に温湿度計のデータを取りたいというニーズは強くて、安価で安定し …

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

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

YouTube Data APIをGoogle Apps Script(GAS)から使おう

YouTubeってAPIから色々な情報を取ることができるんですよ。 APIの情報はリファレンスにまとまってるんですが、APIキーだのOAuth2.0だの、使い始めるまでがまぁまぁ面倒なんですね。 で、 …

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

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

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

前回の続きで、国土地理院の「国土数値情報」っていうオープンデータで遊んでいます。独立した記事なので前回のは読まなくても良いです。 やりたいこと 国土数値情報で提供されている「行政区域データ」は、市町村 …