[Next.js #39] Procedural Lightning on Storm Planet — 球体惑星に雷を落とし、濃い雲でランダム発火させる

はじめに

前回の [Next.js #38] では、球体惑星の雲レイヤーに Interactive Storm を実装し、マウス位置を基準に台風の目や渦巻く雲の流れを作れるようにしました。

しかし、嵐として考えるとまだ足りない要素があります。

雷(Lightning)です。

今回は、今朝の Noise 入門 #36 で実装した Procedural Lightning をベースに、Three.js / GLSL の球体惑星デモへ移植します。

さらにそのまま移植するだけではなく、

  • マウス操作で生まれる台風の雷
  • 雲の濃い場所で自然発生する雷

この 2種類の雷を共存させるように少しアレンジしました。

これにより、ユーザー操作による嵐と、自然現象としての雷鳴が同時に存在する「生きた惑星」に近づきます。

動画(YouTube):

動画(PC):

1. Interactive Storm に Lightning を追加する

前回の Storm は、主に次の要素で構成されていました。

  • 球体惑星
  • ノイズによる雲レイヤー
  • マウス位置による台風の渦

今回追加するのは次の要素です。

Lightning System

  • 稲妻の形状生成
  • 時間によるストロボ発火
  • 雲の内部発光
  • 地表へのフラッシュ

つまり今回の目的は、

Storm + Lightning

嵐を 視覚的に完成させることです。

2. ノイズから稲妻の形状を作る

雷は単なる「光の点滅」ではありません。

実際には、雲の中で細い電気の経路が形成されます。

そこで、まず ノイズから稲妻の形状(Shape) を作ります。

vec3 lightPos = vWorldPosition * 5.0;

float nLight = fbm4d(vec4(lightPos, uTime * 0.1));

float ridge = 1.0 - abs(nLight);

float lightningShape =
    smoothstep(uLightningThreshold, 1.0, ridge);

ポイントはここです。

1.0 - abs(noise)

これは Ridgeノイズと呼ばれる形状で、 山の尾根のような鋭い線が残ります。

さらに smoothstep で閾値処理を行うと、

ノイズ空間
鋭い線だけ抽出
稲妻の形状

という構造になります。

3. 時間ノイズでフラッシュを作る

雷は常に光っているわけではありません。

一瞬だけ バチッと光るストロボです。

そこで、時間ノイズを使ってフラッシュを制御します。

float mouseFlashNoise =
    snoise(vec4(uTime * uLightningSpeed,0,0,0));

float mouseFlash =
    step(0.8, mouseFlashNoise);

ここで step() を使うのが重要です。

smoothstep → 滑らかな変化
step → 突然のON/OFF

雷のような 瞬間的な現象には step() の方が自然に見えます。

4. 台風の雷と自然発生の雷

今回少しアレンジした部分がここです。

雷を

1. 台風中心で発生する雷
2. 雲の濃い場所でランダム発生する雷

の2種類に分けました。

まずはランダム雷です。

float globalFlashNoise =
    snoise(vec4(uTime * 0.5, 10.0, 0.0, 0.0));

float globalFlash =
    step(1.0, globalFlashNoise);

ただしこれだけだと、雲のない場所でも光ってしまいます。

そこで 雲の密度条件を追加します。

float densityCondition =
    smoothstep(0.6, 0.9, shading);

そして最終的なフラッシュは次のように合成します。

float totalFlash =
    mouseFlash * w
  + globalFlash * densityCondition;

つまり

マウス操作 → 台風の雷
雲の濃い場所 → 自然発生雷

という構造になります。

5. 雲の内部発光

雷は雲の内部を光らせます。

そのため、雷の光を 雲の色に加算します。

vec3 lightningGlow =
    uLightningColor
  * lightningShape
  * totalFlash
  * uLightningIntensity;

color += lightningGlow;

これはいわゆる Additive Lighting(加算発光)です。

雲の内部から光っているように見えるため、 嵐のスケール感が大きく変わります。

6. 地表フラッシュ

さらに、雷の光を地表にも少し反映させます。

vec3 groundFlash =
    uLightningColor
  * totalFlash
  * (uLightningIntensity * 0.25);

groundColor += groundFlash;

これにより

雲 → 雷
地面 → フラッシュ

という視覚的な連動が生まれます。


まとめ

今回は、前回作った Interactive Storm に Procedural Lightning を追加しました。

実装としては次の構造です。

  • ノイズから雷の形状を作る
  • 時間ノイズでストロボ発火
  • 台風雷と自然雷を共存
  • 雲内部の発光
  • 地表フラッシュ

Storm が「雲の渦」だとすると、 Lightning はそこに エネルギーを与える存在です。

これによって、球体惑星の嵐が より生きた自然現象に近づきました。

次回は、この惑星に 夜景(Night Lights) を追加し、 文明の灯りが見える惑星へ進化させていきます。