Seascape shader(raylib) lazarus / 39-Graphics ---------------------------------------------------------------------- Guva · 2025-04-15 02:38 I've been wanting to rewrite it for raylib for a long time, based on the @gigatron code. Circular motion and sun have been removed from the shader. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program SeascapeShader; uses  raylib, rlgl, math; const  SCREEN_WIDTH = 800;  SCREEN_HEIGHT = 600; var  Shader: TShader;  TimeLoc, ResLoc: Integer;  Resolution: array [0..1] of Single; // vec2  StartTime: Single; begin  InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, 'Raylib Seascape Shader');  SetTargetFPS(60);   // Загрузка шейдера  Shader := LoadShader(nil, 'seascape.fs');  if Shader.id = 0 then    TraceLog(LOG_ERROR, 'Failed to load shader!');   // Получаем локации uniform-переменных  TimeLoc := GetShaderLocation(Shader, 'iTime');  ResLoc := GetShaderLocation(Shader, 'iResolution');   // Устанавливаем разрешение экрана  Resolution[0] := SCREEN_WIDTH;  Resolution[1] := SCREEN_HEIGHT;  SetShaderValue(Shader, ResLoc, @Resolution, SHADER_UNIFORM_VEC2);   StartTime := GetTime();   while not WindowShouldClose() do  begin    // Обновляем время    StartTime := -GetTime();    SetShaderValue(Shader, TimeLoc, @StartTime, SHADER_UNIFORM_FLOAT);     // Отрисовка    BeginDrawing();      ClearBackground(BLACK);       // Рендерим шейдер      BeginShaderMode(Shader);        DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);      EndShaderMode();       // Отладочная информация      DrawFPS(10, 10);      DrawText('Seascape Shader', 10, 30, 20, GREEN);    EndDrawing();  end;   UnloadShader(Shader);  CloseWindow();end.  seascape.fs: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i #version 330 // Входные данные из вершинного шейдераin vec2 fragTexCoord;in vec4 fragColor; // Uniform-переменные (raylib автоматически передаёт texture0 и colDiffuse)uniform sampler2D texture0;uniform vec4 colDiffuse;uniform float iTime;           // Время для анимацииuniform vec2 iResolution;      // Разрешение экрана // Выходной цветout vec4 finalColor; // Константы и функции шейдера (из оригинального Shadertoy)const int NUM_STEPS = 32;const float PI = 3.141592;const float EPSILON = 1e-3;#define EPSILON_NRM (0.1 / iResolution.x) // Параметры моряconst int ITER_GEOMETRY = 3;const int ITER_FRAGMENT = 5;const float SEA_HEIGHT = 0.6;const float SEA_CHOPPY = 4.0;const float SEA_SPEED = 0.8;const float SEA_FREQ = 0.16;const vec3 SEA_BASE = vec3(0.0, 0.09, 0.18);const vec3 SEA_WATER_COLOR = vec3(0.8, 0.9, 0.6) * 0.6;#define SEA_TIME (1.0 + iTime * SEA_SPEED)const mat2 octave_m = mat2(1.6, 1.2, -1.2, 1.6); // Шум и математикаfloat hash(vec2 p) {    float h = dot(p, vec2(127.1, 311.7));    return fract(sin(h) * 43758.5453123);} float noise(vec2 p) {    vec2 i = floor(p);    vec2 f = fract(p);    vec2 u = f * f * (3.0 - 2.0 * f);  return -1.0 + 2.0 * mix(        mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),        mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);} // Освещениеfloat diffuse(vec3 n, vec3 l, float p) {    return pow(dot(n, l) * 0.4 + 0.6, p);} float specular(vec3 n, vec3 l, vec3 e, float s) {    float nrm = (s + 8.0) / (PI * 8.0);    return pow(max(dot(reflect(e, n), l), 0.0), s) * nrm;} // Небоvec3 getSkyColor(vec3 e) {    e.y = (max(e.y, 0.0) * 0.8 + 0.2) * 0.8;    return vec3(pow(1.0 - e.y, 2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4) * 1.1;} // Морские волныfloat sea_octave(vec2 uv, float choppy) {    uv += noise(uv);    vec2 wv = 1.0 - abs(sin(uv));  vec2 swv = abs(cos(uv));    wv = mix(wv, swv, wv);    return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);} // Карта высот (геометрия)float map(vec3 p) {    float freq = SEA_FREQ;    float amp = SEA_HEIGHT;    float choppy = SEA_CHOPPY;    vec2 uv = p.xz; uv.x *= 0.75;     float d, h = 0.0;    for (int i = 0; i < ITER_GEOMETRY; i++) {        d = sea_octave((uv + SEA_TIME) * freq, choppy);        d += sea_octave((uv - SEA_TIME) * freq, choppy);        h += d * amp;        uv *= octave_m; freq *= 1.9; amp *= 0.22;        choppy = mix(choppy, 1.0, 0.2);    }    return p.y - h;} // Детальная карта высот (фрагменты)float map_detailed(vec3 p) {    float freq = SEA_FREQ;    float amp = SEA_HEIGHT;    float choppy = SEA_CHOPPY;    vec2 uv = p.xz; uv.x *= 0.75;     float d, h = 0.0;    for (int i = 0; i < ITER_FRAGMENT; i++) {        d = sea_octave((uv + SEA_TIME) * freq, choppy);        d += sea_octave((uv - SEA_TIME) * freq, choppy);      h += d * amp;        uv *= octave_m; freq *= 1.9; amp *= 0.22;      choppy = mix(choppy, 1.0, 0.2);    }    return p.y - h;} // Цвет моряvec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {  float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);    fresnel = min(fresnel * fresnel * fresnel, 0.5);     vec3 reflected = getSkyColor(reflect(eye, n));    vec3 refracted = SEA_BASE + diffuse(n, l, 80.0) * SEA_WATER_COLOR * 0.12;     vec3 color = mix(refracted, reflected, fresnel);     float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);    color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;     color += specular(n, l, eye, 60.0);  return color;} // Нормалиvec3 getNormal(vec3 p, float eps) {    vec3 n;    n.y = map_detailed(p);    n.x = map_detailed(vec3(p.x + eps, p.y, p.z)) - n.y;    n.z = map_detailed(vec3(p.x, p.y, p.z + eps)) - n.y;    n.y = eps;    return normalize(n);} // Трассировка лучейfloat heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {    float tm = 0.0;    float tx = 1000.0;    float hx = map(ori + dir * tx);    if (hx > 0.0) {        p = ori + dir * tx;        return tx;    }     float hm = map(ori);    for (int i = 0; i < NUM_STEPS; i++) {        float tmid = mix(tm, tx, hm / (hm - hx));        p = ori + dir * tmid;        float hmid = map(p);        if (hmid < 0.0) {            tx = tmid;          hx = hmid;        } else {            tm = tmid;            hm = hmid;        }        if (abs(hmid) < EPSILON) break;    }    return mix(tm, tx, hm / (hm - hx));} // Главная функция рендерингаvec3 getPixel(vec2 fragCoord, float time) {    vec2 uv = fragCoord / iResolution.xy;    uv = uv * 2.0 - 1.0;    uv.x *= iResolution.x / iResolution.y;     // Положение камеры    vec3 ang = vec3(sin(time * 3.0) * 0.1, sin(time) * 0.2 + 0.3, time);    vec3 ori = vec3(0.0, 3.5, time * 5.0);    vec3 dir = normalize(vec3(uv.xy, -2.0));    dir.z += length(uv) * 0.14;    dir = normalize(dir);     // Трассировка    vec3 p;    heightMapTracing(ori, dir, p);    vec3 dist = p - ori;    vec3 n = getNormal(p, dot(dist, dist) * EPSILON_NRM);    vec3 light = normalize(vec3(0.0, 1.0, 0.8));     // Смешивание цвета неба и моря  return mix(        getSkyColor(dir),        getSeaColor(p, n, light, dir, dist),        pow(smoothstep(0.0, -0.02, dir.y), 0.2)    );} // Точка входа (raylib)void main() {    vec2 fragCoord = gl_FragCoord.xy;    vec3 color = getPixel(fragCoord, iTime);    finalColor = vec4(pow(color, vec3(0.65)), 1.0);} ---------------------------------------------------------------------- Gigatron · 2025-04-15 14:09 Awesome @Guva , this pixel shader is one of the best, thank you ! ---------------------------------------------------------------------- Lulu · 2025-04-15 18:31 very realistic, bravo!