program HyperspaceShaderRaylib;
uses
raylib, math;
const
SCREEN_WIDTH = 800;
SCREEN_HEIGHT = 600;
var
Shader: TShader;
StartTime: Single;
iTimeLoc: Integer;
iResolutionLoc: Integer;
iMouseLoc: Integer;
currentTime: Single;
mousePos: TVector2;
mouseDown: Single;
mouse: array[0..2] of Single;
resolution: array[0..1] of Single;
const
SHADER_CODE =
// shader author blue_max
// https://www.shadertoy.com/user/blue_max
'#version 330'#10 +
'uniform float iTime;'#10 +
'uniform vec2 iResolution;'#10 +
'uniform vec3 iMouse;'#10 +
'out vec4 fragColor;'#10 +
'#define TAU 6.28318'#10 +
'#define FLARE 1'#10 +
'#define NUM_SLICES 125.0'#10 +
'const float MAX_SLICE_OFFSET = 0.4;'#10 +
'const float T_MAX = 2.0;'#10 +
'const float T_JUMP = 0.75;'#10 +
'const float jump_speed = 15.0;'#10 +
'const vec3 blue_col = vec3(0.3, 0.3, 0.5);'#10 +
'const vec3 white_col = vec3(0.85, 0.85, 0.9);'#10 +
'const vec3 flare_col = vec3(0.9, 0.9, 1.4);'#10 +
'float sdLine(in vec2 p, in vec2 a, in vec2 b, in float ring)'#10 +
'{'#10 +
' vec2 pa = p-a, ba = b-a;'#10 +
' float h = clamp(dot(pa,ba)/dot(ba,ba), 0.0, 1.0);'#10 +
' return length(pa - ba*h) - ring;'#10 +
'}'#10 +
'float rand(vec2 co)'#10 +
'{'#10 +
' return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);'#10 +
'}'#10 +
'vec3 lensflare(vec3 uv, vec3 pos, float flare_size, float ang_offset)'#10 +
'{'#10 +
' float z = uv.z / length(uv.xy);'#10 +
' vec2 main = uv.xy - pos.xy;'#10 +
' float dist = length(main);'#10 +
' float num_points = 2.71;'#10 +
' float disk_size = 0.2;'#10 +
' float inv_size = 1.0 / flare_size;'#10 +
' float ang = atan(main.y, main.x) + ang_offset;'#10 +
' float fade = (z < 0.0) ? -z : 1.0;'#10 +
' float f0 = 1.0/(dist * inv_size + 1.0);'#10 +
' f0 = f0 + f0 * (0.1 * sin((sin(ang*2.0 + pos.x)*4.0 - cos(ang*3.0 + pos.y)) * num_points) + disk_size);'#10 +
' if (z < 0.0)'#10 +
' return clamp(mix(vec3(f0), vec3(0.0), 0.75 * fade), 0.0, 1.0);'#10 +
' else'#10 +
' return vec3(f0);'#10 +
'}'#10 +
'vec3 cc(vec3 color, float factor, float factor2)'#10 +
'{'#10 +
' float w = color.x+color.y+color.z;'#10 +
' return mix(color, vec3(w)*factor, w*factor2);'#10 +
'}'#10 +
'void main()'#10 +
'{'#10 +
' vec3 color = vec3(0.0);'#10 +
' float time = mod(iTime, T_MAX);'#10 +
' float t = time / T_MAX;'#10 +
' vec2 p = (2.0 * gl_FragCoord.xy - iResolution.xy) / min(iResolution.x, iResolution.y);'#10 +
' vec2 mo = (2.0 * iMouse.xy - iResolution.xy) / min(iResolution.x, iResolution.y);'#10 +
' p += vec2(0, -0.2);'#10 +
' float ay = 0.0, ax = 0.0;'#10 +
' if (iMouse.z > 0.0) {'#10 +
' ay = 3.0 * mo.x;'#10 +
' ax = 3.0 * mo.y;'#10 +
' }'#10 +
' mat3 mY = mat3('#10 +
' cos(ay), 0.0, sin(ay),'#10 +
' 0.0, 1.0, 0.0,'#10 +
' -sin(ay), 0.0, cos(ay)'#10 +
' );'#10 +
' mat3 mX = mat3('#10 +
' 1.0, 0.0, 0.0,'#10 +
' 0.0, cos(ax), sin(ax),'#10 +
' 0.0, -sin(ax), cos(ax)'#10 +
' );'#10 +
' mat3 m = mX * mY;'#10 +
' vec3 v = vec3(p, 1.0);'#10 +
' v = m * v;'#10 +
' float fade = clamp(mix(0.1, 1.1, t * 2.0), 0.0, 2.0);'#10 +
' for(float i = 0.0; i < 80.0; i++)'#10 +
' {'#10 +
' vec3 trail_color = vec3(0.0);'#10 +
' float angle = atan(v.y, v.x) / 3.141592 / 2.0 + 0.13 * i;'#10 +
' float slice = floor(angle * NUM_SLICES);'#10 +
' float slice_fract = fract(angle * NUM_SLICES);'#10 +
' float slice_offset = MAX_SLICE_OFFSET * '#10 +
' rand(vec2(slice, 4.0 + i * 25.0)) - (MAX_SLICE_OFFSET / 2.0);'#10 +
' float dist = 10.0 * rand(vec2(slice, 1.0 + i * 10.0)) - 5.0;'#10 +
' float z = dist * v.z / length(v.xy);'#10 +
' float f = sign(dist);'#10 +
' if (f == 0.0) f = 1.0;'#10 +
' float fspeed = f * (0.1 * rand(vec2(slice, 1.0 + i * 10.0)) + i * 0.01);'#10 +
' float fjump_speed = f * jump_speed;'#10 +
' float trail_start = 10.0 * rand(vec2(slice, 0.0 + i * 10.0)) - 5.0;'#10 +
' trail_start -= mix(0.0, fjump_speed, smoothstep(T_JUMP, 1.0, t));'#10 +
' float trail_end = trail_start - t * fspeed;'#10 +
' float trail_x = smoothstep(trail_start, trail_end, z);'#10 +
' trail_color = mix(blue_col, white_col, trail_x);'#10 +
' float h = sdLine('#10 +
' vec2(slice_fract + slice_offset, z),'#10 +
' vec2(0.5, trail_start), '#10 +
' vec2(0.5, trail_end),'#10 +
' mix(0.0, 0.015, t * z));'#10 +
' float threshold = 0.09;'#10 +
' h = (h < 0.01) ? 1.0 : 0.85 * smoothstep(threshold, 0.0, abs(h));'#10 +
' trail_color *= fade * h;'#10 +
' color = max(color, trail_color);'#10 +
' }'#10 +
'#ifdef FLARE'#10 +
' float flare_size = mix(0.0, 0.1, smoothstep(0.35, T_JUMP + 0.2, t));'#10 +
' flare_size += mix(0.0, 20.0, smoothstep(T_JUMP + 0.05, 1.0, t));'#10 +
' vec3 flare = flare_col * lensflare(v, vec3(0.0), flare_size, t);'#10 +
' color += cc(flare, 0.5, 0.1);'#10 +
' color += mix(0.0, 1.0, smoothstep(T_JUMP + 0.1, 1.0, t));'#10 +
'#else'#10 +
' color += mix(0.0, 1.0, smoothstep(T_JUMP - 0.0, 1.0, t));'#10 +
'#endif'#10 +
' fragColor = vec4(color, 1.0);'#10 +
'}';
begin
// Инициализация окна
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, 'Hyperspace Shader with Raylib');
SetTargetFPS(60);
// Загрузка шейдера из строки
Shader := LoadShaderFromMemory(nil, PChar(SHADER_CODE));
// Получение локаций uniform-переменных
iTimeLoc := GetShaderLocation(Shader, 'iTime');
iResolutionLoc := GetShaderLocation(Shader, 'iResolution');
iMouseLoc := GetShaderLocation(Shader, 'iMouse');
// Установка разрешения
resolution[0] := SCREEN_WIDTH;
resolution[1] := SCREEN_HEIGHT;
SetShaderValue(Shader, iResolutionLoc, @resolution, SHADER_UNIFORM_VEC2);
StartTime := GetTime();
// Главный цикл
while not WindowShouldClose() do
begin
// Обновление
currentTime := GetTime() - StartTime;
SetShaderValue(Shader, iTimeLoc, @currentTime, SHADER_UNIFORM_FLOAT);
// Установка позиции мыши
mousePos := GetMousePosition();
if IsMouseButtonDown(MOUSE_LEFT_BUTTON) then
mouseDown := 1.0
else
mouseDown := 0.0;
mouse[0] := mousePos.x;
mouse[1] := mousePos.y;
mouse[2] := mouseDown;
SetShaderValue(Shader, iMouseLoc, @mouse, SHADER_UNIFORM_VEC3);
// Рендеринг
BeginDrawing();
ClearBackground(BLACK);
// Рисуем шейдер на весь экран
BeginShaderMode(Shader);
DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
EndShaderMode();
// Выводим инструкции
DrawText('Click and drag mouse to rotate hyperspace effect', 10, 10, 20, LIGHTGRAY);
EndDrawing();
end;
// Очистка
UnloadShader(Shader);
CloseWindow();
end.