Simple version of the Mandelbrot and Julia set. The surrender function can contain any shader you like. It takes an x and y between 0 and 1. Next step perturbation theory
Log in to post a comment.
#version 300 es precision highp float; uniform float iTime; uniform vec2 iResolution; uniform float ShadeMode; // value=1, min=0, max=1, step=1 (No, Yes) uniform float ImageMode; // value=1, min=0, max=1, step=1 (No, Yes) uniform float ImageXScale; // value=1, min=0, max=2, step=0.1 uniform float ImageYScale; // value=1, min=0, max=2, step=0.1 uniform float Front; // value=1, min=0, max=1, step=1 (No, Yes) uniform float Animate; // value=1, min=0, max=1, step=1 (No, Yes) uniform float Radius; // value=0.5, min=0, max=1, step=0.01 uniform float Normalised; // value=1, min=0, max=1, step=1 (No, Yes) uniform float Julia; // value=1, min=0, max=1, step=1 (No, Yes) uniform float Julia_c1; // value=0, min=-1.0, max=1.0, step=0.01 uniform float Julia_c2; // value=0, min=-1.0, max=1.0, step=0.01 uniform int MaxIter; // value=50, min=1, max=1000, step=1 uniform int AA; // value=4, min=1, max=9, step=1 uniform float Zoom; // value=1, min=0.01, max=9, step=0.01 uniform float Xoffset; // value=0, min=-1, max=1, step=0.01 uniform float Xpan; // value=0, min=-1, max=1, step=0.01 uniform float Yoffset; // value=0, min=-1, max=1, step=0.01 uniform float Ypan; // value=0, min=-1, max=1, step=0.01 uniform float light; // value=1.5, min=0, max=4, step=0.01 uniform float angle; // value=45, min=0, max=180, step=0.1 uniform float EscapeRadius; // value=4, min=0, max=100, step=0.01 float jc1; float jc2; out vec4 fragColor; 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 cInverse(vec2 a) { return vec2(a.x,-a.y)/dot(a,a); } vec2 cDiv(vec2 a, vec2 b) { return cMul( a,cInverse(b)); } vec2 cExp(in vec2 z){ return vec2(exp(z.x)*cos(z.y),exp(z.x)*sin(z.y)); } // https://thebookofshaders.com/10/ // Random function float random (vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123); } // Colour scheme // Stolen from llemarie // vec3 HSVtoRGB(float iter){ // iter = mod(iter+iTime, float(MaxIter)); // float value = 1. - float(iter)/float(MaxIter); // value *= value; // float h = value; // float s = 1.; // float v = (iter < float(MaxIter)) ? 1. - value*value : 0.; // float r, g, b, f, p, q, t; // int i; // i = int(h * 6.); // f = h * 6. - float(i); // p = v * (1. - s); // q = v * (1. - f * s); // t = v * (1. - (1. - f) * s); // switch (i % 6){ // case 0: r = v, g = t, b = p; break; // case 1: r = q, g = v, b = p; break; // case 2: r = p, g = v, b = t; break; // case 3: r = p, g = q, b = v; break; // case 4: r = t, g = p, b = v; break; // case 5: r = v, g = p, b = q; break; // } // return vec3(r, g, b); // } vec3 palette(float t) { //return vec3(0.5,0.5,0.5) + vec3(0.5,0.5,0.5)*cos(6.28318*(vec3(2.0,1.0,0.0)*t + vec3(0.5,0.2,0.25))); return vec3(0.5) + vec3(0.5)*cos(6.28318*(vec3(1.0)*t + vec3(0.,0.33,0.67) + iTime)); //return vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5)*cos(6.28318*(vec3(1.0, 1.0, 1.0)*t+2.*iTime*vec3(0.01, 0.10, 0.20)) ); } // Put anything you like here. This is the image that is rendered in the image orbit traps vec4 subrender(float xin, float yin){ xin = xin/ImageXScale; yin = yin/ImageYScale; float sqr = sqrt((xin-0.5)*(xin-0.5)+(yin-0.5)*(yin-0.5)); if(sqr<Radius){ return vec4(sin(xin + iTime)*2. + 0.5,yin,sqr,1.0); } else{ return vec4(0.0); } } vec4 render(float xin, float yin){ vec4 final_col = vec4(0.0); for(int i = 0; i<AA;i++){ float x = 0.0; float y = 0.0; float xx = 0.0; float yy = 0.0; float xy = 0.0; // sample points around the main pixel for anti-aliasing float r = random(vec2(xin + float(i),yin + float(i)))*0.0001; float c1 = (1./Zoom)*(xin + Xoffset + r + Xpan); float c2 = (1./Zoom)*(yin + Yoffset + r - Ypan); // Julia mode if(Julia>0.0){ x = c1; y = c2; c1 = jc1; c2 = jc2; } vec2 dc = vec2(1, 0); vec2 der = dc; float h2 = light; float angle = angle; vec2 v = cExp(vec2(0.0, 45.*2.*3.1415/360.)); v = vec2(sin(iTime),cos(iTime)); int j = 0; // Flag keeps track of opqque pixels int flag = 0; vec4 col = vec4(palette(1.0), 1.0); while(j<MaxIter){ xx = x*x; yy = y*y; if((xx + yy) > EscapeRadius){ if(flag<1){ // Normalised/Smooth iteration count if(Normalised>0.0){ float iter =float(j) - log2(log2(dot(vec2(x,y),vec2(x,y)))) + 4.0; // float logzn = log(xx+yy); // float log4 = log(4.0); // float log2 = 1.44269504089; // float logzndiv4 = logzn/log4; // float loglogzndiv4 = log(logzndiv4); // float nu = loglogzndiv4 * 1.0/log2; // nu = log(logzn/log(4.0))/log(2.0); // float iter = float(j) + 1.0 - nu; col = vec4(palette(iter), 1.0); } else{ col = vec4(palette(float(j)), 1.0); } } break; } der = cMul(vec2(x,y), der) * 2.0 + dc; // TODO: Karatsuba style - not sure how much time it saves. https://mathr.co.uk/blog/2016-04-10_complex_squaring.html xy = x*y; x = xx - yy + c1; y = xy+xy + c2; // Image orbit trap if(ImageMode>0.0 && x>-1.0*ImageXScale && x<=1.0*ImageXScale && y > -1.0*ImageYScale && y<=1.0*ImageYScale){ vec4 sr = subrender(x+0.5, y+0.5); if(sr.a>0.0){ col = sr; if(Front>0.0){ break; } flag = 1; } } j++; } if(ShadeMode>0.0){ vec2 u = cDiv(vec2(x,y), der); u = cDiv(u, abs(vec2(u.x, u.y))); float t = dot(u,v) + h2; t = t/(1. + h2); if(t<0.){ t =0.; } col.xyz *= t; } final_col += col; } return final_col/float(AA); } void main() { // Screen coordinate (from [-aspect, -1] to [aspect, 1]) vec2 q = (2. * gl_FragCoord.xy - iResolution) / iResolution.y; jc1 = Julia_c1; jc2 = Julia_c2; if(Animate>0.0){ jc1 = sin(Julia_c1 + iTime + 5.); jc2 = cos(Julia_c2 + iTime + 7.); } vec4 col = render(q.x, q.y); col.xyz = pow(col.xyz, vec3(0.9)); // Output fragColor = col; }