Begin with what we did last class: sdf.glslify.notes.md · GitHub
… but ignore the perlin noise so that we just have a sphere on the screen.
How do we move a primitive around the screen? We can do this by applying an offset to the current point being sampled by our raytracer. Remember that this point is passed to our doModel function in our shader. Our typical doModel for rendering a sphere is as follows:
vec2 doModel( vec3 p ) {
float radius = 1.;
float dist = length(p) - radius;
return vec2( dist, 0. );
}Offsetting this is done below:
vec2 doModel( vec3 p ) {
float radius = 1.;
vec3 translatedPoint = p + vec3( 1., 0., 0. ); // move on x-axis
float dist = length( translatedPoint ) - radius;
return vec2( dist, 0. );
}We’ll add the following function to our shader for repeating a point over space:
vec3 opRep( vec3 p, vec3 c ) {
vec3 q = mod(p,c)-0.5*c;
return q;
}In the above code, p represents the point being sampled by our raytracer. c determines how often we want to repeat our primitive over space.
To repeat our sphere along the x and y axis using this function:
vec2 doModel( vec3 p ) {
vec3 repeatedPoint = opRep( p, vec3( 3., 3., 0. );
float radius = 1.;
float dist = length( repeatedPoint ) - radius;
return vec2( dist, 0. );
}Here’s the signed distance function for a torus:
float sdTorus( vec3 p, vec2 t ){
vec2 q = vec2(length(p.xz)-t.x,p.y);
return length(q)-t.y;
}The second vec2 determines the outer radius of the ring and the inner radius (the donut hole). To use that in our doModel function:
vec2 doModel( vec3 p ) {
float torus = sdTorus( p, vec2( 1., .5 ) );
return vec2( torus, 0. );
}We can twist a point (rotate it along two axes) with the following function:
vec3 opTwist( vec3 p, float amount ){
float c = cos(amount*p.y);
float s = sin(amount*p.y);
mat2 m = mat2(c,-s,s,c);
vec3 q = vec3(m*p.xz,p.y);
return q;
}To use that in our doModel:
vec2 doModel( vec3 p ) {
vec3 twisted = opTwist( p, 2. );
float torus = sdTorus( twisted, vec2( 1., .5 ) );
return vec2( torus, 0. );
}