Lazarus

Programming => Graphics and Multimedia => Graphics => Topic started by: Guva on April 15, 2025, 04:38:56 am

Title: Seascape shader(raylib)
Post by: Guva on April 15, 2025, 04:38:56 am
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][+][-]
  1. program SeascapeShader;
  2.  
  3. uses
  4.   raylib, rlgl, math;
  5.  
  6. const
  7.   SCREEN_WIDTH = 800;
  8.   SCREEN_HEIGHT = 600;
  9.  
  10. var
  11.   Shader: TShader;
  12.   TimeLoc, ResLoc: Integer;
  13.   Resolution: array [0..1] of Single; // vec2
  14.   StartTime: Single;
  15.  
  16. begin
  17.   InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, 'Raylib Seascape Shader');
  18.   SetTargetFPS(60);
  19.  
  20.   // Загрузка шейдера
  21.   Shader := LoadShader(nil, 'seascape.fs');
  22.   if Shader.id = 0 then
  23.     TraceLog(LOG_ERROR, 'Failed to load shader!');
  24.  
  25.   // Получаем локации uniform-переменных
  26.   TimeLoc := GetShaderLocation(Shader, 'iTime');
  27.   ResLoc := GetShaderLocation(Shader, 'iResolution');
  28.  
  29.   // Устанавливаем разрешение экрана
  30.   Resolution[0] := SCREEN_WIDTH;
  31.   Resolution[1] := SCREEN_HEIGHT;
  32.   SetShaderValue(Shader, ResLoc, @Resolution, SHADER_UNIFORM_VEC2);
  33.  
  34.   StartTime := GetTime();
  35.  
  36.   while not WindowShouldClose() do
  37.   begin
  38.     // Обновляем время
  39.     StartTime := -GetTime();
  40.     SetShaderValue(Shader, TimeLoc, @StartTime, SHADER_UNIFORM_FLOAT);
  41.  
  42.     // Отрисовка
  43.     BeginDrawing();
  44.       ClearBackground(BLACK);
  45.  
  46.       // Рендерим шейдер
  47.       BeginShaderMode(Shader);
  48.         DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
  49.       EndShaderMode();
  50.  
  51.       // Отладочная информация
  52.       DrawFPS(10, 10);
  53.       DrawText('Seascape Shader', 10, 30, 20, GREEN);
  54.     EndDrawing();
  55.   end;
  56.  
  57.   UnloadShader(Shader);
  58.   CloseWindow();
  59. end.
  60.  

seascape.fs:
Code: C  [Select][+][-]
  1. #version 330
  2.  
  3. // Входные данные из вершинного шейдера
  4. in vec2 fragTexCoord;
  5. in vec4 fragColor;
  6.  
  7. // Uniform-переменные (raylib автоматически передаёт texture0 и colDiffuse)
  8. uniform sampler2D texture0;
  9. uniform vec4 colDiffuse;
  10. uniform float iTime;           // Время для анимации
  11. uniform vec2 iResolution;      // Разрешение экрана
  12.  
  13. // Выходной цвет
  14. out vec4 finalColor;
  15.  
  16. // Константы и функции шейдера (из оригинального Shadertoy)
  17. const int NUM_STEPS = 32;
  18. const float PI = 3.141592;
  19. const float EPSILON = 1e-3;
  20. #define EPSILON_NRM (0.1 / iResolution.x)
  21.  
  22. // Параметры моря
  23. const int ITER_GEOMETRY = 3;
  24. const int ITER_FRAGMENT = 5;
  25. const float SEA_HEIGHT = 0.6;
  26. const float SEA_CHOPPY = 4.0;
  27. const float SEA_SPEED = 0.8;
  28. const float SEA_FREQ = 0.16;
  29. const vec3 SEA_BASE = vec3(0.0, 0.09, 0.18);
  30. const vec3 SEA_WATER_COLOR = vec3(0.8, 0.9, 0.6) * 0.6;
  31. #define SEA_TIME (1.0 + iTime * SEA_SPEED)
  32. const mat2 octave_m = mat2(1.6, 1.2, -1.2, 1.6);
  33.  
  34. // Шум и математика
  35. float hash(vec2 p) {
  36.     float h = dot(p, vec2(127.1, 311.7));
  37.     return fract(sin(h) * 43758.5453123);
  38. }
  39.  
  40. float noise(vec2 p) {
  41.     vec2 i = floor(p);
  42.     vec2 f = fract(p);
  43.     vec2 u = f * f * (3.0 - 2.0 * f);
  44.     return -1.0 + 2.0 * mix(
  45.         mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),
  46.         mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);
  47. }
  48.  
  49. // Освещение
  50. float diffuse(vec3 n, vec3 l, float p) {
  51.     return pow(dot(n, l) * 0.4 + 0.6, p);
  52. }
  53.  
  54. float specular(vec3 n, vec3 l, vec3 e, float s) {
  55.     float nrm = (s + 8.0) / (PI * 8.0);
  56.     return pow(max(dot(reflect(e, n), l), 0.0), s) * nrm;
  57. }
  58.  
  59. // Небо
  60. vec3 getSkyColor(vec3 e) {
  61.     e.y = (max(e.y, 0.0) * 0.8 + 0.2) * 0.8;
  62.     return vec3(pow(1.0 - e.y, 2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4) * 1.1;
  63. }
  64.  
  65. // Морские волны
  66. float sea_octave(vec2 uv, float choppy) {
  67.     uv += noise(uv);
  68.     vec2 wv = 1.0 - abs(sin(uv));
  69.     vec2 swv = abs(cos(uv));
  70.     wv = mix(wv, swv, wv);
  71.     return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
  72. }
  73.  
  74. // Карта высот (геометрия)
  75. float map(vec3 p) {
  76.     float freq = SEA_FREQ;
  77.     float amp = SEA_HEIGHT;
  78.     float choppy = SEA_CHOPPY;
  79.     vec2 uv = p.xz; uv.x *= 0.75;
  80.  
  81.     float d, h = 0.0;
  82.     for (int i = 0; i < ITER_GEOMETRY; i++) {
  83.         d = sea_octave((uv + SEA_TIME) * freq, choppy);
  84.         d += sea_octave((uv - SEA_TIME) * freq, choppy);
  85.         h += d * amp;
  86.         uv *= octave_m; freq *= 1.9; amp *= 0.22;
  87.         choppy = mix(choppy, 1.0, 0.2);
  88.     }
  89.     return p.y - h;
  90. }
  91.  
  92. // Детальная карта высот (фрагменты)
  93. float map_detailed(vec3 p) {
  94.     float freq = SEA_FREQ;
  95.     float amp = SEA_HEIGHT;
  96.     float choppy = SEA_CHOPPY;
  97.     vec2 uv = p.xz; uv.x *= 0.75;
  98.  
  99.     float d, h = 0.0;
  100.     for (int i = 0; i < ITER_FRAGMENT; i++) {
  101.         d = sea_octave((uv + SEA_TIME) * freq, choppy);
  102.         d += sea_octave((uv - SEA_TIME) * freq, choppy);
  103.         h += d * amp;
  104.         uv *= octave_m; freq *= 1.9; amp *= 0.22;
  105.         choppy = mix(choppy, 1.0, 0.2);
  106.     }
  107.     return p.y - h;
  108. }
  109.  
  110. // Цвет моря
  111. vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
  112.     float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
  113.     fresnel = min(fresnel * fresnel * fresnel, 0.5);
  114.  
  115.     vec3 reflected = getSkyColor(reflect(eye, n));
  116.     vec3 refracted = SEA_BASE + diffuse(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
  117.  
  118.     vec3 color = mix(refracted, reflected, fresnel);
  119.  
  120.     float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
  121.     color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
  122.  
  123.     color += specular(n, l, eye, 60.0);
  124.     return color;
  125. }
  126.  
  127. // Нормали
  128. vec3 getNormal(vec3 p, float eps) {
  129.     vec3 n;
  130.     n.y = map_detailed(p);
  131.     n.x = map_detailed(vec3(p.x + eps, p.y, p.z)) - n.y;
  132.     n.z = map_detailed(vec3(p.x, p.y, p.z + eps)) - n.y;
  133.     n.y = eps;
  134.     return normalize(n);
  135. }
  136.  
  137. // Трассировка лучей
  138. float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
  139.     float tm = 0.0;
  140.     float tx = 1000.0;
  141.     float hx = map(ori + dir * tx);
  142.     if (hx > 0.0) {
  143.         p = ori + dir * tx;
  144.         return tx;
  145.     }
  146.  
  147.     float hm = map(ori);
  148.     for (int i = 0; i < NUM_STEPS; i++) {
  149.         float tmid = mix(tm, tx, hm / (hm - hx));
  150.         p = ori + dir * tmid;
  151.         float hmid = map(p);
  152.         if (hmid < 0.0) {
  153.             tx = tmid;
  154.             hx = hmid;
  155.         } else {
  156.             tm = tmid;
  157.             hm = hmid;
  158.         }
  159.         if (abs(hmid) < EPSILON) break;
  160.     }
  161.     return mix(tm, tx, hm / (hm - hx));
  162. }
  163.  
  164. // Главная функция рендеринга
  165. vec3 getPixel(vec2 fragCoord, float time) {
  166.     vec2 uv = fragCoord / iResolution.xy;
  167.     uv = uv * 2.0 - 1.0;
  168.     uv.x *= iResolution.x / iResolution.y;
  169.  
  170.     // Положение камеры
  171.     vec3 ang = vec3(sin(time * 3.0) * 0.1, sin(time) * 0.2 + 0.3, time);
  172.     vec3 ori = vec3(0.0, 3.5, time * 5.0);
  173.     vec3 dir = normalize(vec3(uv.xy, -2.0));
  174.     dir.z += length(uv) * 0.14;
  175.     dir = normalize(dir);
  176.  
  177.     // Трассировка
  178.     vec3 p;
  179.     heightMapTracing(ori, dir, p);
  180.     vec3 dist = p - ori;
  181.     vec3 n = getNormal(p, dot(dist, dist) * EPSILON_NRM);
  182.     vec3 light = normalize(vec3(0.0, 1.0, 0.8));
  183.  
  184.     // Смешивание цвета неба и моря
  185.     return mix(
  186.         getSkyColor(dir),
  187.         getSeaColor(p, n, light, dir, dist),
  188.         pow(smoothstep(0.0, -0.02, dir.y), 0.2)
  189.     );
  190. }
  191.  
  192. // Точка входа (raylib)
  193. void main() {
  194.     vec2 fragCoord = gl_FragCoord.xy;
  195.     vec3 color = getPixel(fragCoord, iTime);
  196.     finalColor = vec4(pow(color, vec3(0.65)), 1.0);
  197. }
  198.  
Title: Re: Seascape shader(raylib)
Post by: Gigatron on April 15, 2025, 04:09:18 pm
Awesome @Guva , this pixel shader is one of the best, thank you !
Title: Re: Seascape shader(raylib)
Post by: Lulu on April 15, 2025, 08:31:08 pm
very realistic, bravo!
TinyPortal © 2005-2018