My atempt to get a mandelbrot rendering properly using only shaders, not quite there.
Lot’s of webgl boilerplate underneath
Updates
- 2023-11-25: exprimented with open aliasing
precision highp float;
const float MAX_ITER = 4096.0;
uniform float iTime;
uniform vec2 iResolution;
float mandelbrot(vec2 uv) {
vec2 c = 4.0 * uv - vec2(0.7, 0.0);
c = c / pow(iTime * 0.2, 4.0) - vec2(0.65, 0.45);
vec2 z = vec2(0.0);
float iter = 0.0;
float m;
for(float i = 0.0; i < MAX_ITER; i++){
z = vec2(z.x*z.x - z.y*z.y, 2.0*z.x*z.y) + c;
if(dot(z,z) > 4.0) {
// Compute smoothed iteration count
// m = iter - log(log(length(z))) / log(2.0);
m = iter;
// return m/MAX_ITER;
return iter;
}
iter++;
}
return MAX_ITER;
}
vec3 hash13(float m){
float x = fract(sin(m) * 5624.246);
float y = fract(sin(m + x) * 2216.486);
float z = fract(sin(x + y) * 8276.352);
return vec3(x, y, z);
}
vec3 color(float iter) {
float r = 0.5 + 0.5*cos(3.0 + iter*0.15);
float g = 0.5 + 0.5*cos(3.0 + iter*0.15 + 2.0);
float b = 0.5 + 0.5*cos(3.0 + iter*0.15 + 4.0);
return vec3(r, g, b);
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
vec3 col = vec3(0.0);
const int samples = 4; // Increase for better quality
for(int x = 0; x < samples; x++) {
for(int y = 0; y < samples; y++) {
vec2 sampleUv = uv + vec2(x, y) * (1.0 / iResolution.y) / float(samples);
float m = mandelbrot(sampleUv);
col += color(m) * hash13(m);
}
}
col /= float(samples * samples);
gl_FragColor = vec4(col, 1.0);
}
// Vertex shader
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}