はじめに
今回は、[Next.js #31] で作った “触れるノイズ場” の実装を、平面から球体へ拡張しました。
[Next.js #31] Touching Noise Field — Three.js × GLSLで“触れるノイズ場”を作る
Noise 入門の流れを踏まえ、Three.js × GLSL × Raycasterで“Touching Noise Field”を実装。マウスホバー位置を3D空間上に取得し、その周辺だけノイズの歪みと色変化を強めることで、インタラクティブなノイズ表現を作 …
https://humanxai.info/posts/nextjs-31-touching-noise-field-threejs-glsl/前回は PlaneGeometry に対して Raycaster で接触位置を取得し、GLSL 側でノイズ場へ局所的な反応を与える構成でした。 一方今回は、今朝公開した [Noise 入門 #32] の内容を踏まえ、SphereGeometry を使った球体ノイズ地形の上に、クリック位置から広がる波紋エフェクトを追加しています。
[Noise 入門 #32] 球体ノイズとインタラクション — プロシージャルな惑星を「手で回して」探索する
2Dから3D座標のノイズへ次元を拡張。Three.jsとGLSLを用いてシームレスなノイズ惑星を生成し、Raycasterによる3D座標の取得とVertex Shaderによる地形隆起(Displacement)を組み合わせた「触れる世界」の作り方を直感的に解 …
https://humanxai.info/posts/noise-intro-32-interactive-sphere-planet/
位置づけとしては、
- 理論面: [Noise 入門 #32] の球体ノイズと 3D 座標ベースの地形変形
- 実装面: [Next.js #31] の平面インタラクションの発展
- 今回の着地: 球体表面を伝うクリック波紋デモ
という流れです。
なお、実行環境は Next.js プロジェクト内ですが、実装スタイルとしては React コンポーネント主体ではなく、public 配下で動かす ほぼバニラ Three.js + GLSL の構成です。 そのため今回は、Next.js の UI 実装というより、Next.js を足場にした Three.js / GLSL 実験の記録に近い内容になります。
前回のNext.js記事:
[Next.js #32] Three.js MMDアプリにモデルZIP / 壁紙 / IndexedDB管理を実装 — ローカルアセット基盤の整備
Three.jsベースのMMD / WebXRアプリに、モデルZIPの展開、PMX検出、Blob処理、IndexedDB保存、モデル一覧、壁紙サムネ一覧、削除UIを実装した開発記録。ローカルアセットをアプリ内で管理するための基盤整備をまとめる。
https://humanxai.info/posts/nextjs-32-threejs-mmd-indexeddb-local-assets/動画(PC):
今回作ったもの
今回のデモでは、次の要素を組み合わせました。
- SphereGeometry を使った球体メッシュ
- 3D ノイズによる球体地形の変形
- Raycaster によるクリック位置の取得
- 球面法線ベースのクリック波紋
- 時間経過で外側へ広がるリング表現
- 背景用のスカイスフィア
見た目としては、触ると反応するノイズ惑星 のような構成です。 単に球体にノイズを乗せるだけでなく、クリック位置を起点にしたインタラクションを加えることで、静的な地形表現から一歩進めた内容になりました。
前回との違い
[Next.js #31] では、平面メッシュ上で Raycaster の交点を取得し、その位置を shader に渡して局所的な反応を作っていました。
今回はそれをそのまま流用するのではなく、球体表面に合わせて考え方を変えています。
平面では、
- 接触位置 = 平面ローカル座標
- 距離 = distance(pos.xy, mouse.xy)
のように扱えます。
しかし球体では、単純な XY 距離では不自然になります。 そこで今回は、クリックした位置を球体ローカル座標へ変換し、さらに 法線方向として正規化 した上で、各頂点の法線方向との距離を使ってリングを作る形にしました。
つまり、
- 平面版: ローカル平面距離
- 球体版: 球面法線方向ベースの距離
という違いがあります。
この切り替えにより、クリック位置を中心に、球体表面を伝うようなリング表現が可能になります。
実装の流れ
1. 球体メッシュを用意する
ベースは SphereGeometry です。 分割数をある程度細かくしておくことで、頂点変形の変化が見やすくなります。
今回はここに対して、Vertex Shader 側で 3D ノイズを適用し、地形のような凹凸を作っています。
2. 3D ノイズで球体を変形する
球体では UV ベースでノイズを貼るより、法線方向ベースの 3D 座標ノイズ の方が自然です。
各頂点について、
- 球の表面法線を求める
- その方向ベクトルをノイズ座標として使う
- FBM などで高さを計算する
- 法線方向へ押し出す
という流れで、シームレスな球体地形を作れます。
このあたりの考え方自体は、今朝の [Noise 入門 #32] で整理した内容を、そのまま実装へ持ってきた形です。
3. Raycaster でクリック位置を取る
クリック時には Raycaster を使って球体との交点を取得します。
ただし、そのままワールド座標で扱うのではなく、いったん 球体ローカル座標へ変換し、そこから 法線方向として正規化 して保存します。
これによって、球体が回転していても「どの面をクリックしたか」を安定して扱いやすくなります。
4. 時間で広がるリングを作る
クリック波紋の考え方自体はシンプルです。
- クリック時刻を保存する
- 現在時刻との差分を取る
- その経過時間に応じてリング半径を広げる
- 頂点ごとの球面距離との差を使って帯状の影響を作る
こうすると、クリック地点から時間で広がるリング が作れます。
平面版で使っていた hover 反応とは違い、今回は 単発イベント + 時間変化 の構成です。 これにより、触れた瞬間の反応がより明確になり、視覚的にも分かりやすくなりました。
5. リング部分だけ色も持ち上げる
今回は頂点変形だけでなく、Fragment Shader 側でもリング部分を少し明るくしています。
こうしておくと、
- 高さ変化
- 色変化
の両方で波紋が見えるので、視認性が上がります。
特に球体地形側のノイズが強い場合、形状変化だけでは波紋が埋もれやすいので、色の補助はかなり有効でした。
6. 背景にスカイスフィアを追加する
黒背景だけでも成立はしますが、今回は背景として 大きな球体の内側に星空を描くスカイスフィア も追加しました。
実装としては、
- 大きな SphereGeometry
- THREE.BackSide
- fragment shader 側で星点を描く
という形です。
最初は方向ベクトルをそのままセル分割していたため、星が四角いブロックのように見えてしまいました。 そこで、球面 UV ベースのセル分割に変え、セル内のランダム位置に小さな点を置く 方式に修正しました。
これで、背景として違和感の少ない星空になりました。
実装してみて分かったこと
今回の実装で面白かったのは、ノイズがなくても波紋自体は十分きれいに見える ことでした。
つまり今回の見た目の核は、
- 3D ノイズ地形そのもの
ではなく、
- 球面上を伝うリングの設計
にあります。
この確認ができたのは大きくて、今後は
- 球体波紋を主役にする
- ノイズ地形を弱く足す
- ノイズ地形を主役にして波紋を補助にする
といったバランス調整がしやすくなりました。
また、以前見た高水準な水面 shader 実装の影響もあり、 見た目を1つの shader に詰め込むのではなく、反応レイヤーとして分けて考える という発想もかなり参考になりました。
技術スタック
今回の実装で使っている主な要素は次の通りです。
- Next.js(プロジェクト運用基盤)
- Three.js(3D描画)
- GLSL(頂点変形・波紋表現)
- Raycaster(クリック位置取得)
- lil-gui(パラメータ調整)
あらためて書くと、Next.js 製の 3D UI コンポーネントというより、 Next.js プロジェクトの中で運用しているバニラ Three.js 実験コード という立ち位置です。
今後の発展
今回の球体クリック波紋は、まだ単発リングが中心です。 今後広げるなら、たとえば次の方向があります。
- 複数クリック履歴を保持して、複数リングを同時発生させる
- リング通過後に余韻を残す
- 波紋の形にノイズを混ぜる
- 地形の高低に応じてリングの見え方を変える
- 惑星ではなく生物的な球体表現へ寄せる
このあたりを追加していくと、単なるサンプルから、もう少し作品寄りの表現に発展させやすそうです。
まとめ
今回は、[Next.js #31] の平面インタラクション実装を土台にしつつ、[Noise 入門 #32] の球体ノイズの流れを取り込み、球体表面にクリック波紋が広がるデモ を作成しました。
平面から球体へ変わるだけで、
- 接触位置の扱い
- 距離の考え方
- 波紋の見せ方
が変わり、実装としてもかなり面白い差が出ます。
Next.js の記事として見れば少し変則的ですが、中身としてはかなり素直な Three.js / GLSL の実験です。 今後もこの流れで、触れるノイズ表現 を平面から立体へ広げていきたいところです。
💬 コメント