1
0
Fork 0
mirror of https://github.com/HackerPoet/PySpace synced 2025-08-24 22:02:33 +02:00
fractals/pyspace/frag.glsl
2019-09-21 23:52:16 -07:00

321 lines
8.6 KiB
GLSL

#version 120
#define M_PI 3.14159265358979
uniform mat4 iMat;
uniform mat4 iPrevMat;
uniform vec2 iResolution;
uniform float iIPD;
// [pydefine]
// [/pydefine]
// [pyvars]
// [/pyvars]
const float FOCAL_DIST = 1.0 / tan(M_PI * FIELD_OF_VIEW / 360.0);
float rand(float s, float minV, float maxV) {
float r = sin(s*s*27.12345 + 1000.9876 / (s*s + 1e-5));
return (r + 1.0) * 0.5 * (maxV - minV) + minV;
}
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0 );
return mix(b, a, h) - k*h*(1.0 - h);
//return -log(exp(-a/k) + exp(-b/k))*k;
}
//##########################################
//
// Space folding functions
//
//##########################################
void planeFold(inout vec4 z, vec3 n, float d) {
z.xyz -= 2.0 * min(0.0, dot(z.xyz, n) - d) * n;
}
void absFold(inout vec4 z, vec3 c) {
z.xyz = abs(z.xyz - c) + c;
}
void sierpinskiFold(inout vec4 z) {
z.xy -= min(z.x + z.y, 0.0);
z.xz -= min(z.x + z.z, 0.0);
z.yz -= min(z.y + z.z, 0.0);
}
void mengerFold(inout vec4 z) {
float a = min(z.x - z.y, 0.0);
z.x -= a;
z.y += a;
a = min(z.x - z.z, 0.0);
z.x -= a;
z.z += a;
a = min(z.y - z.z, 0.0);
z.y -= a;
z.z += a;
}
void sphereFold(inout vec4 z, float minR, float maxR) {
float r2 = dot(z.xyz, z.xyz);
z *= max(maxR / max(minR, r2), 1.0);
}
void boxFold(inout vec4 z, vec3 r) {
z.xyz = clamp(z.xyz, -r, r) * 2.0 - z.xyz;
}
void rotX(inout vec4 z, float s, float c) {
z.yz = vec2(c*z.y + s*z.z, c*z.z - s*z.y);
}
void rotY(inout vec4 z, float s, float c) {
z.xz = vec2(c*z.x - s*z.z, c*z.z + s*z.x);
}
void rotZ(inout vec4 z, float s, float c) {
z.xy = vec2(c*z.x + s*z.y, c*z.y - s*z.x);
}
void rotX(inout vec4 z, float a) {
rotX(z, sin(a), cos(a));
}
void rotY(inout vec4 z, float a) {
rotY(z, sin(a), cos(a));
}
void rotZ(inout vec4 z, float a) {
rotZ(z, sin(a), cos(a));
}
//##########################################
//
// Primative distance estimators
//
//##########################################
float de_sphere(vec4 p, float r) {
return (length(p.xyz) - r) / p.w;
}
float de_box(vec4 p, vec3 s) {
vec3 a = abs(p.xyz) - s;
return (min(max(max(a.x, a.y), a.z), 0.0) + length(max(a, 0.0))) / p.w;
}
float de_tetrahedron(vec4 p, float r) {
float md = max(max(-p.x - p.y - p.z, p.x + p.y - p.z),
max(-p.x + p.y + p.z, p.x - p.y + p.z));
return (md - r) / (p.w * sqrt(3.0));
}
float de_inf_cross(vec4 p, float r) {
vec3 q = p.xyz * p.xyz;
return (sqrt(min(min(q.x + q.y, q.x + q.z), q.y + q.z)) - r) / p.w;
}
float de_inf_cross_xy(vec4 p, float r) {
vec3 q = p.xyz * p.xyz;
return (sqrt(min(q.x, q.y) + q.z) - r) / p.w;
}
float de_inf_line(vec4 p, vec3 n, float r) {
return (length(p.xyz - n*dot(p.xyz, n)) - r) / p.w;
}
//##########################################
//
// Compiled
//
//##########################################
// [pyspace]
// [/pyspace]
//##########################################
//
// Main code
//
//##########################################
vec4 ray_march(inout vec4 p, vec4 ray, float sharpness, float td) {
//March the ray
float d = MIN_DIST;
float s = 0.0;
float min_d = 1.0;
for (; s < MAX_MARCHES; s += 1.0) {
d = DE(p);
if (d < MIN_DIST) {
s += d / MIN_DIST;
break;
} else if (td > MAX_DIST) {
break;
}
td += d;
p += ray * d;
min_d = min(min_d, sharpness * d / td);
}
return vec4(d, s, td, min_d);
}
vec4 ray_march(inout vec4 p, vec3 ray, float sharpness, float td) {
return ray_march(p, vec4(ray, 0.0), sharpness, td);
}
//A faster formula to find the gradient/normal direction of the DE(the w component is the average DE)
//credit to http://www.iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
vec3 calcNormal(vec4 p, float dx) {
const vec3 k = vec3(1,-1,0);
return normalize(k.xyy*DE(p + k.xyyz*dx) +
k.yyx*DE(p + k.yyxz*dx) +
k.yxy*DE(p + k.yxyz*dx) +
k.xxx*DE(p + k.xxxz*dx));
}
vec4 scene(inout vec4 origin, inout vec4 ray, float vignette, float td) {
//Trace the ray
vec4 p = origin;
vec4 d_s_td_m = ray_march(p, ray, GLOW_SHARPNESS, td);
float d = d_s_td_m.x;
float s = d_s_td_m.y;
td = d_s_td_m.z;
float m = d_s_td_m.w;
//Determine the color for this pixel
vec3 col = vec3(0.0);
float min_dist = MIN_DIST * max(td * LOD_MULTIPLIER, 1.0);
if (d < min_dist) {
//Get the surface normal
vec3 n = calcNormal(p, MIN_DIST * 10);
vec3 reflected = ray.xyz - 2.0*dot(ray.xyz, n) * n;
//Get coloring
vec3 orig_col = clamp(COL(p).xyz, 0.0, 1.0);
//Get if this point is in shadow
float k = 1.0;
#if SHADOWS_ENABLED
vec4 light_pt = p;
light_pt.xyz += n * min_dist * 10;
vec4 rm = ray_march(light_pt, LIGHT_DIRECTION, SHADOW_SHARPNESS, 0.0);
k = rm.w * min(rm.z, 1.0);
#endif
//Get specular
#if SPECULAR_HIGHLIGHT > 0
float specular = max(dot(reflected, LIGHT_DIRECTION), 0.0);
specular = pow(specular, SPECULAR_HIGHLIGHT);
col += specular * LIGHT_COLOR * k;
#endif
//Get diffuse lighting
#if DIFFUSE_ENHANCED_ENABLED
k = min(k, SHADOW_DARKNESS * 0.5 * (dot(n, LIGHT_DIRECTION) - 1.0) + 1.0);
#elif DIFFUSE_ENABLED
k = min(k, dot(n, LIGHT_DIRECTION));
#endif
//Don't make shadows entirely dark
k = max(k, 1.0 - SHADOW_DARKNESS);
col += orig_col * LIGHT_COLOR * k;
//Add small amount of ambient occlusion
float a = 1.0 / (1.0 + s * AMBIENT_OCCLUSION_STRENGTH);
col += (1.0 - a) * AMBIENT_OCCLUSION_COLOR_DELTA;
//Add fog effects
#if FOG_ENABLED
a = td / MAX_DIST;
col = (1.0 - a) * col + a * BACKGROUND_COLOR;
#endif
//Set up the reflection
origin = p + vec4(n * min_dist * 100, 0.0);
ray = vec4(reflected, 0.0);
//Apply vignette if needed
#if VIGNETTE_FOREGROUND
col *= vignette;
#endif
} else {
//Ray missed, start with solid background color
col += BACKGROUND_COLOR;
//Apply glow
#if GLOW_ENABLED
col += (1.0 - m) * (1.0 - m) * GLOW_COLOR_DELTA;
#endif
col *= vignette;
//Background specular
#if SUN_ENABLED
float sun_spec = dot(ray.xyz, LIGHT_DIRECTION) - 1.0 + SUN_SIZE;
sun_spec = min(exp(sun_spec * SUN_SHARPNESS / SUN_SIZE), 1.0);
col += LIGHT_COLOR * sun_spec;
#endif
}
return vec4(col, td);
}
void main() {
vec4 col = vec4(0.0);
for (int k = 0; k < MOTION_BLUR_LEVEL + 1; ++k) {
for (int i = 0; i < ANTIALIASING_SAMPLES; ++i) {
for (int j = 0; j < ANTIALIASING_SAMPLES; ++j) {
mat4 mat = iMat;
#if MOTION_BLUR_LEVEL > 0
float a = MOTION_BLUR_RATIO * float(k) / (MOTION_BLUR_LEVEL + 1);
mat = iPrevMat*a + iMat*(1.0 - a);
#endif
vec2 delta = vec2(i, j) / ANTIALIASING_SAMPLES;
vec2 delta2 = vec2(rand(i,0,1), rand(j+0.1,0,1));
vec4 dxy = vec4(delta2.x, delta2.y, 0.0, 0.0) * DEPTH_OF_FIELD_STRENGTH / iResolution.x;
#if ODS
//Get the normalized screen coordinate
vec2 screen_pos;
float scale;
vec2 ods_coord = vec2(gl_FragCoord.x, gl_FragCoord.y * 2);
if (ods_coord.y < iResolution.y) {
screen_pos = (ods_coord + delta) / iResolution.xy;
scale = -iIPD*0.5;
} else {
screen_pos = (ods_coord - vec2(0, iResolution.y) + delta) / iResolution.xy;
scale = iIPD*0.5;
}
float theta = -2*M_PI*screen_pos.x;
float phi = -0.5*M_PI + screen_pos.y*M_PI;
scale *= cos(phi);
vec4 p = mat[3] - mat * vec4(cos(theta) * scale, 0, sin(theta) * scale, 0);
vec4 ray = mat * vec4(sin(theta)*cos(phi), sin(phi), cos(theta)*cos(phi), 0);
#else
//Get normalized screen coordinate
vec2 screen_pos = (gl_FragCoord.xy + delta) / iResolution.xy;
vec2 uv = 2*screen_pos - 1;
uv.x *= iResolution.x / iResolution.y;
//Convert screen coordinate to 3d ray
#if ORTHOGONAL_PROJECTION
vec4 ray = vec4(0.0, 0.0, -FOCAL_DIST, 0.0);
ray = mat * normalize(ray);
#else
vec4 ray = normalize(vec4(uv.x, uv.y, -FOCAL_DIST, 0.0));
ray = mat * normalize(ray * DEPTH_OF_FIELD_DISTANCE + dxy);
#endif
//Cast the first ray
#if ORTHOGONAL_PROJECTION
vec4 p = mat[3] + mat * vec4(uv.x, uv.y, 0.0, 0.0) * ORTHOGONAL_ZOOM;
#else
vec4 p = mat[3] - mat * dxy;
#endif
#endif
//Reflect light if needed
float vignette = 1.0 - VIGNETTE_STRENGTH * length(screen_pos - 0.5);
#if REFLECTION_LEVEL > 0
vec3 newCol = vec3(0.0);
vec4 prevRay = ray;
float ref_alpha = 1.0;
for (int r = 0; r < REFLECTION_LEVEL + 1; ++r) {
ref_alpha *= REFLECTION_ATTENUATION;
newCol += ref_alpha * scene(p, ray, vignette, 0.0);
if (ray == prevRay || r >= REFLECTION_LEVEL) {
break;
}
}
col += newCol;
#else
col += scene(p, ray, vignette, 0.0);
#endif
}
}
}
col /= (ANTIALIASING_SAMPLES * ANTIALIASING_SAMPLES * (MOTION_BLUR_LEVEL + 1));
gl_FragColor.rgb = clamp(col.xyz * EXPOSURE, 0.0, 1.0);
gl_FragDepth = min(col.w / MAX_DIST, 0.999);
}