fc2ブログ
Unity3Dとの楽苦な日々
Unity3Dで作成した小品を通じて、楽だった点と苦に感じた点を報告していきます。

OBJ モデルファイルのローダ

miku
https://dl.dropboxusercontent.com/u/108473486/OBJLoader/objLoader.html
https://dl.dropboxusercontent.com/u/108473486/OBJLoader/OBJLoader.zip

前回、かぼちゃをプルプル動かしましたが、色んなモデルを動かしてみたくて、Unity3D アプリを起動した後に、3Dモデルを読み込む機能を探してみました。
どうもそのようなものは無く、自分でローダーを作る必要があるようです。
http://www.everyday3d.com/blog/index.php/2010/05/24/loading-3d-models-runtime-unity3d/
に OBJ フォーマットのローダーが公開されていました。
何ゆえに OBJ が選ばれているかというと、仕様が簡単だからです。

このローダーで対応している OBJ ファイルのタグは、
o オブジェクト定義(GameObject になる)
g グループ
v 頂点座標
vt テクスチャ座標
vn 頂点法線ベクトル
f 頂点番号列によるポリゴン定義
mtllib マテリアル定義ファイル名
usemtl 使用するマテリアル名

で、マテリアルファイルのタグは
newmtl マテリアル名
Ns シャイニネス
Ka アンビエント(ただし、このローダーではサポートしていない)
Kd ディフューズ
Ks スペキュラー
d 又は Tr トランスペアレンシー
illum イルミネーションモード 1:ディフューズ 2:スペキュラー
map_Kd テクスチャファイル名(ただし、WWWクラスで読み込むので、PNG か JPEG のみが有効)
です。

このページで公開されているローダのままで、Blender monkey
http://www.everyday3d.com/unity3d/obj/monkey.obj
が表示できます。
たぶん、セキュリティでために、冒頭に記載した objLoader.html を表示しても、Blender monkey は表示できないかと思いますので、objLoader.zip をダウンロードしてから表示してみて下さい。

ただし、他のモデルだと色々不都合が起こりましたので、以下の修正を行いました。
・オブジェクトとグループは、名称を省略されても良いようにした。
・マテリアルが定義されていないとき、デフォルトのマテリアルを設定するようにした。
・テクスチャと法線が定義されているのに、面の定義でその設定が省略されているときは、
 頂点番号と同じ番号のものを使うようにした。
・面が四角形以上の多角形の場合、三角形分割するようにした。
・d か Tr が 1 未満のときは、Transparent/Diffuse か Transparent/Specular シェーダを使うようにした。

また、描画速度を向上するために、以下の修正も行いました。
・現在と同じマテリアルが定義されたときは、何もしないようにした。
・同じテクスチャファイルは一度しか読まないようにした。

さらに、モデルによっては、三角形の裏面を描画したいときもあるので、裏面、表面、両面と指定できるようにしました。

これでやっと画像で紹介した初音ミク miku.obj がそれなりの速度で描画できるようになりました。
モデルは
http://www.3dvia.com/warehouse/
からダウンロードできますが、登録が必要です。
このモデルではテクスチャファイルとして TGA が使われているので、PNG に変換して使っています。
また、なぜか Tr=0 になっているので、1 に変更しました。

対応していないフォーマットも多々あるかと思いますが、とりあえず、ここまでで自己満足です。
OBJ ファイルをドラッグ&ドロップで表示できるようにしたいのですが、まだできません。
Unity3D ではできないような...

[苦]
Diffuse シェーダ以外のシェーダの組み込み
Diffuse シェーダは WebPlayer からも実行後にロードできるのですが、Specular シェーダなどはロードできません。
Shader.Find( "Specular" )
が null になります。
シーンで使用されているシェーダしか組み込まれないようです。
このため、Specular シェーダなどを使ているダミーオブジェクトを非表示状態でシーンに登録して、必要なシェーダを獲得できるようにしています。
あまりスマートではないと思いますが、他に方法がありますでしょうか?

[注]
頂点数は65000以下でないとダメ。
OBJ フォーマットに限った制限ではありませんが、OBJ の場合、モデル全体が一塊で定義されていることが多く、この制限を越えるサンプルがよくあります。

スポンサーサイト



バネ質点系でモデル変形

rubber lantaern
https://dl.dropboxusercontent.com/u/108473486/rubberLantern/rubberLantern.html

モデルの頂点に、バネ質点系としての特性を与えると、プルプルと変形させることができます。
Unity3D の サンプルの
SIMULATING RUBBER IN UNITY http://rodrigopegorari.net/blog/?p=58
には、おもちゃのアヒルを変形するサンプルコードがあります。
このサンプルでは、頂点カラーを1フレームでの変形量を調節するパラメータに使って、黒なら全く動かず、白に近づくほど変形するようにしています。

今回紹介するものでは、モデルの端を固定して、反対の端にいくほど変形するようにしてみました。
固定される端は、左端、右端、下端、上端、前面、背面から選べます。

少し時期が過ぎてしまいましたが、モデルのハロウィンかぼちゃは、Unity のアッセトストアからダウンロードしたものです。
かぼちゃをドラッグすると、その方向にかぼちゃが伸びて、離すとプルプルと振るえながら元の形に戻ります。

元々のサンプルにバネ質点系の特性に Rubber Duck や Hard Rubber などの名称を付けたものがあったので、そのまま使用しています。
アヒルのおもちゃを変形させているので、デフォルトの特性が Rubber Duck という名称になっています。
カスタムにすると、質量や剛性などをキー入力することができます。

マウスによるドラッグは、すべての頂点に等しく引っ張る力として作用します。
頂点間には物理特性はなく、各頂点は勝手に動いていますが、各頂点の物理特性が全く同じなので、統一的に動くことになります。

このため、重力を有効にしても、左端を固定したときに右端にいくほど垂れ下がるということはなく、不自然なので、無効にしています。

また、変形の方向がすべての頂点で同じなので、2Dのように見えてしまいます。
面白いけど、ちょっと残念な気がします。

Unity3D としては、オブジェクトの MeshFilter の sharedMesh の vertices を変形したものに毎フレーム入れ替えています。
ただし、オブジェクトの座標は、TransformPoint()関数で一旦グローバル座標に変換した上で、力のベクトルによる作用による移動位置を計算し、InverseTransformPoint() でオブジェクトの座標に戻しています。

オブジェクトがない位置でマウスをドラッグすると、カメラを回転できます。
マウスホイールで前進・後退します。
ただし、MacOS のウェブブラウザ Safari だと、"Mouse ScrollWheel" が効きません。
Safari 固有の問題だそうです。
このため、Fキーで、前進, Bキーでも、後退するようにもしました。


[苦]
MacOS の Safari は、"Mouse ScrollWheel" が無効。
対処方法はなく、代替の方法を用意するしかなさそうです。


[注]
今回のサンプルでは、法線ベクトルは更新されない。
使用している方法では、頂点の移動しか計算していないので、陰影が付くシェーダを使うと不自然に見えます。
頂点を共有している面の面法線の平均を取るとか、頂点法線を作る方法はありますが、やっていないです...

スプリング・ジョイント

https://dl.dropboxusercontent.com/u/108473486/Spring-Joint/spring-joint.html

前回、バネ質量系のサンプルを作成したら、スプリング・ジョイントで良いのではないかという気になり、サンプルを作成してみました。
画像は、タイトルが違うだけで前回と同じようなものになるので、省略します。
どのような式でシミュレートされているのか分からないですが、こちらの方がハデに動きます。
何より、球同士の衝突や天井との衝突のシミュレートもやってくれるのが有り難いです。
ほとんどスクリプトを書く必要もありません。
素晴らしい!

オブジェクトに Rigidbody コンポーネントを設定し、さらに Spring Joint コンポーネントに追加します。
Spring Joint には、そのオブジェクトが接続するべきオブジェクトを Connected Body として登録できます。
バネの起点となる位置は、オブジェクトのローカル座標で、Anchor に指定します。
GUI の Anchor はバネ長として、(0,Anchor,0) をアンカーの位置を設定しています。

これを3段に繰り返すと、前回のサンプルと同じような動きをします。
球同士や球と天井をつないでいるのは、物理特性を持たない円筒で、球の中心の移動に合わせて、長さと方向を調節しています。

重力加速度は、Unity3D の Physics.gravity.y に合わせたために、前回のサンプルとは符号が反転しています。
減衰はバネ運動が収まる速度に関するパラメータで、前回のサンプルは 1 でバネによる振動は永続し、0 でそのまま停止するというものでした。
今回の減衰は damper というパラメータで、数値が大きいと逆にバネによる振動時間が短くなります。
上限は 1 を超えても大丈夫です。
単位が何なのか変わりません。

バネが破断する力なども設定できますが、今回は使っていません。

前回、GUI トグルボタンについて説明を忘れたのですが、このボタンをチェックすると、球を固定できます。
isKinematic を true にしているだけですが、マウスによるドラッグは出来ますので、初期位置を好きなところに設定することができます。
ただし、ドラッグではオブジェクトとの衝突は起きません。

[楽]
Spring Joint は、スクリプトいらず!

バネ質点系

バネ質量系
https://dl.dropboxusercontent.com/u/108473486/Spring-Mass/spring-mass.html

Unity3D のサンプルに、SIMULATING RUBBER IN UNITY
http://rodrigopegorari.net/blog/?p=58
というのがありますが、これは
http://processing.org/examples/chain.html
を基にしたということでしたので、まずはこちらから見てみました。
すると、とてもお手軽で面白そうだったので、これを参考に、バネ質点系のサンプルを作ってみました。

このサンプルは、カーソルの位置が上方の球が動いていくベキ位置で、下方の球は上方の球の中心を動いていくべき位置として、バネ質量減衰系で動きます。動きの計算には、重力をY軸正方向(下向き)として、Y軸方向の力に直接足していますが、加速度に足すべきとか、下方の球が上方の球に影響を与えないとか、実際の経過時間が考慮されていないとか、気になるところはありますが、大まかな計算のための簡略化だろうと思います。

全く同じサンプルでは芸がないので、下方の球は上方の球に影響を与えるようにして、全部の球をマウスでドラッグできるようにしてみました。球の直径は1mで、格子は5m間隔になっています。バネ長は力がかかっていないときのバネの長さで、これより長くなれば引っ張りの力、短くなれば逆に押す力がかかっていることになります。
経過時間も Time.deltaTime を使っています。
何となくそれっぽく動きますが、シミュレーションと言えるほど厳密ではないし、検証もしていません。

球同士の衝突や天井との接触は考慮していません。
球と球や球と天井を結ぶ線は、円筒の長さと向きを調節しているだけで、これ自体には物理特性を持たせていません。
極端なパラメータで動かすと、発散してしまうことがあります。
そのときは、「初期化」ボタンで初期化して下さい。

今回、Unity3D としての楽苦は、特にありません。
が、やっているうちに、Unity3D には Spring Joint があったに思い至りました。
たぶん、これを使えば、同様なことがもっと楽に行えるのではないかと思い、取り掛かっています。

プロフィール

海栗亭楽苦

Author:海栗亭楽苦
FC2ブログへようこそ!

最新記事

最新コメント

最新トラックバック

月別アーカイブ

カテゴリ

検索フォーム

RSSリンクの表示

リンク

ブロとも申請フォーム

QRコード

QR