Created
December 9, 2015 12:26
-
-
Save zellyn/d9d52dad24c4f7cb009a to your computer and use it in GitHub Desktop.
Playing with distance fields on shadertoy
This file contains 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
const int MAX_ITER = 100; | |
const float MAX_DIST = 20.0; | |
const float EPSILON = 0.001; | |
struct RayResult { | |
vec3 pos; | |
vec3 normal; | |
float dist; | |
float mindist; | |
float totaldist; | |
}; | |
float sphere(vec3 p, float radius) { | |
return length(p) - radius; | |
} | |
float grid(vec3 p) { | |
p.x = mod(p.x + 0.5, 1.0) - 0.5; | |
p.y = mod(p.y + 0.5, 1.0) - 0.5; | |
return sphere(p, 0.1); | |
} | |
float oldDistFunc(vec3 p) { | |
float g = grid(p); | |
float smaller = min( | |
min(sphere(p-vec3(1.0, 0.0, 0.0), 0.5), | |
sphere(p-vec3(0.0, 1.0, 0.0), 0.5)), | |
min(sphere(p-vec3(-1.0, 0.0, 0.0), 0.5), | |
sphere(p-vec3(0.0, -1.0, 0.0), 0.5))); | |
float spheres = min(g, min(sphere(p, 0.3), smaller)); | |
float floor = p.z + 1.0; | |
return min(spheres, floor); | |
} | |
// start iq primitives | |
// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm | |
float udRoundBox( vec3 p, vec3 b, float r ) | |
{ | |
return length(max(abs(p)-b,0.0))-r; | |
} | |
float sdCylinder( vec3 p, vec3 c ) | |
{ | |
return length(p.xz-c.xy)-c.z; | |
} | |
// end iq primitives | |
float distFunc(vec3 p) { | |
float ground = p.z; | |
float box = udRoundBox(p, vec3(5.0, 0.3, 5.0), 1.0); | |
float cyl = sdCylinder(p, vec3(0.0, 2.0, 2.5)); | |
float holeyBox = max(box, -cyl); | |
// return min(oldDistFunc(p), min(holeyBox, ground)); | |
return min(holeyBox, ground); | |
} | |
vec3 getNormal(vec3 pos){ | |
vec2 eps = vec2(0.0, EPSILON); | |
return normalize(vec3( | |
distFunc(pos + eps.yxx) - distFunc(pos - eps.yxx), | |
distFunc(pos + eps.xyx) - distFunc(pos - eps.xyx), | |
distFunc(pos + eps.xxy) - distFunc(pos - eps.xxy))); | |
} | |
float softShadow(in vec3 ro, in vec3 rd, float mint, float maxt, float k) | |
{ | |
float res = 1.0; | |
float t = mint; | |
for( int i=0; i < 100; i++) | |
{ | |
float h = distFunc(ro + rd*t); | |
res = min(res, max(k*h/t, 0.0)); | |
t += clamp( h, 0.02, 0.3 ); | |
if( h<0.001 || t>maxt ) continue; | |
} | |
return res; | |
} | |
RayResult castRay(vec3 rPos, vec3 rDir){ | |
RayResult result; | |
result.dist=MAX_DIST; | |
result.mindist=MAX_DIST; | |
result.totaldist=0.0; | |
for (int i = 0; i < MAX_ITER; i++) | |
{ | |
if (result.dist < result.mindist) { result.mindist = result.dist;} | |
if (result.dist < EPSILON || result.dist > MAX_DIST) {continue;} | |
result.dist = distFunc(rPos); // Evalulate the distance at the current point | |
result.totaldist += result.dist; | |
rPos += result.dist * rDir; // Advance the point forwards in the ray direction by the distance | |
} | |
result.pos = rPos; | |
result.normal = getNormal(result.pos); | |
return result; | |
} | |
void mainImage( out vec4 fragColor, in vec2 fragCoord ) | |
{ | |
// Copied from | |
// http://www.reddit.com/r/twotriangles/comments/1hy5qy/tutorial_1_writing_a_simple_distance_field/ | |
// and https://www.shadertoy.com/view/MsSGW1 | |
float viewPlaneDistance = 1.5; | |
vec3 cameraOrigin = vec3(-12.0, | |
-9.0, | |
6.0); | |
vec3 cameraWiggle = vec3(0.4 * sin(iGlobalTime/13.0), | |
0.0, | |
1.3 * sin(iGlobalTime/7.0)); | |
cameraOrigin += cameraWiggle; | |
vec3 cameraTarget = vec3(0.0, 0.0, 2.0); | |
vec3 upDirection = vec3(0.0, 0.0, 1.0); | |
vec3 cameraDir = normalize(cameraTarget - cameraOrigin); | |
vec3 cameraRight = normalize(cross(upDirection, cameraOrigin)); | |
vec3 cameraUp = cross(-cameraDir, cameraRight); | |
vec3 lightPos = vec3(2.0, -12.0, 9.0); | |
vec3 lightWiggle = vec3(1.0*sin(iGlobalTime/101.0), | |
3.0*cos(iGlobalTime/3.0), | |
6.0*sin(iGlobalTime/3.0)); | |
lightPos += lightWiggle; | |
// it's a lot easier to work with if we rescale to be between -1 and 1 and correct | |
// the aspect ratio: | |
vec2 screenPos = -1.0 + 2.0 * gl_FragCoord.xy / iResolution.xy; // screenPos can range from -1 to 1 | |
screenPos.x *= iResolution.x / iResolution.y; // Correct aspect ratio | |
vec3 rayDir = normalize(cameraRight * screenPos.x + cameraUp * screenPos.y + viewPlaneDistance * cameraDir); | |
RayResult ray = castRay(cameraOrigin,rayDir); | |
vec3 c; | |
if(ray.dist<EPSILON){ | |
float diffuse = max(0.1, dot(normalize(lightPos-ray.pos), ray.normal)); | |
diffuse *= softShadow(ray.pos, normalize(lightPos-ray.pos), 0.02, 0.5, 8.0); | |
float specular = pow(diffuse, 32.0); | |
c = vec3(diffuse + specular); | |
} else { | |
c = vec3(0.0); | |
} | |
fragColor = vec4(c, 1.0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment