はじめに
今回は、制作中の Three.js + MMD ベースのWeb時計アプリ に、設定UIをまとめて実装しました。
公開上の連番としては #35 ですが、内容としては以下の記事の続編にあたります。
- [Three.js #32] MMD + IndexedDB ローカルアセット管理
- IndexedDB に保存したローカルアセットを、実際のアプリ運用へどう繋げるか
- 時計アプリとして、どこまで設定可能にするか
前回 #32 では、主に ローカルアセット保存の土台 を整えました。 今回はその次の段階として、ユーザーが画面上から設定を変更し、その状態を保存・復元できる構成 をまとめて実装しました。
単なる値変更ではなく、
- 設定UI
- 保存
- 復元
- 即時反映
- IndexedDB アセット管理
まで、一通り繋いだのが今回のポイントです。
動画(Youtube):
Three.js × MMD Settings UI|localStorage保存・壁紙・床Shader対応
Three.js + MMD ベースのWeb時計アプリに Settings UI を実装。壁紙、時計色、床Shader、MotionAssets の設定を GUI から変更し、localStorage / IndexedDB で保存・復元できるようにしました。▼ブログ記事https://humanxai.info...
https://www.youtube.com/shorts/jTUr1--zD88動画(PC):
今回やったこと
今回実装した内容を整理すると、主に次の5系統です。
- 設定UIの追加
- 時計設定の保存・復元
- 壁紙設定の保存・復元
- 床マテリアル / 床シェーダー設定の保存・復元
- MotionAssets(VMD / VPD)の一覧管理UI
途中でかなり広がりましたが、最終的には「時計アプリ全体の見た目と動作設定を、GUI経由で調整して保存できる」状態まで持っていけました。
Settings パネルを導入
まず一番大きかったのは、アプリ全体に対する Settings パネル の導入です。
これまでは、
- コードを直接書き換える
- 一時的な Inspector 的UIで値を試す
- 値を触ってもリロードすると消える
という状態が多かったのですが、今回の実装で、
- アナログ時計
- デジタル時計
- 壁紙
- 床
- Motion
を1つの設定パネルに集約できるようになりました。
UI構造としては、既存の Model / Info / Rig / Debug / Wallpaper パネルと同じ流儀に揃えています。
- index.html に
<template> - style.css に見た目
- ui.js にイベント配線
- settings-store.js に保存構造
- settings-apply.js に反映処理
という役割分担にしたことで、後から設定項目を足すのもかなり楽になりました。
localStorage で設定を保存・復元
今回の中核になったのは、設定保存の土台です。
settings-store.js を用意し、アプリ全体の設定をまとめて持つ構造を定義しました。
管理対象は、概ね次のような構成です。
- analogClock
- digitalClock
- motion
- wallpaper
- floor
これにより、起動時に
- localStorage から設定をロード
- settings-apply.js で runtime に反映
- UI側にも初期値として流し込む
という流れを作れました。
ここができたことで、単発の調整ではなく、状態として残るUI になりました。
アナログ時計の設定
アナログ時計側では、次の項目を設定できるようにしました。
- 色
- 透明度
- Margin
- Scale
特に大きかったのは、透明度を設定できるようになったこと です。
壁紙を背面に入れた場合、アナログ時計が不透明すぎると前面に出すぎてしまいます。 そこで material の transparent / opacity を設定UIから変更できるようにし、背景とのバランスを取れるようにしました。
これによって、単に色を変えるだけではなく、画面全体のレイヤー感まで調整できる ようになりました。
デジタル時計の設定
デジタル時計側では、次のような項目を保存・復元できるようにしました。
- 日付色
- 時刻色
- 補助文字色
- UI Alpha
- Glow
- Margin
- Scale
デジタル時計は画面左側の情報量をかなり持っているので、色や透明度の調整ができるだけでも見え方が大きく変わります。
壁紙を明るめにした時、文字が埋もれないようにするためにも、このあたりの設定をUIから触れるようにしたのは大きかったです。
壁紙設定の保存・復元
時計アプリとして見たときに、やはり壁紙の存在感はかなり大きいです。
今回、壁紙まわりも設定保存の対象に含めました。
保存対象
- 壁紙の tint color
- texture の有効 / 無効
- 選択中のプリセット壁紙
- custom wallpaper の参照ID
ここでポイントだったのは、壁紙画像そのものを localStorage に保存しない ことです。
役割は次のように分離しています。
- 画像ファイル本体 → IndexedDB
- どの壁紙を使うか、色味はどうか → localStorage
この構造にしておくと、
- 画像データは IndexedDB に安全に保持
- 現在の選択状態だけは軽量に保存
という形になり、リロード後も
- どの壁紙を選んでいたか
- tint がどうだったか
- texture が有効だったか
を復元できます。
壁紙の扱いは思ったより構造が複雑でしたが、ここを整理できたのはかなり大きかったです。
床色の分離と保存対応
途中で気づいたのが、アナログ時計の色と床色が連動してしまう 問題でした。
原因は、床側面が時計色と同じ参照を使っていたことです。 これを修正して、まず 床側面色を独立 させました。
その上で、床の設定項目として次を保存対象に追加しました。
- 側面色
- レンガ密度
- 目地の太さ
- ムラの強さ
つまり、シェーダー側の
- uScale
- uMortar
- uAmp
まで、設定UIから変更・保存・復元できるようにしています。
これで床は単なる固定背景ではなく、時計アプリの一部としてちゃんと調整可能な要素になりました。
床上面シェーダーの色も uniform 化
床上面は ShaderMaterial でレンガ風に描画しているのですが、最初は色が shader 内の固定値でした。
そこで最後に、固定色だったレンガ色と目地色を
- uBrickColor
- uMortarColor
として uniform 化し、設定UIから変更できるようにしました。
これにより床上面についても、
- レンガ色
- 目地色
- レンガ密度
- 目地太さ
- ムラ
まで制御可能になりました。
結果として、床に関しては
- 側面
- 上面
- シェーダーパラメータ
を一通り調整できるようになり、見える範囲の床表現はかなり自由度が高くなりました。
MotionAssets の一覧管理UI
今回の後半で大きかったのが、VMD / VPD の扱いです。
以前の記事でも触れた通り、ローカルアセットは IndexedDB に保存できる状態でした。 今回はそこから一歩進めて、Settings 内で MotionAssets を一覧管理できるUI を追加しました。
現在できること
- IndexedDB 上の VMD 一覧表示
- IndexedDB 上の VPD 一覧表示
- Default 選択
- Enabled 切り替え
- Delete
ここで重要だったのは、手入力でパスを追加するUIをやめて、保存済みアセットを管理する方向へ寄せたこと です。
つまり Motion セクションは、
- 「追加フォーム」 ではなく
- 「アセット管理リスト」
として整理しました。
この方が、実際のデータ構造とアプリの使い方に合っています。
model.json の motion 構造も整理
VMD / VPD の一覧管理に合わせて、model.json 側の構造も整理しました。
最終的には、概ね次のような形になっています。
"motion": {
"defaultVmd": "walk",
"defaultPvd": "talkFront",
"vmdList": [
{ "id": "walk", "name": "walk", "filePath": "/motions/walk.vmd", "enabled": true }
],
"pvdList": [
{ "id": "talkFront", "name": "talkFront", "filePath": "/poses/talk_front.pvd", "enabled": true },
{ "id": "sleep", "name": "sleep", "filePath": "/poses/sleep.pvd", "enabled": true },
{ "id": "smile", "name": "smile", "filePath": "/poses/smile.pvd", "enabled": true },
{ "id": "sit", "name": "sit", "filePath": "/poses/sit.pvd", "enabled": true }
]
}
特に大きかったのは、defaultVmd / defaultPvd を ファイル名ではなく id 参照に揃えたこと です。
これにより、
- UI選択
- messages[].pose
- モーション一覧
- 将来のファイル名変更
の整合が取りやすくなりました。
単なる設定ファイルではなく、モデル動作設定ファイルとして筋の通った形 に近づいたと思います。
今回しんどかったところ
今回一番重かったのは、単に設定項目が多かったことではありません。
しんどかったのはむしろ、
- state をどこに置くか
- どこで保存するか
- どこで runtime に反映するか
- 何を IndexedDB に持たせるか
- 何を localStorage に持たせるか
という、構造整理の部分でした。
実際に触ったファイルもかなり多くなりました。
- ui.js
- index.html
- style.css
- settings-store.js
- settings-apply.js
- backwall.js
- mmd-floor.js
- motionAsset.js
- model.json
1ファイルだけの修正で終わる内容ではなく、複数の層を横断して見直す必要があったので、想像以上に重い作業でした。
ただ、そのぶん一度土台ができると、今後は新しい設定項目を追加するコストがかなり下がります。
ここまで来ると、初期版としてかなり完成度が高い
今回の実装によって、少なくとも見える範囲の主要要素はかなり調整できるようになりました。
- アナログ時計
- デジタル時計
- 壁紙
- 床側面
- 床表面
- Motion default / enable / delete
さらに、保存・復元まで通っています。
ここまで来ると、単なる試作ではなく、使えるWeb時計アプリの初期版 という感覚があります。
個人的には、この段階で ver.1.0.0 として公開してもよいレベルだと思っています。
もちろん、今後やりたいことはまだあります。
- テーマ機能
- 設定 export / import
- model.json の Web 編集
- MotionAssets 追加UIの改善
ただ、それらは次の段階の話で、今回の時点で一つ大きな区切りがつきました。
まとめ
今回は、Three.js + MMD ベースの時計アプリに対して、設定UIと保存・復元基盤をまとめて実装しました。
今回できるようになったこと
- 時計設定のGUI操作
- 壁紙設定の保存・復元
- 床マテリアル / 床シェーダー設定の保存・復元
- VMD / VPD の一覧管理
- Motion default 設定
- localStorage + IndexedDB を使った状態管理
前回 #32 で作った IndexedDB ベースの土台が、今回ようやく 実際のアプリの使い勝手 としてつながってきた感じです。
次はこの設定基盤を前提に、
- テーマ機能
- model.json のWeb編集
- 設定の export / import
のような方向へ広げても面白そうです。
まずはこの時計アプリを、ひとつの区切りとして 初期版公開 まで持っていきたいと思います。
💬 コメント