[Next.js #38] Interactive Storm on Sphere Planet — マウスで台風を錬成する Three.js / GLSL 実装

はじめに

今回は、以前作成した球体惑星のプロシージャル雲表現をさらに発展させ、マウス操作で局所的な台風を発生させる Interactive Storm を実装しました。

シリーズ番号としては Next.js #38 ですが、内容としては

Next.js #36 Procedural Clouds on Sphere Planet

の直系の続きになります。

また、今回の実装アイデアは今朝まとめた以下の記事をベースにしています。

Noise 入門

今回作ったもの

今回の実装では、球体惑星の雲に対して マウス操作で嵐を発生させるインタラクション を追加しました。

主な要素は次の通りです。

  • FBMノイズによる雲
  • Curl Noiseによる乱流
  • 球面接線ベクトルによる回転流
  • 台風の目
  • 嵐リング
  • 地表影の同期

マウス位置を中心として大気をかき混ぜることで、巨大な台風が生成される表現になります。

[Next.js #38] Interactive Storm on Sphere Planet — マウスで台風を錬成する Three.js / GLSL 実装

動画(YouTube):

動画(PC):

実装の全体構成

今回のシーンは大きく分けて 3つのレイヤーで構成されています。

  • planetMesh
  • cloudMesh
  • atmosphere

特に重要なのは cloudMesh と planetMesh の同期です。

雲だけを歪ませると、嵐の下にある地表が動かないため不自然になります。

そのため

  • cloud warp
  • terrain warp

を同じ storm mask で処理しています。

Raycasterで球体表面の座標を取得する

嵐の中心はマウス位置から計算します。

Three.js の Raycaster を使用して、球体との交点を取得します。

raycaster.setFromCamera(mouse, camera);
const hit = raycaster.intersectObject(cloudMesh);

if (hit.length > 0) {
  uniforms.uStormCenter.value.copy(hit[0].point);
}

ここで得られるのは ワールド座標です。

この座標を shader に渡すことで、

  • 地表

の両方で同じ storm center を共有できます。

Curl Noiseで乱流を作る

嵐の基本的な揺らぎは Curl Noise で作ります。

vec3 curl = curlNoise(vWorldPosition * 2.0 + uTime * 0.5);

Curl Noise を使うと、次の特徴が得られます。

  • divergence-free
  • 流体っぽい動き
  • 自然な渦

通常のノイズで押すだけより、はるかに大気っぽい動きになります。

球面接線ベクトルで回転流を作る

台風の回転は、球面上の接線ベクトルを使って作ります。

まず中心方向を求めます。

vec3 centerDir = normalize(uStormCenter);
vec3 localDir = normalize(vWorldPosition);

次に中心からの放射方向を求めます。

vec3 radial = normalize(localDir - centerDir * dot(localDir, centerDir));

そして接線方向を作ります。

vec3 swirl = normalize(cross(centerDir, radial));

これが 台風の回転ベクトルになります。


台風の目を作る

嵐の中心は雲が薄くなるため、eye mask を作ります。

float eyeMask = smoothstep(
  stormEyeRadius,
  stormEyeRadius + stormEyeSoftness,
  dist
);

この値を雲密度に掛けることで、

  • 中央は雲が薄い
  • 外周は厚い

という台風構造になります。


嵐リングを作る

台風の最も強い雲は、中心ではなく外周にあります。

そこで リングマスク を作ります。

float ringMask = smoothstep(
  stormRadius * 0.6,
  stormRadius,
  dist
);

このリング部分で

curl noise
swirl
warp

を強く適用します。

これにより 台風の雲壁が形成されます。


雲Warpの合成

最終的な warp は次のようになります。

vec3 warpVec =
    curl * curlStrength +
    swirl * swirlStrength;

warpVec *= ringMask * stormStrength;

この warp を

cloud noise
terrain shadow

両方に適用します。


地表影も同期させる

雲だけを歪ませると不自然になるため、地表の影にも同じ warp を適用します。

shadowUV += warpVec.xz * 0.02;

これにより

  • 地表

が同じ嵐構造になります。

パラメータ調整

今回の嵐は GUI で調整できるようにしています。

主なパラメータは次の通りです。

Storm Radius
Storm Strength
Eye Radius
Eye Softness
Swirl Strength
Ring Boost

特に重要なのは

Swirl Strength
Eye Radius

です。

ここを調整すると

  • 台風
  • ハリケーン
  • 巨大嵐

など雰囲気が大きく変わります。

実装して分かったこと

今回の実装で重要だったのは次の3点です。

1. 雲だけ動かすと不自然

地表影を同期させることで説得力が大きく上がりました。

2. swirl が台風の印象を作る

Curl Noise だけでは嵐っぽくなりません。

回転ベクトルが入ることで一気に台風になります。

3. eye を作ると完成度が上がる

中心を抜くだけで

  • 台風

の違いがはっきり出ます。

今後の拡張

今回の Interactive Storm はまだ基礎段階です。

次のような拡張が考えられます。

  • 雷フラッシュ
  • 雲発光
  • 複数台風
  • 風向き場
  • 大気循環
  • 気圧帯

これらを追加すると、さらに 生きた惑星に近づきます。

まとめ

今回の実装で、球体惑星の雲表現は

流れる背景
干渉できる気象システム

へ進化しました。

Raycaster、FBM、Curl Noise、Domain Warping を組み合わせることで、マウス操作で台風を生成するインタラクティブな惑星表現が実現できます。

理論部分は以下の記事で解説しています。

Noise 入門

Next.js 実装記事と合わせて読むと、全体の流れが見やすくなると思います。