- 概要
- three-vrmのupdate処理をまず呼び出す
- カメラ目線にする
- ポーズの変更方法(vroidposeデータから変更する)
- 表情の変更方法
- 口の形の変更方法
- 変なテクスチャが表示されてしまう問題
- 解像度問題の対応
- vrm.update処理の中身について
- サンプルコードはこちら
- vroidposeにまつわる問題点
three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する方法を載せています。
こちらはPart-02となり、Part-01の内容を前提としたものになっています。
今回は以下のコード例を載せています。
Part-01のコードがベースなので、「/* 追加 start */~/* 追加 end */」という形で、追加部分を明記しています。
今回紹介するコード例
- three-vrmのupdate処理をまず呼び出す
- カメラ目線にする
- ポーズの変更方法(vroidposeデータから変更する)
- 表情の変更方法
- 口の形の変更方法
- 変なテクスチャが表示されてしまう問題
- 解像度問題の対応
また、今回も例によって、実際に動作確認できる(であろう)サンプルコードを下部に載せています。
今回行う内容(例えばカメラ目線にする)の中で、three-vrmが用意しているupdate処理を毎フレーム行うことでモデルに反映されるものがあります。
そのため事前準備として、animateメソッドの中でVRoidのアップデート処理を呼び出しておきましょう。
最後の方でこのvrm.updateについて簡単にまとめますが、色んな自動計算を行ってくれているようです。
また、この追加とともにvrmの初期化のあたりで、以下を入れておいてください。
これも後述しますが、これをしないと後の手順で行う「ポーズの変更」がVRoidに反映されないはずです
VRoidをカメラ目線にします。
より正しく言えば、vrmの初期化時にVRoidの注視点をカメラに設定します。
行数で言うとたった6行で完了(後は前項のvrm.updateを呼び出す必要あり)。
最初の2行が「VRoidがカメラを見る」(VRoidの眼球をカメラに向ける)というものになります。まぁそのままですね。
最後の4行ですが、デフォルト設定だとそんなにカメラを見てくれなくて、微妙に違う場所を見ている感じになってしまいます(一旦この行を消して試してみると分かりやすいです)。
そのため、カメラに目を向ける補正値を大きくすることでカメラ目線になるようにします。あまりに大きい値にすると今度は行き過ぎてしまうので丁度いい値を探すと良いと思います。
VRoidのポーズを変更します。
手動で設定するのも良いですが、vroidposeファイルを使用するのが楽だと思うのでその方法で書きます。
html側でもファイルを読み込めるようにする
ファイルを読み込む処理が入っているので若干行数多めですが、肝心のポーズを変更する処理は「vrmBone.quaternion.set(quat.x, quat.y, -quat.z, -quat.w)」の一行のみです。
もしこの処理を入れても、上手くいかないようであれば最初のvrm.update処理の中で記述した「vrm.humanoid.autoUpdateHumanBones = false;」と言うのを忘れているのではないかと思います。
ところでthree-vrmで読み込んだvroidモデル情報には「rawBone」と「normalizedBone」という二つのボーン情報が入っています。
・rawBone:threejsが持っている大元のボーン情報。本処理で書き換えてるのはこっち。
・normalizedBone:three-vrmjsによってvrm用に正規化されたボーン情報。
vrm.updateメソッドを呼び出すと、このnormalizedBoneからrawBoneに自動的にいい感じにボーンを設定してくれます。
なので逆に言うと、vrm.updateメソッドを使ってしまうとrawBoneを書き換えても勝手にnormalizedBone情報からrawBone側を勝手に書き換えてしまい、元のポーズに戻ってしまいます。「vrm.humanoid.autoUpdateHumanBones = false;」とすることで、その書き換えをさせないようにしています。
本処理ではrawBoneを使っていますが、normalizedBoneを使うことで、vrm側の設定違い(軸やポジションの違い)を補正してrawBone側に設定してくれるようです。なので、normalizedBoneを使う方が無難ではあるかと思います。
normalizedBoneを使いたい場合は上のコードの「vrm.humanoid.getRawBoneNode(lowerBoneName)」を「vrm.humanoid.getNormalizedBoneNode(lowerBoneName)」としたうえで、「vrm.humanoid.autoUpdateHumanBones = false;」を消せば良いです。
また、「手の形」は反映されません。これは元のvroidposeデータを見れば分かると思いますが、手だけはボーンではなくテンプレートを指定して設定されているためです。テンプレートを手のボーンに変換しないとVRoidには反映できないかなと思います。
表情変更も簡単です。
html側で切り替えできるようにする
実質「vrm.expressionManager.setValue('relaxed', 1.0);」の一行のみです。
setValueの引数に、「表情」と「変更の度合い」を設定すれば良くて、もし怒りと悲しみを0.5ずつ設定したいときは「setValue('sad', 0.5)」「setValue('angry', 0.5)」にすれば良いだけです。
ちなみにVRoidStudioで作ったモデルであれば、以下の表情が設定できると思います。
・relaxed
・sad
・angry
・happy
・Surprised
・neutral
口の形の変え方はほぼ表情変更と同じです。
html側で切り替えできるようにする
実質「vrm.expressionManager.setValue('aa', 1.0);」の一行のみです。
表情変更とほぼ同じですね。
ちなみにVRoidStudioで作ったモデルであれば、以下の口の形が設定できると思います。
・aa
・ih
・ou
・ee
・oh
Part-01では、モデルの首の下や背中部分に不自然に黒いテクスチャが出現していたかと思います。
これというのは実は服のテクスチャに、「ほぼ透明に近いけど透明ではない部分」があり、それが不透明度1.00(最大)として表示されてしまっていたためです。
しかし、恐らく現状のコードであれば多分透明になっていると思います。
一番最初に行った「vrm.update」メソッドがこの部分をいい感じにしてくれているようで、それによって透明になっているようです。
なので、現状対応不要なのですが、vrm.updateメソッドの処理をすべて行うとは限らない(後述)ので、一応個別に設定したい場合の方法を書きます。
テクスチャは複数あるので、ループで回す必要はありますが、肝心の個別設定は「val.uniforms.alphaTest.value = 0.02;」の一行のみで設定できます。
このalphaTest.valueという値が閾値になっており、これ以上の不透明度のテクスチャは不透明度1.00(最大)として表示されるようです。初期値は0なので、ごくわずかでもテクスチャに不透明な場所があるとそれが不透明度1.00(最大)として表示されてしまうということです。
vrm.updateメソッド内で行われているテクスチャ関連の自動更新処理がこのalphaTestの値をいい感じに変更してくれるようなので、vrm.updateメソッドをきちんと呼んでいればこの問題は多分起こらないと思います。
スマホなどの高解像度の端末で表示すると、綺麗にcanvasが表示されず若干崩れて表示されることがあります。
まぁ原因は解像度が高いから、とそれ以上でもそれ以下でも無いですが、解像度の設定も容易にできます。
window.devicePixelRatioの値が、Android端末だと大体3.5倍くらいなのですが、割と顕著に処理が重くなります。もちろん元のcanvasサイズが大きければ更に重くなります。
実際にはwindow.devicePixelRatioの値をそのまま設定するのではなく、「Math.min(window.devicePixelRatio, 2.0)」などとすることで、上限値を設けた方が良いと思います。
何度も話に出てくる「vrm.update」メソッドについて、簡単に書いておきます。
このメソッドですがざっくり以下のことをやっているようです(更に深堀りすると複雑になるので、更に細かく見たい場合は御自身でご確認ください)。
今回の所で言うと、this.lookAt.updateメソッドはかなり関係します。カメラ目線にする際、カメラをターゲットにするだけで良かったですが、それはこのメソッドのおかげです。
コード量を減らすためにvrm.updateメソッドはきちんと利用するべき(というかそうしないならthree-vrmを使う意味が……)だとは思いますが、毎フレーム呼ばれている処理なので不要な処理はなるべく呼びたくないという人もいると思います。そういう方はvrm.updateメソッドの中身を見て個別に呼び出すのが良いかと思います。
サンプルコードはPart-01と同じ場所(GitHub)にあります。
vroidposeデータはVRoidStudio用のポーズデータですが、前述の通り「手の形」はそのままではボーンに反映されない問題があります。
こちらは対応がまだできるのですが、「SpineControlPointDeltaPosition」という独自の設定をボーンに反映するのが難しいです。
何か良い対応方法が思いつけば記事にするかもしれません。