[Astro] #185 トップページの世界に風・雪・夜を足す 01 — 髪・霧・雪を 1 つの風でつなぎ、調整パネルで決める
はじめに
前回は、.git の中身を調べるツール、Git Inspector を作りました。
[Astro] #184 ブラウザだけで動く .git 解析ツール — 重い理由と、中身を、読むだけで調べる
ブラウザの中だけで動く、.git の中身を調べるツール Git Inspector を作りました。
lain-lab.com今回は、ツールではなく、トップページの 3D の世界の話です。先日、トップページに霧を足しました。ところが、霧は薄すぎて、最初は「出ていない」と思ったほどでした。設定の数字(JSON)を直して、やっと見えるようになりました。
霧が見えるようになると、次を足したくなります。
- 風: VRM の髪は、揺れやすい作りです。風を感じられるはず。ただし、風は目に見えません。霧と連動させれば、見えるようになります
- 雪: もうすぐ冬です
- 夜: 時間に合わせて、暗くなったり明るくなったりする。ライティングは大事です
- スポットライト: 夜は、アバターが暗くなるので、照らしたくなります
1 回では終わらない内容なので、シリーズにします。この記事は、その 1 回目です。風と雪は、実機で良い見た目になりました。夜とスポットライトは、仕組みはできたものの、見た目はまだ決まっていません。 決まっていないところも、そのまま書きます。
作ったもの
どれも、data/weather.json という 1 つの JSON で、設定します。値を直して再読み込みすれば、反映されます。
- 風: 風の強さと向きを 1 か所で持ち、髪・霧・雪が、同じ風を読みます
- 雪: 粒(Points)を、カメラのまわりの箱の中に降らせます
- 時間帯: 時刻から、画面全体の明るさ、環境光、空の色を変えます。時刻は、JSON に書けば固定(テスト用)、書かなければ今の時刻(PC の時計)です
- スポットライト: 夜に、アバターを照らす光(途中です)
- 右クリックメニューのスイッチ: 霧・風・雪・昼夜を、見る人が ON / OFF できます。値は記憶せず、再読み込みで JSON の設定に戻ります
- 調整パネル: スライダーで値を動かしながら、画面を見て決める道具。今回の、いちばんの収穫でした
(画像: 風が吹いて、髪が揺れ、霧が流れている画面)
風
髪は、スプリングボーンで揺れる
VRM の髪や服の揺れは、スプリングボーン(揺れ物の物理)で動いています。three-vrm では、vrm.springBoneManager.joints の中に、揺れ物の関節が入っていて、それぞれに gravityDir(重力の向き)と gravityPower(重力の強さ)があります。
風は、この重力に、風のベクトルを足して、実現しました。
- モデルを読み込んだとき、全部の関節の、元の重力の向きと強さを覚えます
- 毎フレーム、「元の重力 + 風」のベクトルを、向きと強さに直して書き込みます
- 風を止めたとき(OFF、または ROOM 以外のモード)は、覚えておいた元の値に戻します
スプリングボーンの更新そのものは、これまでの場所で行われているので、設定の値だけを書き換える作りにしました。
最初の風は、不自然でした
最初は、一定の強さで、右から吹かせました。髪は動きましたが、傾いたまま止まりました。強さを 0.5 から上げても、見た目は変わりませんでした。揺れ物の硬さで、頭打ちになるからだと考えています(確認はしていません)。
「風に動きがないので、不自然か」と気づいて、風の強さを時間で変えました。
- 周期の違う 3 つの波を混ぜて、規則的に見えないようにします
- 真ん中を急にして、凪ぎ(ほぼ 0)と突風(ほぼ最大)を、はっきりさせます
- 計算上、約 27% の時間が凪ぎ(強さが 0.25 未満)、約 36% が強め(0.75 超)で、強弱の切り替わりは 1 秒に 1 回ほどです
凪ぎが入ったことで、髪が戻って、また吹かれる、という動きになりました。「0 と 0.5 を、不規則に入れ替えれば、風の揺れになるのでは」という、見ていて出た思いつきが、そのまま正解でした。
風の向きも、少しゆらがせます。最初は ±25° にしましたが、「左から右だけだね」と言われました。広げる値(swayDeg)を、調整できるようにしました。
霧と連動させて、風を見える化
霧は、半径の違う球の殻に、ノイズで濃淡をつけたものです。ノイズを引く座標を、風の向きにずらして行くと、霧の模様が風下へ流れます。髪と霧が、同じ風を読むので、髪が右に揺れるとき、霧も右に流れます。
実機では、「風があって、髪の動きとシンクロしてる」と、確認できました。
ただし、霧が出ていないとき(晴れ)には、風は髪でしか見えません。「霧がある時だけでいい」ということにしました。
雪
雪は、Points(粒)です。
- 粒は 2,500 個です。位置は、頂点シェーダーの中で計算します。CPU が毎フレーム渡すのは、時間と、落ちた量と、風で流された量くらいです
- 粒は、カメラのまわりの、12 × 8 × 12 メートルの箱の中にあります。箱の外に出たら、反対側から入るように、余りの計算(
mod)をします。カメラが動いても、箱はついてくるので、ずっと降り続けます - 横への流れは、風から受け取ります。風が止まれば、まっすぐ落ちます
- 粒ごとに、揺れの位相と速さを変えて、ひらひらさせます
- 箱の端と、カメラの近くでは、薄くします。粒が突然出たり消えたり、目の前に大きな粒が出たりするのを、防ぐためです
- 人・ステージの後ろの粒は、深度テストで隠れます
数値の検証として、単体の WebGL で、「量が 0 のとき、粒が 0 個」「量に比例して増える」「遠くへ動かしたカメラにも、ついてくる」ことを確認しました。
実機では、「これはいいわ」と、見た目を確認できました。
(画像: 雪が降っている画面)
時間帯(夜)
動かすもの
画面を暗くするだけなら、画面全体の明るさを下げれば済みます。ただ、それでは、空が青くなりません。そこで、次を動かすことにしました。
- 画面全体の明るさ: レンダラーの
toneMappingExposure - 環境光: シーンにあった
ambientLightを、時間帯の倍率と色を掛ける部品に置き換えました - 空の色: カメラを中心にした球の殻を、背景の手前に置いて、色を掛け算します(
画面の色 × 殻の色)。人・ステージの手前には出ません - 環境マップの強さ:
scene.environmentIntensity
時刻は、JSON で決める
時刻は、JSON の time.override に "22:30" と書けば、その時刻に固定されます。空にする(または書かない)と、PC の時計に従います。「時間を消すと、今の時間」という使い方です。
時刻ごとの値は、キーフレームとして、JSON に並べます。
- 時刻(
at)、画面の明るさ(exposure)、環境光の強さと色、空の色、スポットライトの強さ、環境マップの強さ - キーの間は、なめらかに補間します。24 時間でつながるので、夜から翌朝へも、途切れません
- 朝焼けと夕焼けは、そのときのキーの色で作ります(06:30 と 17:30)
補間のテストは、「24 時間を 1 分ずつ見て、急な変化がない」(1 分あたりの最大の変化は 0.012)、「時刻が壊れたキーは無視する」「キーが順不同でも動く」を確認しました。
実機では、時刻を 22:30 に固定して、夜の青い空になることを、確認しました。夕方に開いたら、夕方の薄暗さがそのまま出ました。時刻が実際の時間と連動しているので、リアルに夕方は薄暗い、という当たり前のことに、あとで気づきました。
(画像: 夜にしたトップページ)
スポットライト — ここが、まだ決まっていません
夜になると、アバターが暗くなります。そこで、アバターを照らすスポットライトを足しました。
- アバターの子として置くので、アバターが動いても、光がついていきます
- 強さは、「基準の強さ × 時間帯の倍率」です。夜は 1、夕方は 0.5、昼は 0 です
- 灯りの数が変わると、全部の素材が作り直されて重くなるので、いつも置いておき、消すときは強さを 0 にします
ところが、見た目が、思うようになりませんでした。
床に、光が届かない
ステージの素材を、コンソールに出して調べました。結果は、MeshStandardMaterial が 3 個、MeshPhysicalMaterial が 12 個でした。光を受ける素材です。ところが、metalness(金属度)が 1 でした。
金属は、光が当たって明るくなる分(拡散光)を持たず、まわりの映り込みでしか見えません。そのため、スポットライトを当てても、床に光だまりが出ません。
そこで、光が床に当たる場所に、ぼかした光の円を重ねることにしました(疑似の光だまり)。光の位置から、照らす点を通る直線が、床と交わる場所を計算して、加算で重ねます。単体の WebGL で、円が描かれることは確認しましたが、実際の床との重なりは、まだ確かめていません。
アバターに、陰影が出ない
もう 1 つの問題は、アバターの陰影でした。左から光を当てると、右側の体が暗くなるはずです。実際は、全体が一様に明るく見えました。
最初は、「空の環境マップが、全方向から当たっているせいだ」と考えて、夜の環境マップの強さを下げました。これは、外れでした。 アバターの素材(MToon)が環境マップの光を受けているか、単体の WebGL で調べたところ、環境マップだけで照らした球は、上でも下でも同じ色でした。MToon は、環境マップの光を受けていませんでした(単体のテストでの結果です。実機のモデルでは、確かめていません)。環境マップを下げて、暗くなったのは、床の金属だけでした。
主な原因は、環境光(ambient)でした。環境光は、金属のステージには効きません。そこで、環境マップは元に戻し、夜の環境光だけを大きく下げました。
それでも、実機の見た目は「全然だめ」でした。暖色の光で、肌がオレンジに寄りすぎたり、暗い側が黒すぎたりします。数字は変えられますが、どう見えたら良いかを決めるのは、見ている人の美的感覚です。ここで、調整パネルを作りました。
調整パネル
コンソールに、1 行ずつ値を打って試す方法は、1 回の試行に、時間がかかります。数字を当てずっぽうに変えるのも、疲れます。そこで、値をスライダーで動かしながら、画面を見て決めるパネルを作りました。
- 右クリックメニューの SYS に、
TUNE_PANELのボタンを足しました。localhost か、URL に?tuneを付けたときだけ表示します。公開の訪問者には、見せません - 時刻: スライダーで 0〜24 時を動かせます。
REALで今の時刻に戻ります - キーフレーム: 時刻を選ぶと、その時刻に切り替わり、明るさ・環境光・空の色などを動かせます。同じ値のキー(夜の 3 つ)は、まとめて動きます
- スポットライト・風・雪: すべての値が、スライダーです。スポットの位置は、x / y / z で動かせます
- COPY: セクションごとに、
weather.jsonに貼れる形で、クリップボードにコピーします。貼って、再読み込みすれば、同じ見た目になります
パネルの値は、記憶しません。再読み込みで、weather.json の値に戻ります。気に入った値は、必ず COPY で残す、という作りです。
ヘッドレスのブラウザで、「開閉」「スライダーで値が変わる」「夜のキー 3 つが連動する」「COPY が、正しい JSON になる」を確認しました。実機では、「動いてる、これは便利」と確認できました。
(画像: 調整パネルを開いた画面)
詰まったこと
- 一定の風は、不自然でした。髪が傾いたまま止まりました。凪ぎと突風を入れました
- 風向きのゆらぎが小さすぎました。±25° では、ずっと同じ向きに見えました
- 「環境マップを下げれば、陰影が出る」は、外れでした。MToon は、環境マップを受けていません。確かめずに、先に直していました
- 床が光を受けない理由は、推測で語る前に、調べるべきでした。調べると、金属でした
- コンソールに貼る例を、まとめて貼られました。1 行ずつ選ぶ前提で書いたのに、
poolEnabled = falseまで一緒に実行されて、床の評価が、無効になりました。例の書き方の問題です - 光の調整は、当てずっぽうでは決まりません。数字を変えるのは簡単でも、見た目の良し悪しは、画面を見て決めるものでした
「ライティングは大事だね」と言って始めましたが、数字ではなく、自分の目で決める作業でした。ノイズの記事を書いていたころと、結局、何も変わっていません。数字を触って、見て、直す。この繰り返しを、早くするものが、調整パネルでした。
未確認のこと・制限
- スポットライトの見た目は、まだ決まっていません。位置・強さ・色・光だまりの値を、調整パネルで決めて、次回に載せます
- 光だまりと、実際の床の重なりは、確かめていません。床の高さが 0 でないときは、高さの値(
poolY)を合わせる必要があります - VR / MR では、霧・雪・時間帯・スポットライトを、出さない作りにしています。VR でどう見せるかは、決めていません
- 処理の重さは、測っていません。雪の 2,500 粒、スポットライト 1 灯(影なし)で、見た目に問題はありませんでしたが、数字では確かめていません
- Chrome(Windows)でだけ、確認しました。スマホは、確認していません
- 風の強さの初期値(髪の揺れの大きさ)は、実機の見た目で決めた値です。モデルによって、合うかどうかは確認していません
- 霧は、調整パネルに、まだ入っていません
おわりに
風は、髪を揺らすだけでなく、霧と雪を、同じ風でつなぐことで、世界に 1 つの空気ができました。髪の動きと、霧の流れが合っているのを見たとき、風が「ある」ように感じました。
いちばん大きな収穫は、実は風でも雪でもなく、調整パネルでした。見た目の良し悪しは、数字ではなく、人の目で決めます。ならば、目で決める作業を、できるだけ早くする道具が要る。Inspector(中身を見る道具)を作り続けてきた理由と、同じだと思いました。
次回は、調整パネルで決めた値で、夜とスポットライトを仕上げます。その次は、霧をパネルに足して、全体の見た目を整えます。
PROTOCOL.LAIN // Archive
lain-lab.com のトップページ。右クリックメニューから、霧・風・雪・昼夜を切り替えられます。
lain-lab.com