建設とUnity

Unityを使って、建設業界向けのソフトを開発するノウハウを紹介します。

【Blender→Unity】STLのランタイム読込とZ-up・右手系からY-up・左手系への変換方法

3Dデータにはさまざまなものがありますが、今回はSTLデータをランタイムに読みこみ、 CADやBlender(Z-up・右手系)のデータをUnity(Y-up・左手系)で正しい位置に表示する方法を説明します。

ランタイムでSTLを読みこむ

ランタイムでSTLを読みこむ方法は以下のリンクで紹介されています。

UnityでSTLファイルの動的な読込み - Qiita

単純に読みこむだけの場合は、こちらの記事の通りに実装すればよいです。 以下では、実際にありがちな問題に対処する方法を説明します。

Z-up・右手系からY-up・左手系へ

Y-upかZ-upか

3Dデータは作成したソフトによって、Y-upなのかZ-upなのかが変わります。 Y-upやZ-upというのは垂直軸はY軸なのか、Z軸なのかという意味です。

この違いについては以下のブログの説明がとてもわかりやすいです。 (加えて右手、左手系やソフトごとの説明も詳しいのでぜひ読んでみてください)

3DCGツールやゲームエンジンやデザインツールがY-upの製品が多いのようで、衣装制作で使うMarvelous DesignerもY-upになります。 CADがなぜZ-upなのか?と言うと、元々製図は紙で行っていますから、平面が基準になっています。

■ 3DCGの座標 | @Kay-nea@のブログ

ソフトによっては出力する際に、Y-upにするかZ-upにするか選択することができますが、 引用した文章の通り、CADはZ-upのことが多いです。

左手系か右手系か

より詳しく言うと、CADはZ-upかつ右手系(フリーのモデリングソフトであるBlenderも同じです)のことが多く、 UnityはY-upかつ左手系です。

そのため、CADで作製したデータがZ-upで右手系の場合、 Y-upの左手系に変換する必要があります。

BlenderからUnityへ(Yが上・Zが前方の場合)

f:id:sayadoki:20211230000742p:plain

たとえば、上の画像のようなBlenderで作成したデータを 下の画像のようにUnityで読みこむことを目標とします。

f:id:sayadoki:20211230000806p:plain

今回は多くのCADと同じく、Z-up・右手系のBlenderを例に説明します。

Blenderの場合は、STLをExportするときに上方向と前方方向をどの軸にするか設定することができます。 そこで、上方向を「Yが上」に設定して、前方方向を「Zが前方」に設定しておくと楽です。

「Yが上」「Zが前方」の設定をした上でSTLを出力して、 Unityでランタイムに読みこんでみましょう(最初に紹介したリンクの方法でSTLは読みこめます)。

位置の修正

f:id:sayadoki:20211230001159p:plain

すると、X軸に対して反対の位置にモデルが読みこまれます。これはBlenderが右手系で、Unityが左手系のためです。

これを修正するために、頂点のX座標値にマイナスをかけましょう。

vertex[triangleIndex + 0] = new Vector3(- reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
vertex[triangleIndex + 1] = new Vector3(- reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
vertex[triangleIndex + 2] = new Vector3(- reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
メッシュの裏表の修正

f:id:sayadoki:20211230001327p:plain

頂点のX座標値にマイナスをかけたことで、メッシュの裏表が逆になってしまいます。 STLは以下のリンクのように3つの頂点からひとつのポリゴンを形成しますが、 頂点をたどって右ねじが回して、親指が立つ方向が表向きになるようになっています。

STLファイルフォーマット

たとえば以下のように、読みこむ際の頂点の順番を変えることで、表裏を正すことができます。 0, 1, 2の順番で読んでいたところを、0, 2, 1の順番に変えるだけです。

vertex[triangleIndex + 0] = new Vector3(- reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
vertex[triangleIndex + 2] = new Vector3(- reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
vertex[triangleIndex + 1] = new Vector3(- reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());

BlenderからUnityへ(Zが上・Yが前方の場合)

UnityがY-upであることに配慮して、出力してもらえれば先ほどの手順でOKですが、 「Zが上」「Yが前方」のデータを読みこまないといけない場合もあります。

その際は、たとえば以下のようにYとZの値を交換してあげた上で、 メッシュの裏表を反転させてあげると、正しく読みこめます。

var v0 = vertex[triangleIndex + 0];
var v1 = vertex[triangleIndex + 1];
var v2 = vertex[triangleIndex + 2];
vertex[triangleIndex + 0] = new Vector3(v0.x, v0.z, v0.y);
vertex[triangleIndex + 2] = new Vector3(v1.x, v1.z, v1.y);
vertex[triangleIndex + 1] = new Vector3(v2.x, v2.z, v2.y);

以上で、UnityでSTLをランタイムに読みこみ、Z-up・右手系からY-up・左手系へ変換する方法を説明しました。