‘three.js’ タグのついている投稿

three.jsで遊んでみる(24)

 プログラム,
 公開日:2014年4月8日 / 更新日:2014年4月9日

とあるカメラモーションにおいて、
輪郭線の太さが変化するという現象が起きていました。
調べてみたところ、
fov(画角)が変わると輪郭線の太さも変わることが分かりました。

画角に対する対応が不十分だったようです。
あと、計算が間違っていたりしました(^_^;)

そんなわけで改善してみました。
詳細については、
以前の投稿内容を更新したのでそちらを参照してください。

テストではこちらこちらのデータを拝借しました。
画角の変化が多用されているのでテストにもってこいでした。

ということで動作を参照するには以下からどうぞ。
比べてみると違いが認識できると思います。
改善前はこちら
改善後はこちら

なんか最近やたらとサーバーが重いことがあります・・・。
激しく気長に待ってみてください(^_^;)

ChromeなどのWebGL対応のブラウザで見てください。PCパワーもそれなりに必要となるかもしれません。反応がない場合は、リロードして再度試してみてください。

20140408

three.jsで遊んでみる(23)

 プログラム,
 公開日:2014年3月30日

IKがうまく行かないことがあるようです。
対策を入れてみました。

ついでにseekバーなコントローラを導入してみました。
また処理を軽くするために fxaa なアンチエイリアスは止めました。

なお、
shadow などのチェックを全て外し、
outline scale をゼロにすると動作的に一番軽くなります。

テストではこちらのモーションを拝借しました。
ということで参照するにはこちらからどうぞ。

なんか最近やたらとサーバーが重いことがあります・・・。
激しく気長に待ってみてください(^_^;)

ChromeなどのWebGL対応のブラウザで見てください。PCパワーもそれなりに必要となるかもしれません。反応がない場合は、リロードして再度試してみてください。

20140330.001

three.jsで遊んでみる(22)

 プログラム,
 公開日:2014年3月5日

前回
PNG画像の透過判定はメンドイのでとりあえずやらない
みたいなこと書きましたが、
バイナリデータとして改めて読み込んで
PNG形式に則って解析すればイイんじゃね?
と気づきました(^_^;)
同じファイルを2回読むことになってしまいますが、
画像として読み込んだ後にやれば、
ブラウザ側でキャッシュされてるはずだから速度的にも気にならないだろうし。
そんなわけでアッサリとJavaScriptで透過判定できました。
ちなみに判定方法はこちらを参考にしました。

ついでに今回は、
BDEF4にも対応してみました。

MMDのPMX形式では、
ボーン変形による頂点blendingとして、
BDEF1,BDEF2,BDEF4,SDEFの4つをサポートしていますが、
今まではいずれもBDEF2として扱っていました。

three.js(r58)でサポートしていたのが2ボーン(つまりBDEF2)だったので、
それに沿うように実装していたためです。
ただ内部的には4ボーンまでのデータ領域は確保されており、
そのうちの2つを使うようになっていました。
(※three.js(r66)では4ボーンをサポートしたようです)

従来の実装では、
BDEF1 -> 2つめのボーンの参照インデクスと重みをゼロにすることで、BDEF2へ変換。
BDEF2 -> そのままBDEF2として扱う。
BDEF4 -> 重みの大きい方から2つを選び、重みの合計を1.0に正規化することで、BDEF2へ変換。
SDEF -> SDEF固有部分を無視することで、BDEF2相当として扱う。

だったのが、
今回の実装では、
BDEF1,2,4 -> フラグ判定によりそれぞれ純粋に1,2,4ボーンによる変形として扱う。
SDEF -> SDEF固有部分を無視することで、BDEF2相当として扱う。

と変えました。
判定用のフラグとしての頂点属性を追加するのが素直な実装になるのですが、
その分のメモリが余計に必要になったりします。
頂点数が数万個とかになったりすることもあるので結構バカにならないのです。
そこで、ボーンの参照インデクスが必ずゼロ以上になることを利用して、
負数なデータを埋め込むことで、
属性を追加することなくできるように実装を工夫しました。
シェーダーレベルでの改良なので、
場合によっては以前より速度の向上も期待できるかもしれません。

なお、
BDEF4の動作はテストで一応確認済みなのですが、
テストで使ったデータファイルのサイズが大きいため、
今回はテスト動作の公開はありません。
ローディング時間があまりにも長くなりそうなので、やめました。
ここのサーバー、最近なんか重いし変だし・・・(^_^;)
WebGL的にもメモリが厳しくなりそうだし。
BDEF4を使用したほどよいサイズのPMXがあるとよいのですが。

ということで、
変更は前回の方に適用しておきましたので、そちらを参照してください。
といっても内部的な改良なので、見た目には変わっていませんが(^_^;)

three.jsで遊んでみる(21)

 プログラム,
 公開日:2014年2月20日 / 更新日:2014年3月16日

このシリーズの書き込みは久しぶりだったりします。

先日、
とあるPMXなファイルを読もうとしたら、
うまく動かなかったので今回対処してみた次第です。

以前にも書いたりしましたが、
PMXの読み込みに対応してはいるものの、
PMDの代わりっぽく扱っていたりしました。
実際、今までテストで使っていたPMXはPMDから変換したものです。
そんなわけでピュアにPMXなファイルを読み込んでみると、
いろいろ不具合が発覚したりしました(^_^;)

ときに、
PMXではPMDよりテクスチャを多用しているのが多い気がしました。
sphereマップを使って光源処理による陰影感を抑えるようにしてたりとか、
いろいろ工夫があって面白いですね。
ファイルサイズが10MBを超えるようなものもあったりしました。
某MMDなアニメで配布されているのを試してみたのですが、
WebGLではメモリ食い過ぎるようで厳しい感じです(^_^;)

ということで、
修正&改善した所は以下の通りです。

  • データ要素を参照する際のindexサイズの扱いが不十分でした。頂点だけ扱いが特別なのですが、やり方がおかしかったのを修正しました。
  • BDEF2などのボーン変形による頂点blendingにおいて、ボーンの参照インデクスが-1、つまりボーン指定無しの場合は安全のためにインデクスはゼロに変えました。当然、対応する「重み」はゼロになります。
  • 同名のテクスチャファイルを複数読む場合は、共有して使いまわせるようにしました。
  • toonテクスチャの参照インデクスが-1、つまりtoon無しに対応しました。PMX仕様には明記されていないのですが、こういうのが認められているようです。素直にシェーディング処理だけをやれば良いのかと思ったのですが、MMD的には光源処理を無効にする指定になるようですので、そのように対処しました。
  • sphereモードは乗算に加えて加算にも対応しました。
  • sphereありの指定(乗算や加算モード)なのに、sphereテクスチャの参照インデクスが-1、つまりsphere無しという矛盾する場合があるようです。これはsphere無しとしました。どうやら編集でこういうのが作れてしまうようです。
  • PNGをテクスチャとして使う場合は常に「透過」扱いにするようにしました。そのため多少効率が悪くなるかもしれません。本来なら透過成分があるかどうか判定したいところですが、JavaScriptの場合はかなり煩雑なのでやっていません。いったんcanvasに描画して、ピクセルのアルファ成分を1つずつ調べて行く方法しかなさそうなので。もっと簡単に判定できる方法があればよいのですが。別途phpとかでヘッダ参照して調べるほうが早いかも。ちなみに、不透過の場合は手前から奥、透過の場合は奥から手前に描画しないと期待したような結果にならないのです。three.jsはこれを自動でやってくれてます。
  • あらかじめ全てのモーフターゲットを生成していたのを、必要な分だけ生成するように変えました。メモリ使用量が減ってくれるはず。

これらの対処によって、数MB程度までのPMXファイルならば
とりあえず動作してくれるようになると思います。
実は、変な描画になってしまうPMXが一部あったりするのですが、
原因はよくわかってません。

テストではこちらのデータを拝借しました。
ちびミクさんはなんとも愛らしくて良いですね。
影の有無とか輪郭線の太さを調整できるようにもしてみました。
ということで参照するにはこちらからどうぞ。
ローディングにちょっと時間かかるかも。
なんか最近やたらとサーバーが重いことがあります・・・。
激しく気長に待ってみてください(^_^;)

ChromeなどのWebGL対応のブラウザで見てください。PCパワーもそれなりに必要となるかもしれません。反応がない場合は、リロードして再度試してみてください。

20140220.001

なお、
現状で対応できていない所があります。
以下に列挙しておきます。

  • BDEF4
  • SDEF
  • 回転・移動付与による変形
  • 頂点毎の輪郭線スケール

いずれ、どうにかしたいですね(^_^;)

three.jsで遊んでみる(20)

 プログラム,
 公開日:2013年6月26日 / 更新日:2013年10月30日

今回は、
three.jsのMeshにおける境界球(bounding sphere)の
扱いに気になる所を見つけたので、
それについて書いてみたいと思います。

three.jsではMeshを作る際に、
geometryとmaterialを渡すのですが、
geometryに境界球が設定されてなかった場合は、
自動的に作られるようになっています。
視錐台カリング(frustum culling)で必要となるからです。
視錐台カリングについては後ほど触れます。

上記で作られる境界球は以下のようになります。
中心=Meshの原点(0,0,0)
半径=geometryの頂点情報から計算

ここで気になるのが、
頂点情報から重心(中心)を求めた後に、
半径を計算していないことです。
Meshの原点と、構成する頂点の加算平均(重心)は、
必ずしも一致しないはずですが、
three.jsでは原点が中心という前提になっている?

ちなみにMMDなミクさんのモデルで境界球を求めてみると、
だいたい以下の様な数値となっていました。

・three.jsのデフォルトの場合
中心=(0, 0, 0) 半径=22.115

・境界ボックスを求め、それに外接する球を計算した場合
中心=(0, 10.139, -0.874) 半径=12.489

three.jsのデフォルトでは半径が倍くらいになってしまうので、
視錐台カリングの際に効率が悪くなってしまいそうです。

視錐台カリングというのは、
カメラの視界(視錐台)に含まれないオブジェクトを、
あらかじめ除外することで無駄な描画をしない方策のことです。
こちらのページの図を見ると分かりやすいかと思います。

three.jsでは
オブジェクトの境界球を使って視錐台カリングを行なっていますので、
出来るだけフィットするような境界球が望ましいことになります。

ところで
ミクさんのモデルはSkinnedMeshとなっています。
SkinnedMeshでは、自身の座標系以外に
内部にボーンによる座標系の階層を持っており、
Skeleton(骨格)が構成されています。

ミクさんのモデルの原点は、
両足の中間あたりで地面に接する位置、
骨格のルートである0番目のボーンの原点は、
だいたい体の中心あたりの位置、
となっているようです。

重要なことはこの状態でskinアニメーションすると、
ルート配下のボーンの位置とか変化しますが、
モデルの位置は変わりません。
アニメーションで対象となるのはボーンなので。

したがって、
ルートボーンの位置に応じて、
境界球の中心も調整してやる必要が出てきますが、
three.jsでは考慮されてないので
自前で対処する必要があります。

また本来なら、
アニメーションを更新する毎に、
境界球の中心と半径を再計算するのが理想ですが、
それなりにコストがかかるのでやってません。
初期のバインドポーズ時に求めた境界球のままでも、
おおむね問題なさそうにフィットしている感じです。
ミクさんが髪の毛を振り回した時とか微妙に気になるけど(^_^;)

色々書きましたが、
説明だけでは分かりにくいですよね(^_^;)
ということで、視覚化してみました。
こちらです。
左のモデルはthree.jsのデフォルトな境界球で、
中央のモデルは調整した境界球です。
調整した方は、
アニメーションに追従するようにしてあるので、
適正な視錐台カリングになってくれると思います。
なお、
緑色の球はモデルの原点の位置を表しています。
アニメーションによってルートボーンの位置は変わったりしますが、
モデル原点は最初のままの位置なことに注目してみてください。

ChromeなどのWebGL対応のブラウザで見てください。PCパワーもそれなりに必要となるかもしれません。反応がない場合は、リロードして再度試してみてください。

mytest24

ところで、
視錐台カリングのコードは
だいたい以下のような感じになっています。

frustumは行列から計算された6つの平面から成っており、
閉じた領域を示しています。
これら平面と境界球との距離を求めることで、
frustumとの交差が判定されるようになっています。

ただ、
交差判定のコードを参照してみると、
なぜか境界球の中心位置を使わず、
オブジェクトのワールド行列から求めた位置を使っています。
つまりオブジェクトのローカル座標系における原点に対応する位置です。
これはちょっとおかしいと思うので、
境界球の中心位置を使うように変更しました。
変更後のコードは以下の様な感じになります。

上記のコードにあるように、
交差判定はワールド座標系で行われていますが、
なぜprojScreenMatrixから求められたfrustumが
ワールド座標系での6つの平面を示すことになるのか、
よく理解できてなかったりします(^_^;)
う~ん、なんでこれでいいんだろ?

よく分かってないけど、
そういうもんなんだとしておきます(^_^;)

でも、
このように視覚化してみると
見事にうまく行っています。
黄色い線で囲まれた領域が視錐台に相当します。
青い球がカリングされたオブジェクトで、
赤い球が交差判定されたオブジェクトとなります。
マウスでグリグリ動かしてみると、
分かりやすくなると思います。

mytest26