gpu-fractal/frag_shader.glsl
2025-01-18 22:24:46 +00:00

146 lines
2.8 KiB
GLSL

/*
* Copyright (c) Camden Dixie O'Brien
* SPDX-License-Identifier: AGPL-3.0-only
*/
#version 450
#include "config.h"
#define NCOLS 8
#if !defined(CPOW_DTHETA) && !defined(THING)
#define MAXMAG 2.0
#endif
layout(location = 0) out vec4 out_colour;
layout(push_constant) uniform Constants {
vec2 img_size;
#if defined(JULIA) || defined(THING)
vec2 julia;
#endif
vec2 centre;
#ifdef CPOW_DTHETA
vec2 cpow;
#endif
#ifdef POWRATE
float zpow;
#endif
float scale;
} params;
vec3 incol = vec3(0.000000, 0.014444, 0.027321);
vec3 palette[NCOLS] = vec3[](
vec3(0.000000, 0.049707, 0.107023),
vec3(0.025187, 0.064803, 0.177888),
vec3(0.254152, 0.080220, 0.274677),
vec3(0.502886, 0.080220, 0.278894),
vec3(1.000000, 0.124772, 0.119538),
vec3(1.000000, 0.234551, 0.030713),
vec3(1.000000, 0.381326, 0.000000),
vec3(1.000000, 0.651406, 0.215861)
);
#if SS == 4
vec2 ss_offsets[SS] = vec2[](
vec2(-0.25, -0.25),
vec2( 0.25, -0.25),
vec2(-0.25, 0.25),
vec2( 0.25, 0.25)
);
#elif SS == 9
vec2 ss_offsets[SS] = vec2[](
vec2(-0.33, -0.33), vec2(0.0, -0.33), vec2(0.33, -0.33),
vec2(-0.33, 0.0), vec2(0.0, 0.0), vec2(0.33, 0.0),
vec2(-0.33, 0.33), vec2(0.0, 0.33), vec2(0.33, 0.33)
);
#else
#error "Unsupported supersampling count"
#endif
vec2 maptoz(vec2 xy)
{
float aspect = params.img_size.x / params.img_size.y;
vec2 z = 4.0 * (xy / params.img_size.xy - 0.5);
z.x *= aspect;
return params.scale * z + params.centre;
}
vec2 cmul(vec2 a, vec2 b)
{
return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}
vec2 cexp(vec2 z)
{
return exp(z.x) * vec2(cos(z.y), sin(z.y));
}
vec2 cln(vec2 z)
{
return vec2(log(length(z)), atan(z.y, z.x));
}
vec2 cpow(vec2 z, vec2 p)
{
if (z.x == 0.0 && z.y == 0.0) return vec2(0.0, 0.0);
return cexp(cmul(p, cln(z)));
}
vec2 zpow(vec2 z, float p)
{
float mag = pow(length(z), p);
float arg = p * atan(z.y, z.x);
return mag * vec2(cos(arg), sin(arg));
}
int fractal(vec2 c) {
#ifdef JULIA
vec2 z = c;
c = params.julia;
#else
vec2 z = vec2(0.0, 0.0);
#endif
for (int i = 0; i < MAXITER; ++i) {
#ifdef CPOW_DTHETA
z = cpow(z, params.cpow) + c;
#elif defined(POWRATE)
z = zpow(z, params.zpow) + c;
#elif defined(THING)
z = cpow(z, c) + params.julia;
#else
z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;
#endif
if (length(z) > MAXMAG)
return i;
}
return -1;
}
vec3 colour(int i) {
if (i == -1) {
return incol;
} else {
float c = float(NCOLS) * sqrt(float(i) / float(MAXITER));
int fc = int(floor(c));
int cc = int(ceil(c));
float p = c - float(fc);
p = smoothstep(0.0, 1.0, p);
return mix(palette[fc], palette[cc], p);
}
}
void main()
{
vec2 c;
vec3 col = vec3(0.0, 0.0, 0.0);
for (int i = 0; i < SS; ++i) {
c = maptoz(gl_FragCoord.xy + ss_offsets[i]);
col += colour(fractal(c));
}
col /= SS;
out_colour = vec4(col, 1.0);
}