ライブで試す このプロジェクトについて
6枚のパネルは、Scene内に存在する本物のWebGLジオメトリです。厚みと曲率を持ち、キャラクターを遮ることも、キャラクターに遮られることもあり、どの角度から見ても深度順が正しく保たれます。canvasの上に浮かべたDOMカードではありません。
インタラクション全体は、1つの役割分担で成り立っています。発見は3D、操作は2Dです。パネルはキャラクターの周囲を漂い、ジェスチャーに合わせて回転しながら、閲覧と選択を担います。実際の再生操作は、画面下部に固定された安定したスクリーン空間のインターフェースが担当します。曲の選択は単なる状態切り替えではなく、連続した受け渡しです。パネル自体が下へ飛んでプレイヤーになり、別のトラックを選ぶと、古いパネルが元の3D位置へ飛んで戻ります。
体験ポイント
- 何もない空間をドラッグすると、ミュージックカードがキャラクターの周囲を回り、離した後も慣性で動き続けます。キャラクターをドラッグした場合は、そのキャラクターだけが回転し、カメラとパネルは動きません。両者はゆっくりと反対方向へ漂います。この対向する動きによって、まとまり全体が背景ではなく、軌道を回る1つの天体として感じられます。
- パネルをクリックすると3D空間から抜け出し、キャラクターの横をかすめて移動しながら、画面下部の横長プレイヤーへ展開します。別のパネルを選ぶと、2枚が同時に飛行します——新しいパネルが手前へ進む間に、古いパネルは折りたたまれ、元の位置へ正確に戻ります。
- ホイール操作で、カメラを4.6〜16ワールド単位の範囲でドリー移動できます。押し込むと手前のパネルがフレームからあふれ、引くと空間全体が集まり、上から眺める1つの音楽の星座になります。
- カスタムカーソルの四隅のフレームは、各パネルを実際に投影したクアッドへ固定されます。ブラケットは遠近法に沿った本来の四隅に重なり、パネルの傾きに合わせて回転します。
技術解説
3Dアセット · 手を加えていないTripoエクスポート
Artist.glbは、Tripoからエクスポートされた状態のまま配信します。59 MB、1.02M頂点、8192²のベースカラーマップ——デシメーションもリサイズも行わず、制作時のディテールをすべて保持しています。そのコスト(mipmap生成後は~350 MB VRAM、各フレームで100万頂点を再描画)はあらかじめ織り込み、2つの判断で扱いやすくしています。高負荷なメッシュではraycastingを無効にし——ポインターが動くたびに100万三角形を判定するとメインスレッドが停止するため——モデル自身の境界から大きさを決めた不可視のカプセルを代わりに使います。また、エクスポートにアニメーションクリップがないため、架空のスケルトンを追加せず、グループ単位のアイドル動作(ゆっくりした揺れと1ミリメートルほどの呼吸)を与えています。
scripts/のmeshoptパイプラインに同じファイルを通すと2.9 MBになります。ロード時にモデルを計測して正規化するため、ビルドを差し替えてもコードの変更は不要です。
マテリアル · Tripoエクスポートのボリュームマテリアルをダウングレード
TripoのエクスポートはメッシュにKHR_materials_volumeを付与します。three.jsでは、これはtransmission/thicknessパスを持つMeshPhysicalMaterialとして読み込まれますが、このSceneには不要で、処理コストも許容できません。ロード時にすべてのマテリアルをMeshStandardMaterialへダウングレードし、PBRマップ一式はそのまま保持します。見た目は同じまま、コストだけを取り除きます。
カスタムShaderMaterialsにはcolorspace_fragmentを明示的に含めています。これがないと線形値がsRGBフレームバッファへ直接書き込まれ、ほぼ黒くレンダリングされます。
ミュージックパネル · 曲面上の実ジオメトリ
各パネルは4種類のジオメトリ——表面、実際の厚みを作るようにスイープしたリムストリップ、半透明の背面プレート、不可視のヒット判定用クアッド——で構成されます。すべてがキャッシュ済みの1つのバッファセットを共有し、カードごとに異なるのはグループ変換だけです。全要素を平面として制作し、大きな垂直円柱に巻き付けています。進捗の溝と時計は親子付けせず同じ曲面へ焼き込み、進捗の塗りはMeshBasicMaterialへ注入したUVカットオフで表現します。メッシュ自体をスケーリングすると、遠端が曲面から浮いてしまうためです。
パネルのアートワークは更新頻度に応じて3つのcanvasへ分割しています。1320×680の表面は1度だけ描画し、時刻ストリップは表示する秒が変わったとき、アイコンは再生状態が切り替わったときだけ再描画します。レンダーループ内で高負荷な処理は行いません。6枚の透明パネルはすべてdepth writeを無効にし、各フレームでカメラからの距離に応じた段階的なrenderOrderを割り当てるため、どの角度から見てもオクルージョンが正しく保たれます。
3Dから2Dへのリレー · カードがプレイヤーとして着地する
WebGLメッシュをDOMノードに変えることはできません。そこで連続性を、3つの仕組みで成立させています。プロジェクターが各フレームで全カードのスクリーン空間上のボックスを最新に保つこと——復路にも着地点が必要なため、非表示のカードも対象です。DOMパネルの最初のフレームには、カードのWebGLテクスチャ用にすでに描画済みのcanvasビットマップそのものを使うこと——完全には位置が合わないHTMLの再現ではありません。そして同じフレームでカードを非表示にすること——同じ場所に2つがあり、片方だけが見えない状態です。
横方向への展開は、飛行が~35%進むまで保留します。飛行の途中で2:1のカードを11:1のバーへ引き伸ばすと、アートワークが崩れてしまうためです。軌道には横へ膨らむ2次ベジェ曲線を使い、左上からドッキングするカードがアーティストを回り込むように移動します。到着先は各フレームで再取得します。星座状の配置は動き続けているため、出発時に取得したrectを使うと、パネルが元のカードの横に着地してしまいます。


