[Noise 入門 #23] 極座標 × 4D Noise — GLSLで「プロシージャルな魔法陣」を展開する

はじめに:空間の破壊から、秩序の構築へ

前回は Domain Warping を用いて空間をねじ曲げ、すべてを飲み込む「ブラックホール」を錬成しました。

今回はその対極です。破壊された空間に、数学的な「秩序」を描き出します。

テーマは 「プロシージャルな魔法陣 / ノイズオーラ」。 ゲームやVFXでキャラクターの足元に展開されたり、アイテムを包み込んだりする、あの美しく明滅するエフェクトです。

これをGLSLで実装するための最強の武器が、「極座標(Polar Coordinates)」という概念です。ここに4Dノイズを流し込むことで、ただの無機質な幾何学模様が、呼吸するように脈打つ魔法の陣へと昇華します。

1. 極座標(Polar Coordinates)とは何か? — 空間を「距離」と「角度」で捉え直す

普段、私たちがShaderで画面上のピクセルを扱うとき、基本となるのは横(X軸)と縦(Y軸)で位置を特定する「直交座標系(Cartesian Coordinates)」です。

四角形を描いたり、水平・垂直方向にノイズをスクロールさせたりする場合には、この直交座標が極めて直感的で便利です。しかし、「円を描く」「回転させる」「放射状のエフェクトを作る」といった円環的なアプローチをとろうとした瞬間、直交座標では計算が恐ろしく複雑になってしまいます。

そこで、空間に対する視点を変えます。 「原点からX, Yにどれだけ進んだか」ではなく、「原点からどれくらい離れているか(距離:Radius)」と、「どの方向にあるか(角度:Angle)」の2つの値で位置を定義し直すのです。これが「極座標系(Polar Coordinates)」です。

数式が示す変換のルール

直交座標 $(x, y)$ から極座標 $(r, \theta)$ への変換は、ピタゴラスの定理と三角関数によって以下のように定義されます。

$$r = \sqrt{x^2 + y^2}$$

$$\theta = \arctan\left(\frac{y}{x}\right)$$

一見難しそうに見えますが、GLSLの世界ではこの複雑な計算を、組み込み関数を使ってたった2行で完結させることができます。

// uv座標を中心に移動し、-1.0 〜 1.0 の範囲に正規化する
vec2 st = vUv * 2.0 - 1.0;

// 1. 中心からの距離 (Radius)
float r = length(st);

// 2. 角度 (Angle/Theta)
float theta = atan(st.y, st.x);

GLSLにおける極座標変換のポイント

この2行のコードには、Shaderを書く上で非常に重要なエッセンスが詰まっています。

  • length(st) の意味 length 関数はベクトルの長さを返す関数ですが、内部的には先ほどの平方根の計算 $r = \sqrt{x^2 + y^2}$ をそのまま行っています。これにより、中心(原点)を $0.0$ とし、外側に向かって値が大きくなる同心円状のグラデーションが r に格納されます。
  • atan(y, x) の魔法 数学の $\arctan$(アークタンジェント)ですが、GLSLでは引数を2つ取る atan(y, x) を使用するのが鉄則です。これにより、$x = 0$ のときのゼロ除算エラーを防ぎつつ、中心から見てどの角度にいるかを $-\pi$ から $\pi$ (約 $-3.14$ 〜 $3.14$)の範囲で正確に返してくれます。つまり、theta には時計の針のような放射状のグラデーションが格納されます。

なぜ極座標だと「円」が簡単になるのか?

極座標の最大の利点は、「円の世界を、直線の世界に展開(アンロール)できる」ことです。

極座標に変換した空間では、中心からの距離 r が「Y軸(高さ)」のように振る舞い、角度 theta が「X軸(横幅)」のように振る舞います。 そのため、直交座標では複雑な計算が必要だった「波打つ円(魔法陣のギザギザした縁など)」も、極座標の世界では「角度(theta)に対してサイン波(sin)を足すだけ」で、いとも簡単に描けてしまうのです。

空間を「円」として扱うための準備は整いました。次はこの極座標という新たなキャンバスに、魔法陣の骨格となる「幾何学的な秩序」を描き出していきましょう。

2. 秩序(Order):数式で描く魔法陣の骨格

極座標という新たなキャンバスを手に入れたら、まずはノイズを入れず、極座標の力だけで魔法陣のベースとなる「幾何学(Order)」を描いてみましょう。

発光する美しいリングや、規則的に波打つ放射状の模様は、極座標のパラメータ(距離 $r$ と角度 $\theta$)に対してシンプルな数式を適用するだけで構築できます。

発光(Glow)を生み出す「逆数」の魔法

Shaderでビームやオーラ、ネオンサインのような「発光体」を描く際、最もよく使われる王道のテクニックがあります。それが「距離の逆数」を利用したアプローチです。

// 発光するリング(Glow効果)
float ring = 0.02 / abs(r - 0.5);

このたった1行のコードには、2つの重要な数学的トリックが隠されています。

  1. abs(r - 0.5) によるエッジの定義 $r$ は中心からの距離です。r - 0.5 を計算すると、$r = 0.5$ の位置(円の輪郭)で値が $0$ になります。ここに絶対値 abs() をかぶせることで、「円周上が $0$ となり、内側にも外側にも離れるほど値が大きくなる」というV字型のグラデーション(距離関数)が生まれます。
  2. 0.02 / による無限大への発散 数学において、分母が $0$ に近づくほど、計算結果は無限大へと発散します。つまり、円の輪郭($r = 0.5$)に近づくほど値が急激に跳ね上がり、ピクセルが強烈に白く飛びます。逆に輪郭から離れると値は急速に減衰し、闇へと溶け込みます。

この $f(x) = \frac{k}{x}$ の性質を利用することで、中心が鋭く輝き、周囲にふんわりと光が漏れ出す「完璧なGlow効果」が数式だけで完成するのです。

角度($\theta$)を歪ませて多角形を描く

次に、このただの丸いリングを、魔法陣らしい「放射状の模様」へと変形させます。ここで活躍するのが、極座標のもう一つのパラメータである角度 $\theta$ です。

// 放射状の模様(多角形や星型のベース)
float rays = sin(theta * 6.0 + u_time) * 0.1;
  • theta * 6.0:$\theta$ は $-\pi$ から $\pi$ へと円を一周する値です。これに $6.0$ を掛けてサイン波(sin)に入れることで、「一周する間に6回の波(頂点)」が生まれます。これが六芒星や六角形のベースになります。
  • + u_time:時間を足すことで、波の位相がズレていきます。極座標の世界における位相のズレは、直交座標系で見ると「回転」として表現されます。
  • * 0.1:波の振幅(ギザギザの深さ)を調整します。

幾何学の合成

最後に、ベースとなる距離 $r$ に対して、この波打つ角度の情報 rays を合成します。

// リングに模様を合成
float magicCircle = 0.02 / abs(r - 0.5 + rays);

本来 $0.5$ の位置にあるはずの円の輪郭が、$\theta$ の向きによって $+0.1$ されたり $-0.1$ されたりと、波打つように歪みます。

これだけで、サイバーパンクやファンタジー作品に登場しそうな、規則正しく回転しながら美しく発光する「魔法陣の骨格」が浮かび上がりました。数式によって完全に統制された、美しい幾何学(Order)の姿です。

しかし、これだけでは単調な「機械的なアニメーション」に過ぎません。生物的な脈動や、溢れ出すような魔力の表現には、まだ何かが足りません。

3. 混沌(Chaos):4D Simplex Noise の注入 — 空間をシームレスに歪める

完璧な数式によって構築された「秩序」だけでは、魔法陣は冷たく機械的です。ここに、生命の息吹であり、自然界の揺らぎである「ノイズ(Chaos)」を注入しましょう。

幾何学的な輪郭線(距離 r)に対して、ノイズの値を足し引きすることで、魔法陣から溢れ出し、空間を浸食するような「オーラ」を表現します。ここで使うのは、第15回や第16回でも活躍した 4D Simplex Noise です。

魔法陣のような2Dの平面エフェクトを作るのに、なぜわざわざ「4次元(4D)」のノイズが必要になるのでしょうか?

円の「切れ目」を無くすためのサンプリング技術

もし、直交座標の感覚で単純に snoise(vec2(theta, r)) のように、角度と距離だけで2Dノイズを読み込むとどうなるでしょうか。 角度 theta は $-\pi$ から $\pi$ へと一周しますが、$-\pi$ と $\pi$ の境目(時計の9時の方向)で値が不連続にジャンプするため、ノイズから生成されるオーラに「くっきりとした不自然な切れ目(シーム)」が入ってしまいます。

これを解決し、360度どこから見てもシームレスに繋がるオーラを作るためのエレガントなハックが、以下のコードです。

// 極座標をベースにノイズをサンプリング
// 角度(theta)と時間(u_time)を使って、円周上で繋がるノイズを作る
vec4 noisePos = vec4(cos(theta) * 2.0, sin(theta) * 2.0, r * 3.0, u_time * 0.5);
float noiseVal = snoise(noisePos);

// ノイズを使ってリングの輪郭を歪ませる
float aura = 0.03 / abs(r - 0.5 + noiseVal * 0.2);

4つの次元(X, Y, Z, W)の役割分担

この noisePos という4次元ベクトルには、それぞれ明確な役割が与えられています。

  • 第1・第2の次元(X, Y):cos(theta), sin(theta) ノイズのサンプリング空間(Noise Space)の中で、$\theta$ を再び「円軌道」に変換して読み込みます。こうすることで、始点と終点が物理的に同じ座標でピッタリと一致し、絶対に切れ目のないループノイズが手に入ります。
  • 第3の次元(Z):r 中心から外側へ向かう距離です。これを次元に加えることで、中心から放射状に広がるにつれてノイズの形が変化していく、奥行きのある揺らぎが生まれます。
  • 第4の次元(W):u_time 時間の流れです。もし時間に沿って2Dの空間をスクロールさせてしまうと「風に流される」ようなエフェクトになってしまいますが、4次元目(W軸)に向かってノイズを進ませることで、位置は動かずにその場でウネウネと「呼吸するように脈打つ」表現になります。

最後に、この生命力あふれるノイズ値 noiseVal を、先ほど学んだ距離関数の輪郭線に足し合わせます。 abs(r - 0.5 + noiseVal * 0.2) とすることで、完璧な真円だったはずの輪郭が予測不能に歪み、エネルギーが溢れ出すような魔力へと昇華されるのです。

4. 融合:プロシージャルな魔法陣の完成 — 秩序と混沌の交差点

いよいよ、すべてのピースを繋ぎ合わせます。

ベースとなる幾何学的な魔法陣(Order)を中心核として配置し、その外周を包み込むように揺らぐノイズオーラ(Chaos)を展開します。そして最後に、純粋なエネルギーの塊である「光」として画面に定着させましょう。

これが、極座標と4Dノイズが織りなす魔法陣の全貌です。

void main() {
    // 1. 極座標変換キャンバスの準備
    vec2 st = vUv * 2.0 - 1.0;
    float r = length(st);
    float theta = atan(st.y, st.x);

    // 2. 4Dノイズの生成(シームレスな円環)
    float n = snoise(vec4(cos(theta) * 3.0, sin(theta) * 3.0, r * 2.0, u_time * 0.5));

    // 3. 秩序(Order):内側のシャープな多角形リング
    // 半径0.4の位置に、鋭く発光する8角形の星を展開
    float order = 0.01 / abs(r - 0.4 + sin(theta * 8.0) * 0.05);

    // 4. 混沌(Chaos):外側に広がるノイズオーラ
    // 半径0.6の位置に、ノイズで激しく歪む柔らかなオーラを展開
    float chaos = 0.03 / abs(r - 0.6 + n * 0.3);

    // 5. 合成(Additive Blending)して色をつける
    float intensity = order + chaos;
    vec3 color = vec3(0.2, 0.6, 1.0) * intensity; // 神々しいシアンブルー

    gl_FragColor = vec4(color, 1.0);
}

コードに込められた「光と配置」の設計意図

この短いコードの中には、エフェクトを美しく見せるための細かいパラメータ調整(アートディレクション)が施されています。

  • 半径の対比(r - 0.4 vs r - 0.6) 幾何学的な星(Order)を 0.4 と内側に置き、それを護るようにノイズオーラ(Chaos)を 0.6 と外側に配置しています。これにより、エフェクトに立体的な階層構造が生まれます。
  • 光の鋭さの対比(0.01 / vs 0.03 /) 発光の強さを決める分子の値に注目してください。内側の Order は 0.01 と小さくすることで、レーザーのように「鋭く細い線」にしています。一方、外側の Chaos は 0.03 と大きく設定することで、大気中にエネルギーが漏れ出ているような「太く柔らかな光(ブルーム)」を表現しています。
  • 光の加算合成(order + chaos) 光の世界(物理ベースの描画)では、エネルギーは足し算で表現されます。intensity として2つの値を足し合わせることで、線が交差する部分は値が劇的に跳ね上がり、白飛びするほど強烈に発光する「コア」が生まれます。

数式が描く「魔法」の顕現

計算された intensity に対して、ベースカラーとなる青色 vec3(0.2, 0.6, 1.0) を掛け合わせます。中心のコア部分は強烈な白に輝き、外側に向かって美しいシアンブルーのグラデーションを描きながら闇へと溶け込んでいきます。

画面に浮かび上がるのは、数学の絶対的なルール(極座標)に従いながらも、ノイズによって絶えず形を変え、燃え上がるように明滅する魔法陣です。

数式で完璧に統制された「幾何学(Order)」と、ノイズがもたらす予測不能な「揺らぎ(Chaos)」。 この相反する二つの要素が Shader の中で完璧に交差したとき、真の「魔法」が画面上に顕現します。

結び:極座標という新たなキャンバス — 円環に宿る無限の可能性

直交座標(XY)という平坦なグリッドの世界から、極座標(距離と角度)という新たな視点へ踏み出すだけで、ノイズの表現幅は「円環状」へと劇的に広がりました。

今回実装した魔法陣は、この極座標キャンバスに描ける魔法のほんの序章に過ぎません。 距離関数と角度、そして時間経過で変化する4Dノイズの組み合わせは、あらゆる「放射状のエフェクト」の基礎となります。

  • 爆発の衝撃波(Shockwave): 距離 r に対して時間経過で広がるリングを描き、ノイズで輪郭を歪ませることで、空気を切り裂くような衝撃を表現できます。
  • 瞳の虹彩(Iris): 角度 theta の方向に細かな高周波ノイズを引き伸ばすことで、生々しく複雑な眼球のテクスチャを数式だけで生成できます。
  • ワープエフェクト: 極座標の距離を時間の逆数と絡めることで、光速でトンネルを抜けるようなダイナミックな空間移動表現が可能になります。

数式による完璧な統制(Order)と、ノイズによる予測不能な揺らぎ(Chaos)。 この相反する二つをGLSLという言語を通して自在に操れるようになった今、あなたはもう、画面上にどんな魔法でも描き出すことができるはずです。

次回予告:画面全体を侵食する「ポストプロセス」の世界へ

これまでは、空間内の「一部のオブジェクト」や「平面(Plane)」に対してノイズを適用し、エフェクトや地形を作り出してきました。

しかし次回(#24)は、この「ノイズのエフェクト」をさらに発展させ、ついに ポストプロセス(Post-Processing / 画面全体への適用) の領域へと足を踏み入れます。

レンダリングされた美しい世界そのものをノイズで歪ませ、水中の揺らぎ、灼熱の陽炎(Heat Haze)、あるいは次元が崩壊するようなグリッチエフェクトを作り出す手法を解説します。

空間を歪め、光を描き出した次は、ついに「世界(カメラ)そのもの」をハックします。次回も、数式が描くめくるめく世界でお待ちしています。お楽しみに!