見出し画像

🎡GLSLで海表現に一矢むくいたい


めちゃめちゃすごすぎるすげー。これで197行

もう海じゃん。どうなってんだGLSL

まずはエントリポイントのmainから

このコードはGLSL(OpenGL Shading Language)で書かれたフラグメントシェーダーで、Alexander Alekseev aka TDMによる「Seascape」(2014年)という作品です。Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported Licenseの下でライセンスされています。このシェーダーは、動的に生成される海景色をリアルタイムでレンダリングするために設計されています。

シェーダーの概要と主な機能は以下の通りです:

  • 初期設定: #ifdef GL_ES は、OpenGL ES(Embedded Systemsの略)環境で低精度の浮動小数点数を使うための設定です。これにより、モバイルデバイスなどのパフォーマンスが限られた環境でも効率的に動作します。

  • Uniform変数: time, mouse, resolution はシェーダーに外部から渡される変数で、それぞれ現在の時間、マウスの位置、画面の解像度を表します。

  • 定数と変数の定義: 海のレンダリングに必要なパラメータ(例えば、海の高さ、波の形状、速度、色など)が定義されています。

  • 数学関数: fromEuler, hash, noise など、3D空間内で物体を操作したり、ノイズを生成するための数学関数が定義されています。

  • ライティング: diffuse, specular 関数は、物体の表面における光の拡散反射と鏡面反射を計算します。

  • 海と空の色: getSkyColor, getSeaColor 関数は、与えられたパラメータに基づいて空と海の色を計算します。

  • 海の表面の計算: sea_octave, map, map_detailed 関数は、海の表面の形状と詳細を計算するために使用されます。

  • ノーマルマップとトレース: getNormal, heightMapTracing 関数は、海の表面の法線を計算し、視線追跡を行って物体の形状を決定します。

  • メイン関数: main 関数はシェーダーのエントリーポイントで、すべての計算を統合し、最終的な色をフラグメントの色として出力します。

このシェーダーは、海の動き、波の形状、光の反射と屈折、空の色の変化など、自然な海景色のリアルタイムレンダリングを実現するために複雑な数学とアルゴリズムを使用しています。


波の形状を表現する部分は、主にsea_octave関数とそれを使用しているmapおよびmap_detailed関数によって実現されています。これらの関数は、海の表面の高さと形状を計算するために使用されます。

sea_octave関数

この関数は、特定のUV座標(海の表面上の点)に対して、波の形状を計算します。波の形状は、noise関数によって生成されたノイズに基づいており、波の細かさや動きをシミュレートします。choppyパラメータは、波の荒れ具合を制御します。

map および map_detailed 関数

これらの関数は、3D空間内の点pに対して海の高さを計算します。sea_octave関数を複数回呼び出し、異なるスケールと振幅で波を重ね合わせることにより、よりリアルな海の表面を生成します。ITER_GEOMETRYITER_FRAGMENTは、それぞれの関数で行う繰り返しの回数を指定し、海の表面の詳細度を決定します。

  • map関数は、光の追跡によって視点から見える海の表面を決定するために使用されます。

  • map_detailed関数は、より詳細な海の表面を計算するために使用され、特に法線ベクトルの計算で役立ちます。

これらの関数によって計算された海の表面の形状は、フラグメントシェーダーによってピクセルごとに色を割り当てる際に使用され、結果として波の動きや形状が表現されることになります。



let seaTime = 0;

function setup() {
  createCanvas(800, 400);
  noFill();
}

function draw() {
  background(220);
  
  beginShape();
  for (let x = 0; x <= width; x += 10) {
    // 波の高さを計算
    let y = height / 2 + sin(x * 0.02 + seaTime) * 50;
    // Perlinノイズを使って波をより自然に見せる
    y += noise(x * 0.01, seaTime * 0.5) * 20;
    vertex(x, y);
  }
  endShape();

  seaTime += 0.05; // 時間を進める
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    vec3 col = vec3(0.0);

    // カメラ設定
    vec3 camPos = vec3(0.0, 1.0, 3.0); // カメラの位置
    vec3 rayDir = normalize(vec3(uv, -1.0)); // 視線の方向

    // 波のパラメータ
    float waveSpeed = 1.0;
    float waveHeight = 0.2;
    float frequency = 5.0;

    // 光線追跡
    float t = 0.0;
    for(int i = 0; i < 100; i++) {
        vec3 pos = camPos + t * rayDir;
        float height = sin(pos.x * frequency + iTime * waveSpeed) * cos(pos.z * frequency + iTime * waveSpeed) * waveHeight;
        if(pos.y < height) {
            float diff = height - pos.y;
            col = vec3(0.2, 0.8, 1.0) * (1.0 - diff * 10.0);
            break;
        }
        t += 0.05;
    }

    // 背景色とのブレンド
    col = mix(vec3(0.1, 0.1, 0.2), col, smoothstep(0.0, 1.0, t * 0.2));

    fragColor = vec4(col, 1.0);
}


三次元空間で波を表現する場合、波の形状は通常、空間内の各点における高さ(または他の属性)を時間と空間の関数としてモデル化することによって記述されます。三次元の波を数式で表現する一般的な方法は、波の振幅、周期、位相を含む数学的関数を使用することです。シンプルな三次元波の一例として、次のような数式を考えることができます:


この数式は、二次元空間内での波の伝播を記述し、時間に依存する任意の点の高さを計算することができます。三次元の視覚化のためには、この関数を空間内の点に対して評価し、結果の高さを使用して点の位置を上下に移動させることで、波の動きを模倣します。
実際のシェーダーやシミュレーションでは、この基本的な数式を拡張して、複数の波の重ね合わせ、異なる方向や速度での波の伝播、さらには波の反射や屈折など、より複雑な現象を表現することが一般的です。また、実際の海の波をよりリアルに再現するために、Perlinノイズやシンプレックスノイズなどのノイズ関数を使用して、波の不規則性や細かいディテールを加えることもあります。


お願い致します