Hi!
First of all, I want to thank you for such a great book!
I have a question about drawing infinite number of spheres. I can’t full understand how the neat trick works when we make a local copy of the ray. I want imagine it but I can’t.
We loop for a given number of times (steps) to make sure we get enough precision for initial ray. Every time we create a local copy of the initial ray. But what forces our repeatRay do its job separately? I mean, if we create new a repeatRay every time, then where is this loop to handle all calls to the distanceToSphere function?
I think you try ray marching algorithm
A good source of information is
You don’t create a loop because from a position and your repeat function you know which one is the nearest without looking on your collection.
Thanks for the resource. This guy is a genius!
I try to write what I can’t understand:
For instance, we have one pixel before the loop:
Ray ray = Ray(float3(1000.0), normalize(float3(0.2, 0.4, 1.0)));
Next this initial ray enters the loop:
In our first iteration we create the first pairs of repeatRay and Sphere. We get the short distance from function distanceToScene.
To satisfy the condition:
if (distance < 0.001) {
color = float3(1.0);
break;
}
our repeatRay has to call more than one time, I guess. I’m sure I just missed something important in this example
I completely understand example with one Sphere and one Ray, but this one I can’t.
I don’t know what do you mean by repeaRay.
But the ray marching is:
Var r = ray(position, direction)
Var p = position
For(var i=0; i < maxIntersectionSearchCount; i++)
{
Float distance = maxDistance
Foreach(sdfFunction in allMyObject)
{
distance = Min(sdfFunction(p), distance)
}
If (distance < epsilon)
{
Color =….
Break
}
position = position+ distance*direction
}
But for infinite number of a specific object you will not create an infinite transformation object. So your allMyObject will have only one sdfFunction.
Sample for a point:
You will use a reverse function to evaluate only one sdf of point (sqrt(dot(position)).
If you want an infinite point on axis x with a distance between each point = 3.
Which mean point 0: 0, point 1: 3, point 2: 6….
Fx(instance) = 3xinstance.
To retrieve instance from xinstance = xinstance/3
For any x you would like to determine the distance between this x and the nearest point instance. To do that you will transform your x to the instance origin:
So x’ = x - Fx(nearest instance)
Nearest instance = round(x/3)
If x= 5 nearer instance is 2…
x’ = x - 3xround(x/3).
Now your distance is the distance between x’ and the origin which mean sdfpoint(x’) = sqrt(x’x’)
RepeatPointSdf(position 2)=>
Var x’= 2 - 3*round(2/3) = 2-3= -1.
Distance = sdf of point (repeatPositionReverse)
→ 1 for this case.
The thing here you can’t have a random position for your point/objects.
The google term for repeating the spheres is Domain Repetition.
The code is very succinct. Without calling outside functions, it looks like:
for (int i = 0.0; i < MaxSteps; i++) {
// repeat the ray throughout the domain
float3 newOrigin = fmod(ray.origin, 2.0);
// distance to sphere
float distance = length(newOrigin - sphere.center) - sphere.radius;
if (distance < 0.001) {
color = 1.0;
break;
}
// add on the new distance to offset the next repeated ray in the loop
ray.origin += ray.direction * distance;
}
I have replaced repeatRay
with just newOrigin
here.
You may have missed the last line which changes the new repeatRay
in the book code.
I’d really recommend looking at actual values using Metal’s Capture GPU Workload shader debugger.
You capture the GPU workload, and then locate the dispatchThreadgroups command in the navigator. You then click the bug icon to bring up the thread selector. The thread position in grid corresponds to the position in the texture, so it’s quite easy to find the spot in the render you want to trace.
The executed code will then display with the results, and you can follow the for loop through each execution and look at the result.
(In this render I shaded the spheres using the sphere’s normals.)
@hougoul’s recommendation of Inigo Quilez is great. He’s amazing. And shadertoy samples are also good.
This discussion of IQ’s article might help:
The operation here is that you distort space with the modulo operator. So now you have space that repeats – and when you trace rays through this repeated space, you’re basically teleporting the rays back to the origin (using mod in the classic “wrapping around” fashion) every time they pass out of a section of space.
Well, about time I got it:) Thanks to the right approach to debugging I’ve been able to visualize the whole picture in my head.
Thanks a lot;)