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

 プログラム,
 公開日:2014年5月14日 / 更新日:2014年9月22日

残念ながらいまだ、
うまく再現できないPMXがあったりします(^_^;)
今回、改善や対応が少し進んだりしたので、
書いてみたいと思います。

1つ目は、物理演算の改善。

物理演算の剛体には、
大きく分けて静的と動的の2つがあり、
拘束条件によって2つの剛体を結び付けるようになっています。

MMDでは、拘束条件はジョイントと呼ばれ、
剛体には対応するボーンが設定されています。
MMDの剛体は以下の3タイプとなっています。

・type0:ボーン追従(静的)
・type1:物理演算(動的)
・type2:物理演算(動的)+ボーン位置合わせ

特徴的なのが type2 で、
当初はよく分からないので type1 として扱っていましたが、
最終的にはこちらで書いたように理解しました。
要するに、拘束条件のアンカーにロックさせるために、
強制的にボーンの位置を適用させる動的剛体ということになります。
位置はボーンのを、回転は動的剛体のを適用するわけです。
私の実装においては、
これは相手の剛体が静的である場合に成立します。
つまり、type2の相手はtype0である必要があります。
さらに対応するボーンの親子関係が、
type0 -> type2 でないとうまく行きません。

ところが、PMXファイルの中には、
剛体のジョイント関係が次のようになっていることがあります。
type0 -> type2 -> type2 -> type2 …
例えば、頭から連なる髪とかで見受けられます。
このままでは、固まったようになってしまい、
うまく動作してくれませんでした。
そこで、親側が静的剛体で無い場合は、
子側のボーン位置合わせは無効にするようにしました。
つまり以下のように強制的に変更するようにしました。
type0 -> type2 -> type1 -> type1 …
これで、期待したような感じになってくれました。
MMD的には厳密でないと思いますが、まぁ良しとしましょう(^_^;)

2つ目は、「付与」変形の対応。

あるボーンの変形量に他のボーンのを率を掛けて加算するのが「付与」です。
変形量は移動または回転です。
対象ボーンをA、参照するボーンをBとして、
Aのローカルな変形量 += Bのローカルな変形量 × 付与率
と素直にやってみたのですが、どうにもうまく行きません。
調べてわかったのは、
モーションによる変形の差分を適用する必要があるようです。
つまり、
ある描画フレームとその次のフレームでの変形量の差分を求めて、
それに対して付与を計算しないとダメなようです。
要するに、以下の様なことになるようです。
Aのローカルな変形量 += Bのローカルな変形量の差分 × 付与率

2014年9月21日追記。
付与の実装方法が間違っていました(^_^;)
詳しくはこちら

また、
付与については変形順序に注意です。
PMXにはボーンの変形順序が規定されているのですが、
今までは無視しても動いていました(^_^;)
three.js内部で行われる部分については、
制御するのが困難だったというのも理由だったりします。
ただ付与だけは対応しておく必要がありそうです。

さて、
テストでは以下のデータを借用させていただきました。
モデルはこちら、モデルモーションはこちら、カメラモーションはこちら
ということで動作を参照するにはこららからどうぞ。

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

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

20140514.001

タグ: ,

コメント / トラックバック 3 件

  1. to より:

    【ご相談】
    はじめまして。最近Three.jsをやり始めて参考にさせて頂いてます。

    以前の投稿(7)を参考に、r66でトゥーンシェーダを実装しており、renderMesh()を2回実行するマルチパスの動作自体はうまくいっているようなのですが、レンダリング結果が「パス1(Front)とパス2(Back)の合成」ではなく「パス2のみ(Back)」になってしまいます。

    恐縮ですが、何かお心当たりはありますでしょうか?

    マテリアルには、ShaderMaterialを使用し、renderMesh()後の
    コールバック関数で、描画面とVertex・Fragmentの内容を切り替えています。

    • 管理人 より:

      カリングの設定がうまく行ってないのかもしれません。

      わたしの場合は、
      preRenderPassの
      はじめのパスで、
      gl.enable( gl.CULL_FACE );
      gl.cullFace( gl.BACK );
      次のパスで、
      gl.enable( gl.CULL_FACE );
      gl.cullFace( gl.FRONT );
      とやってます。

      ただし、
      postRenderPassで
      gl.enable( gl.CULL_FACE );
      gl.cullFace( gl.BACK );
      とやってデフォルトに戻しておきます。

      基本的にはカリングはBACKなので、
      FRONTに変更した時だけ、
      後でデフォルトのBACKに戻すようにすれば良いのですが、
      どっかで変更されてたりする可能性があるので、
      多少冗長的でも毎回設定し直すようにした方が無難かと思われます。

      こちらのソースの1248行目あたりを参照してみてください。

コメント投稿