Signed Distance Fields

Signed Distance Fields

Further Graphics Ray Marching and Signed Distance Fields Alex Benton, University of Cambridge – [email protected] 1 Supported in part by Google UK, Ltd GPU Ray-tracing Ray tracing 101: “Choose the color of the pixel by firing a ray through and seeing what it hits.” Ray tracing 102: “Let the pixel make up its own mind.” 2 GPU Ray-tracing 1. Use a minimal vertex shader (no transforms) - all work happens in the fragment shader 2. Set up OpenGL with minimal geometry, a single quad 3. Bind coordinates to each vertex, let the GPU interpolate coordinates to every pixel 4. Implement raytracing in GLSL: a. For each pixel, compute the ray from the eye through the pixel, using the interpolated coordinates to identify the pixel b. Run the ray tracing algorithm for every ray 3 GPU Ray-tracing // Window dimensions vec3 getRayDir( uniform vec2 iResolution; vec3 camDir, vec3 camUp, // Camera position vec2 texCoord) { uniform vec3 iRayOrigin; vec3 camSide = normalize( cross(camDir, camUp)); // Camera facing direction vec2 p = 2.0 * texCoord - 1.0; uniform vec3 iRayDir; p.x *= iResolution.x / iResolution.y; // Camera up direction return normalize( uniform vec3 iRayUp; p.x * camSide + p.y * camUp // Distance to viewing plane + iPlaneDist * camDir); uniform float iPlaneDist; } // ‘Texture’ coordinate of each // vertex, interpolated across camUp // fragments (0,0) → (1,1) camDir in vec2 texCoord; camSide 4 GPU Ray-tracing: Sphere Hit traceSphere(vec3 rayorig, vec3 raydir, vec3 pos, float radius) { float OdotD = dot(rayorig - pos, raydir); float OdotO = dot(rayorig - pos, rayorig - pos); float base = OdotD * OdotD - OdotO + radius * radius; if (base >= 0) { float root = sqrt(base); float t1 = -OdotD + root; float t2 = -OdotD - root; if (t1 >= 0 || t2 >= 0) { float t = (t1 < t2 && t1 >= 0) ? t1 : t2; vec3 pt = rayorig + raydir * t; vec3 normal = normalize(pt - pos); return Hit(pt, normal, t); } } return Hit(vec3(0), vec3(0), -1); } 5 An alternative to raytracing: Ray-marching An alternative to classic ray-tracing is ray-marching, in which we take a series of finite steps along the ray until we strike an object or exceed the number of permitted steps. ● Also sometimes called ray casting ● Scene objects only need to answer, “has this ray hit you? y/n” ● Great solution for data like height fields ● Unfortunately… • often involves many steps • too large a step size can lead to lost intersections (step over the object) • an if() test in the heart of a for() loop is very hard for the GPU to optimize 6 GPU Ray-marching: Signed distance fields Ray-marching can be dramatically improved, to impressive realtime GPU performance, using signed distance fields: 1. Fire ray into scene 2. At each step, measure distance field function: d(p) = [distance to nearest object in scene] 3. Advance ray along ray heading by distance d, because the nearest intersection can be no closer than d This is also sometimes called ‘sphere tracing’. Early paper: http://graphics.cs.illinois.edu/sites/default/files/rtqjs.pdf 7 Signed distance fields An SDF returns the minimum possible float sphere(vec3 p, float r) { distance from point p to the surface return length(p) - r; } it describes. The sphere, for instance, is the distance float cube(vec3 p, vec3 dim) { from p to the center of the sphere, vec3 d = abs(p) - dim; minus the radius. return min(max(d.x, max(d.y, d.z)), 0.0) Negative values indicate a sample + length(max(d, 0.0)); inside the surface, and still express } absolute distance to the surface. float cylinder(vec3 p, vec3 dim) { return length(p.xz - dim.xy) - dim.z; } float torus(vec3 p, vec2 t) { vec2 q = vec2( length(p.xz) - t.x, p.y); return length(q) - t.y; } https://www.scratchapixel.com/lessons/advanced-rendering/rendering-distance-fields 8 Raymarching signed distance fields vec3 raymarch(vec3 pos, vec3 raydir) { int step = 0; float d = getSdf(pos); while (abs(d) > 0.001 && step < 50) { pos = pos + raydir * d; d = getSdf(pos); // Return sphere(pos) or any other step++; } return (step < 50) ? illuminate(pos, rayorig) : background; } 9 Visualizing step count Final image Distance field Brighter = more steps, up to 50 10 Combining SDFs We combine SDF models by choosing which is closer to the sampled point. ● Take the union of two SDFs by taking the min() of their functions. ● Take the intersection of two SDFs by taking the max() of their functions. ● The max() of function A and the negative of function B will return the difference of A - B. By combining these binary operations we can create functions which describe very complex primitives. 11 Combining SDFs min(A, B) (union) max(-A, B) (difference) distance max(A, B) (intersection) Object d = zero centers 12 Blending SDFs Taking the min(), max(), etc of two SDFs yields a sharp discontinuity. Interpolating the two SDFs with a smooth polynomial yields a smooth distance curve, blending the models: Sample blending function (Quilez) float smin(float a, float b) { float k = 0.2; float h = clamp(0.5 + 0.5 * (b - a) / k, 0, 1); return mix(b, a, h) - k * h * (1 - h); } http://iquilezles.org/www/articles/smin/smin.htm13 Transforming SDF geometry To rotate, translate or scale an SDF model, apply the inverse transform to the input point within your distance function. Ex: float sphere(vec3 pt, float radius) { return length(pt) - radius; } float f(vec3 pt) { return sphere(pt - vec3(0, 3, 0)); } This renders a sphere centered at (0, 3, 0). More prosaically, assemble your local-to-world transform as usual, but apply its inverse to the pt within your distance function. 14 Transforming SDF geometry float fScene(vec3 pt) { // Scale 2x along X mat4 S = mat4( vec4(2, 0, 0, 0), vec4(0, 1, 0, 0), vec4(0, 0, 1, 0), vec4(0, 0, 0, 1)); // Rotation in XY float t = sin(time) * PI / 4; mat4 R = mat4( vec4(cos(t), sin(t), 0, 0), vec4(-sin(t), cos(t), 0, 0), vec4(0, 0, 1, 0), vec4(0, 0, 0, 1)); // Translate to (3, 3, 3) mat4 T = mat4( vec4(1, 0, 0, 3), vec4(0, 1, 0, 3), vec4(0, 0, 1, 3), vec4(0, 0, 0, 1)); pt = (vec4(pt, 1) * inverse(S * R * T)).xyz; return sdSphere(pt, 1); } 15 Transforming SDF geometry The previous example modified ‘all of space’ with the same transform, so its distance functions retain their local linearity. We can also apply non-uniform spatial distortion, such as by choosing how much we’ll modify space as a function of where in space we are. float fScene(vec3 pt) { pt.y -= 1; float t = (pt.y + 2.5) * sin(time); return sdCube(vec3( pt.x * cos(t) - pt.z * sin(t), pt.y / 2, pt.x * sin(t) + pt.z * cos(t)), vec3(1)); } 16 Find the normal to an SDF Finding the normal: local gradient float d = getSdf(pt); vec3 normal = normalize(vec3( getSdf(vec3(pt.x + 0.0001, pt.y, pt.z)) - d, getSdf(vec3(pt.x, pt.y + 0.0001, pt.z)) - d, getSdf(vec3(pt.x, pt.y, pt.z + 0.0001)) - d)); The distance function is locally linear and changes most as the sample moves directly away from the surface. At the surface, the direction of greatest change is therefore equivalent to the normal to the surface. Thus the local gradient (the normal) can be approximated from the distance function. 17 SDF shadows Ray-marched shadows are straightforward: march a ray towards each light source, don’t illuminate if the SDF ever drops too close to zero. Unlike ray-tracing, soft shadows are almost free with SDFs: attenuate illumination by a linear function of the ray marching near to another object. 18 Soft SDF shadows float shadow(vec3 pt) { vec3 lightDir = normalize(lightPos - pt); float kd = 1; int step = 0; for (float t = 0.1; t < length(lightPos - pt) && step < renderDepth && kd > 0.001; ) { float d = abs(getSDF(pt + t * lightDir)); if (d < 0.001) { kd = 0; } else { kd = min(kd, 16 * d / t); } t += d; By dividing d by t, we step++; attenuate the strength } of the shadow as its return kd; source is further from } the illuminated point. 19 Repeating SDF geometry If we take the modulus of a point’s position along one or more axes before computing its signed distance, then we segment space into infinite parallel regions of repeated distance. Space near the origin ‘repeats’. With SDFs we get infinite repetition of geometry for no extra cost. float fScene(vec3 pt) { vec3 pos; pos = vec3( mod(pt.x + 2, 4) - 2, pt.y, mod(pt.z + 2, 4) - 2); return sdCube(pos, vec3(1)); } 20 Repeating SDF geometry float sphere(vec3 pt, float radius) { return length(pt) - radius; } ● sdSphere(4, 4) = √(4*4+4*4) - 1 = ~4.5 ● sdSphere( ((4 + 2) % 4) - 2, 4) = √(0*0+4*4) - 1 = 3 ● sdSphere( ((4 + 2) % 4) - 2, ((4 + 2) % 4) - 2) = √(0*0+0*0) - 1 = -1 // Inside surface 21 SDF - Live demo 22 Recommended reading Seminal papers: ● John C. Hart, “Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces”, http://graphics.cs.illinois.edu/papers/zeno ● John C. Hart et al., “Ray Tracing Deterministic 3-D Fractals”, http://graphics.cs.illinois.edu/sites/default/files/rtqjs.pdf Special kudos to Inigo Quilez and his amazing blog: ● http://iquilezles.org/www/articles/smin/smin.htm ● http://iquilezles.org/www/articles/distfunctions/distfunctions.htm Other useful sources: ● Johann Korndorfer, “How to Create Content with Signed Distance Functions”, https://www.youtube.com/watch?v=s8nFqwOho-s ● Daniel Wright, “Dynamic Occlusion with Signed Distance Fields”, http://advances.realtimerendering.com/s2015/DynamicOcclusionWithSignedDistanceFields.pdf ● 9bit Science, “Raymarching Distance Fields”, http://9bitscience.blogspot.co.uk/2013/07/raymarching-distance-fields_14.html 23 Supported in part by Google UK, Ltd UK, Google by part in Supported Alex Benton, University of Cambridge – [email protected] – Cambridge of University Benton, Alex 24 More Fun with Rays Further Graphics “Cornell Box” by Steven Parker, University of Utah.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    238 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us