Log Polar Warping of space - Real time ray marching infinite sdf's using shader-doodle. Click and drag the mouse around!
Created
April 21, 2020 13:36
-
-
Save artemuzz/b0a533b67923a0f96462f4ec618f58b4 to your computer and use it in GitHub Desktop.
Mechanic Polar Dream
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- https://github.com/halvves/shader-doodle --> | |
<!-- https://www.osar.fr/notes/logspherical/ --> | |
<shader-doodle> | |
<script type="x-shader/x-fragment"> | |
precision mediump float; | |
#define MAX_STEPS 150. | |
#define MAX_DIST 45. | |
#define MIN_DIST .001 | |
#define PI 3.14159 | |
#define PI2 6.28318 | |
// Change to 2 to for antialiasing | |
#define AA 1 | |
#define ZERO 0 | |
mat2 r2(float a){ | |
float c = cos(a); float s = sin(a); | |
return mat2(c, s, -s, c); | |
} | |
vec3 hsv2rgb( in vec3 c ) { | |
vec3 rgb = clamp(abs(mod(c.x*6.+vec3(0.,4.,2.),6.)-3.)-1., 0., 1.); | |
return c.z * mix(vec3(1.), rgb, c.y); | |
} | |
vec3 get_mouse(vec3 ro) { | |
float x = -(u_mousedrag.y / u_resolution.y * 1. - .5) * PI; | |
float y = -(u_mousedrag.x / u_resolution.x * 1. - .5) * PI; | |
float z = 0.0; | |
ro.zy *= r2(x); | |
ro.xz *= r2(y); | |
return ro; | |
} | |
float sdTorus( vec3 p, vec2 t ) { | |
p.xy *= r2(PI*4.5); | |
p.yz *= r2(PI*4.5); | |
vec2 q = vec2(length(p.xz)-t.x,p.y); | |
return length(q)-t.y; | |
} | |
float sdBox( vec3 p, vec3 b ) { | |
vec3 q = abs(p) - b; | |
return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0); | |
} | |
float smin( float d1, float d2, float k ) { | |
float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 ); | |
return mix( d2, d1, h ) - k*h*(1.0-h); | |
} | |
float shorten = 1.16; | |
float density = 10.; | |
vec4 map(in vec3 p) { | |
float thickness = 0.035; | |
float lpscale = floor(density)/PI; | |
vec2 res = vec2(100.,0.); | |
// forward log-spherical map | |
float r = length(p); | |
p = vec3(log(r), acos(p.z / length(p)), atan(p.y, p.x)); | |
// scaling factor to compensate for pinching at the poles | |
float xshrink = 1.0/(abs(p.y-PI)) + 1.0/(abs(p.y)) - 1.0/PI; | |
// fit in the ]-pi,pi] interval | |
p *= lpscale; | |
p.x -= u_time *.35; | |
p.z += u_time *.45; | |
// tile coordinates | |
vec3 pi = floor((p + 1.)/2.); | |
p = mod(p+1.,2.) - 1.; | |
p.x *= xshrink; | |
float pole = length(p.xz) - thickness; | |
pole = min(length(p.yx) - thickness, pole); | |
if(pole<res.x) res = vec2(pole,3.); | |
p.xz *= r2(u_time*.5); | |
float ret = sdBox( abs(p)-vec3(0.,.5,0.), vec3(.2,.01,.2) ); | |
ret = min(sdBox( abs(p)-vec3(0.,.5,0.), vec3(.2,.2,.01) ),ret); | |
ret = min(sdBox( abs(p)-vec3(0.,.5,0.), vec3(.01,.2,.2) ),ret); | |
if(ret<res.x) res = vec2(ret,1.); | |
float rings = sdTorus( p.yzx, vec2(.5,thickness) ); | |
rings = min(sdTorus( p.zxy, vec2(.5,thickness) ),rings); | |
if(rings<res.x) res = vec2(rings,2.); | |
// compensate for the scaling that's been applied | |
float mul = r/lpscale/xshrink; | |
float d = res.x * mul / shorten; | |
return vec4(d,res.y, pi.xz); | |
} | |
vec3 get_normal(in vec3 p) { | |
float d = map(p).x; | |
vec2 e = vec2(.01,.0); | |
vec3 n = d - vec3( | |
map(p-e.xyy).x, | |
map(p-e.yxy).x, | |
map(p-e.yyx).x | |
); | |
return normalize(n); | |
} | |
vec4 get_ray( in vec3 ro, in vec3 rd ) { | |
float depth = 0.; | |
float mate = 0.; | |
float m = 0.; | |
vec2 bi = vec2(3.); | |
for (float i = 0.; i<MAX_STEPS;i++) { | |
vec3 pos = ro + depth * rd; | |
vec4 dist = map(pos); | |
mate = dist.y; | |
bi = dist.zw; | |
if(dist.x<.0001*depth) break; | |
depth += abs(dist.x*.65); // hate this but helps edge distortions | |
if(depth>MAX_DIST) { | |
depth = MAX_DIST; | |
break; | |
} | |
} | |
return vec4(depth,mate,bi); | |
} | |
float get_diff(vec3 p, vec3 lpos) { | |
vec3 l = normalize(lpos-p); | |
vec3 n = get_normal(p); | |
float dif = clamp(dot(n,l),0. , 1.); | |
float shadow = get_ray(p + n * MIN_DIST * 2., l).x; | |
if(shadow < length(p - lpos)) { | |
dif *= .1; | |
} | |
return dif; | |
} | |
vec3 get_color(float m, vec2 bi){ | |
vec3 mate = vec3(.2); | |
if(m==1.) { | |
if(mod(bi.y,2.)<.1){ | |
mate = hsv2rgb(vec3(.25+bi.x*.1,1.,.5)); | |
}else{ | |
mate = hsv2rgb(vec3(.5+bi.x*.1,1.,.5)); | |
} | |
} | |
if(m ==2.) mate = hsv2rgb(vec3(bi.x*.1,1.,.5)); | |
if(m ==3.) mate = vec3(1.1,1.3,1.3); | |
return mate; | |
} | |
vec3 render( in vec3 ro, in vec3 rd, in vec2 uv) { | |
vec3 color = vec3(0.0); | |
vec3 fadeColor = vec3(.1,.15,.20); | |
vec4 ray = get_ray(ro, rd); | |
float t = ray.x; | |
vec2 bi = ray.zw; | |
vec3 lcolor, dcolor, ccolor; | |
if(t<MAX_DIST) { | |
vec3 p = ro + t * rd; | |
vec3 tint = get_color(ray.y,ray.zw); | |
lcolor = vec3(.4,.4,.5); | |
dcolor = vec3(.4,.3,.4); | |
ccolor = vec3(.3,.3,.28); | |
vec3 lpos1 = vec3(-.5, 13.45, 3.0); | |
vec3 lpos2 = vec3(-1.5, 12.21, .1); | |
vec3 lpos3 = vec3(12.5, -11., -1.5); | |
vec3 diff1 = dcolor * get_diff(p, lpos1); | |
vec3 diff2 = lcolor * get_diff(p, lpos2); | |
vec3 diff3 = ccolor * get_diff(p, lpos3); | |
vec3 diff = diff1 + diff2 + diff3; | |
color += tint * diff; | |
} | |
//iq - saw it in a tutorial once | |
color = mix( color, fadeColor, 1.-exp(-0.005*t*t*t)); | |
return pow(color, vec3(0.4545)); | |
} | |
vec3 ray( in vec3 ro, in vec3 lp, in vec2 uv ) { | |
vec3 cf = normalize(lp-ro); | |
vec3 cp = vec3(0.,1.,0.); | |
vec3 cr = normalize(cross(cp, cf)); | |
vec3 cu = normalize(cross(cf, cr)); | |
vec3 c = ro + cf * .87; | |
vec3 i = c + uv.x * cr + uv.y * cu; | |
return i-ro; | |
} | |
void main( void ) { | |
vec3 color = vec3(0.); | |
vec2 uv; | |
// | |
#if AA>1 | |
for( int m=ZERO; m<AA; m++ ) | |
for( int n=ZERO; n<AA; n++ ) | |
{ | |
// pixel coordinates | |
vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5; | |
uv = (2. * gl_FragCoord.xy - (u_resolution.xy+o))/u_resolution.y; | |
#else | |
uv = (2. * gl_FragCoord.xy - u_resolution.xy )/u_resolution.y; | |
#endif | |
// ray origin / look at point | |
vec3 lp = vec3(-0.5,0.1,0.); | |
vec3 ro = vec3(-0.15,-1.5,-2.15); | |
ro = get_mouse(ro); | |
// get ray direction | |
vec3 rd = ray(ro, lp, uv); | |
color += render(ro, rd, uv); | |
// AA from NuSan | |
#if AA>1 | |
} | |
color /= float(AA*AA); | |
#endif | |
gl_FragColor = vec4(color,1.0); | |
} | |
</script> | |
</shader-doodle> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Click and drag the ball around yo! | |
Experiments in Log Polar Warping - good read here! | |
https://www.osar.fr/notes/logspherical/ | |
Zero webgl boilerplate, its all handled by shader-doodle. | |
https://github.com/halvves/shader-doodle | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://unpkg.com/[email protected]"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html { | |
font-size: 100%; | |
height: 100%; | |
} | |
body { | |
width: 100vw; | |
height: 100vh; | |
background: rgb(55, 55, 55); | |
overflow: hidden; | |
} | |
shader-doodle { | |
display: flex; | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
bottom: 0px; | |
left: 0; | |
} | |
.info { | |
position: absolute; | |
font-family: "Righteous", cursive; | |
bottom: 10px; | |
right: 10px; | |
color: #fff; | |
text-shadow: 0 0 13px rgba(0, 0, 0, 0.5); | |
font-size: 0.95rem; | |
white-space: nowrap; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment