前回の続きです。
ということで、
最近の three.js のソースコードを眺めた結果、
MMDを扱うために改造すべき点などが見えてきたので
それらについて書いてみたいと思います。
過去の投稿でも書いていますが、
Object3D
クラスにおいて、
オイラー角とクォータニオンは相互に同期するようになっています。
どちらか一方を変更する度に変換計算が行われるわけですが、
気になるのはその変換コスト。
基本的に回転はクォータニオンでやることになるので、
オイラー角->クォータニオンはまだしも、
クォータニオン->オイラー角 は無くても良さげなので、
同期は一方通行に改造します。
かつての Vector3
には perspective divide を伴う、
applyProjection()
と、伴わない applyMatrix4()
という
2種類のマトリクス変換メソッドが用意されていましたが、
現状では applyMatrix4()
へ統合されています。
perspective divide が必要なのかどうかは、
分かりにくかったりするので統合されたのだと思います。
ただ、マトリクスのw成分が(0,0,0,1)であることが確実なら、
perspective divide するのは無駄な計算になります。
そこで、perspective divide をしない版の
メソッドを追加して対応することにしました。
three.js r58 の頃はありませんでしたが、
現状では SkinnedMesh
のボーンによるスケルトン構造が
Skeleton クラスとして独立しています。
さらに、SkinnedMesh
には bindMode
というのが追加されています。
いまひとつよく分かってはいませんが、一つのスケルトンを
複数の描画オブジェクトで使い回せるようにするための機能のようです。
ただ、MMDライブラリとの折り合いをつけるのが難しい感じだったので、
bindMode
を使わない、かつてのやり方でも行けるように改造します。
スケルトン内における各マトリクスはグローバルに扱えるようになってないと
どうも上手くやれない感じです。
また合わせて、ヘルパークラスである SkeletonHelper
についても
同様に対応させるために改造します。
かつては、マテリアルに
castShadow
や receiveShadow
というプロパティ がありましたが、
現状では影を投げたり受けたりが、メッシュ単位でしか出来なくなっています。
普通に考えればそれで十分だったりするわけですが、
MMD的には都合が悪いので、
以前のようにマテリアル単位でも出来るように改造します。
輪郭線描画を実装するために、マルチパスな描画機能を追加します。
以前に書いてたりしてますが、それと同様な改造になります。
シェーダーについては、
three.js の phong を参考にしつつも大幅に手を入れます。
MMD的にはリアリスティックにする必要はないので、
基本的には直接光による効果のみになるように改造します。
簡便なフォンシェーディングといった感じにします。
ただ、かつてはマテリアルにあった ambient 成分が現状は無くなっています。
前回で書いていますが、
直接光の派生で間接的な影響が生じるということになっているので、
間接光の一種である ambient を成分として持つことは、
現状とそぐわないことになってしまいます。
なので、削除されたものと思われます。
環境光である ambient はマテリアルではなく、
ambient光やhemisphere光などの環境光源による影響を、
間接光として加えることで処理されるようになっています。
一方、MMDのマテリアルには ambient 成分があるため、
マテリアルの成分として復活せざるを得ません。
しかしそうすると、現状の環境光源と折り合いがつかなくなってしまいます。
うーん、困りました・・・。
仕方ないのでMMDの ambient はあらかじめ焼き込まれた環境光として扱い、
three.jsの環境光源による影響は無いものとして処理することにしました。
ということで、
だいたいの改造方針が決まりました。
あとは SDEF をどう実装するかだけです。
が、少し長文になってしまい、
書くのも疲れたのでまた次回で(^_^;)