0% found this document useful (0 votes)
2 views

1. Ray Marching and Signed Distance Fields

The document discusses GPU ray-tracing and ray-marching techniques, focusing on the use of signed distance fields (SDFs) for improved performance in rendering. It explains the principles of ray-marching, how to implement SDFs, and techniques for combining and transforming SDF geometry. Additionally, it highlights methods for achieving shadows and repeating geometry using SDFs, along with recommended readings for further exploration of the topic.

Uploaded by

Muhammad Farhan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

1. Ray Marching and Signed Distance Fields

The document discusses GPU ray-tracing and ray-marching techniques, focusing on the use of signed distance fields (SDFs) for improved performance in rendering. It explains the principles of ray-marching, how to implement SDFs, and techniques for combining and transforming SDF geometry. Additionally, it highlights methods for achieving shadows and repeating geometry using SDFs, along with recommended readings for further exploration of the topic.

Uploaded by

Muhammad Farhan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

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; }

camUp
// ‘Texture’ coordinate of each
// vertex, interpolated across
// fragments (0,0) → (1,1) camDir
in vec2 texCoord;
ca
mS
id
e

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.htm
13
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

You might also like