[JavaScript] 3D ROOM制作 2日目(前) 初期設定ウィザードとスカイボックス実装 (Three.js)
はじめに
何となく作り始めた 3D ROOMのWEBアプリ制作、2日目。
昨日は、プロトタイプとしてROOMデータを読み込みVRMアバターを動かすまで作ったので、今日は、初期設定画面制作。
その前に、昨日の段階で基本実装とはいえ、かなり実装コードが増えて1000行を越えていた為、リファクタリングから着手。
前回の記事:
[JavaScript] フォルダ置くだけで動く3D ROOM機能を作る(Three.js) // PROTOCOL.LAIN
Three.js + vanilla JSで、ZIPを解凍してサーバーに置くだけで動く3D ROOM機能を構築。GLB部屋モデル、VRMアバター、BVH衝突判定、3人称カメラ、ポータルリンクまで、バンドラー不要のピュアESM構成で実装した記録
lain-lab.com
リファクタリング
1日目の1000行のapp.jsを4ファイルに分割。
app.js 217行 ← state、init、lights、render loop
room-loader.js 327行 ← GLB/部屋/家具/スカイボックス/ポータル
avatar.js 142行 ← VRM読み込み/アニメーション/更新
controls.js 227行 ← 入力/衝突判定/移動/カメラ/ポータル判定
setup.js 230行 ← 初期設定ウィザード(新規)
共有stateはSTATEオブジェクトとしてapp.jsからexport、各モジュールは関数の引数Sで受け取る。ESMのimport/exportだけで依存管理。バンドラー不要。
初期設定ウィザード
Click to Start画面を4ステップのウィザードに置き換え。
ROOM選択 → アバター選択 → スカイ選択 → 名前入力 → START
ROOM選択はmodels.jsonからサムネイル・クリエイター名・ライセンス・ポリゴン数を読んでグリッド表示。クリックで選択すると、そのモデルのdefaults(scale、pos、spawn)が自動適用される。
アバターは男女2体のデフォルトVRM + カスタムVRMアップロード。アップロードしたVRMはIndexedDB(Dexie)にArrayBufferとして保存。次回起動時にblobURLで復元して読み込む。
設定情報はlocalStorageに保存。2回目以降はウィザードをスキップして直接ルームに入る。
スカイボックス4プリセット
全部Canvas描画のプロシージャルテクスチャ。HDRIは使わない。GPUコストほぼゼロ。
Night:暗い星空 + 月 + ムーングロウ。星は暖色(#fff1ce)で半径0.25以下、低アルファで自然な見た目に。SphereGeometryに貼って低速回転。
Sunset:暖色グラデーション + 雲レイヤー。雲は別のSphereGeometry(半径195)に透明テクスチャで描画。メインの空球体と異なる速度で回転させて奥行き感を出す。
Day:青空 + 白い雲。同じ二重天球方式。
WIRED:黒背景 + 緑グリッドオーバーレイ + 星。lain-labの世界観。回転速度を他より速く。
ノイズは使わない。雲も星も事前にCanvasに描いた静的テクスチャを回転させるだけ。ノイズが活きるのは「毎フレーム変化し続けて同じ模様が二度と出ない」必要がある時だけ。空はゆっくり動いてるように見えればいいので、テクスチャ回転で十分。
export const SKY_PRESETS = {
night: {
name: 'Night',
topColor: '#000008', midColor: '#050515', bottomColor: '#0a0510',
stars: true, moon: true, rotSpeed: 0.003,
bgColor: '#050515',
},
sunset: {
name: 'Sunset',
topColor: '#0a0a3a', midColor: '#cc4400', bottomColor: '#ffaa33',
stars: false, moon: false, rotSpeed: 0.005,
clouds: true, cloudColor: 'rgba(60,20,10,0.3)',
bgColor: '#cc4400',
},
day: {
name: 'Day',
topColor: '#1a6bcc', midColor: '#55aaee', bottomColor: '#aaddff',
stars: false, moon: false, rotSpeed: 0.002,
clouds: true, cloudColor: 'rgba(255,255,255,0.6)',
bgColor: '#55aaee',
},
wired: {
name: 'WIRED',
topColor: '#000000', midColor: '#0a0a1a', bottomColor: '#001100',
stars: true, moon: false, rotSpeed: 0.008,
grid: true,
bgColor: '#0a0a1a',
},
};
Dexie(IndexedDB)
素のIndexedDB APIからDexieに移行。CDN(jsdelivr)からimportmapで読み込み。
import Dexie from 'dexie';
const db = new Dexie('RoomDB');
db.version(1).stores({
assets: '',
});
3関数(openDB, saveToIDB, loadFromIDB)が2行のput/getに簡略化。今後のPhase 3でセーブスロットや家具配置データの保存が増える時もテーブル追加だけで済む。
今後
Phase 3のエディタ機能。右クリックメニューでROOM調整モード(scale/pos/rotスライダーでリアルタイムプレビュー)、家具配置、メディア配置(画像・動画を壁に貼る)。展示空間としての機能を足していく。