プログラミング

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

-プログラミング

執筆者:


  1. […] 細かいところで、「パンツかどうかをどう判断するの?」という問題があって、ぶっちゃけ3Dモデルに依存します。 パンツが独立したサブメッシュであることがキーポイントです。特定のサブメッシュのポリゴンを抜いてくるのは比較的カンタンなので。詳しくは以前の記事参照です。 これを満たすモデルは中々なくて、今回デモに出したのはセシル変身アプリで作成したVRMモデルです。 他にもアイドル部の八重沢なとりとかがこれを満たしていていい感じに風紀を正すことができます。 […]

comment

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

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

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

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

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

国土地理院の地図データをUnityで読みたい(願望)

なんかgoogleのAdSense通ったんで有益な情報載せないとなって。 国土地理院のオープンデータ 国土地理院が公開している(正確には国土地理院のデータを利用して国土交通省国土政策局国土情報課が公開 …

no image

[C言語]スペースを大量に入れるとバグが直るコードを書いてみた

↓こういうツイートがバズっていたので、実際に組んでみた。 修士の頃、授業の課題でC言語書いてる時にどうしても謎のエラーが出て困っていた。それを見たSE経験(金融系)がある社会人大学院生の同期の女性が「 …

no image

例え話をしないC言語のポインタの説明

もくじ1 まえおき2 Hello, Worldより簡単に2.1 サンプルコード2.2 変数の置き場所2.3 変数が入っているところを見てみる3 C言語とメモリ3.1 変数cの「まわり」を見てみる3.2 …