Open edap opened 2 years ago
So I think the main problem here is that you're using dist.abs()
, which means that you could move through the surface without the dist.abs()
ever reaching below eps
and therefore never triggering a hit, and then dist
would start increasing again on the other side so you'd never hit the surface. And the reason it would happen more in the middle is that the relative change in dist.abs()
compared to a change in t
(in calculus terms, the derivative of the distance function with respect to t) is highest when the surface is aligned with the direction of the ray, so the issue of going through the surface is most likely to happen in that case. If you step based on dist
but check whether you are close enough by dist.abs()
then you should avoid this issue well for well defined SDFs. The reason I use always abs in rayn
is that the SDFs of the fractals I was tracing weren't always well defined on the inside of the surface, so doing that isn't always possible.
so your main tracing loop would then look like:
for _march in 0..MAX_MARCHES {
let point = ray.point_at_parameter(t);
let dist = self.sdf.dist(point); // remove abs here
let eps = f32::from(0.00005 * SDF_DETAIL_SCALE).max(f32::from(0.05 * SDF_DETAIL_SCALE));
if dist.abs() < eps { // abs applied for comparison
hit = true;
break;
}
t = t + dist; // this addition can now be negative so you can then approach the surface again
if t > t1 || t.is_nan() {
break;
}
}
Also you will likely need to reevaluate this if you try to do refraction, i.e. have rays that pass through the inside of an SDF, in which case you could special case the tracing loop to negate the distance or something like that.
oh also, one more thing to point out here is that if you're not using a function like half_pixel_size_at
then you may as well get rid of all the fancy calculation of eps to just a constant (maybe times another constant)... right now that whole line should just evaluate to a single constant value anyway since there's no dynamic value in it anymore.
The reason I use always abs in rayn is that the SDFs of the fractals I was tracing weren't always well defined on the inside of the surface, so doing that isn't always possible.
Actually I think I misspoke here and indeed my code likely has the same issue, the real reason I did this was because of the refraction thing I mentioned, and then didn't reevaluate if there was a better way to solve the problem (which there likely is).
Many thanks for your replies. You were correct, using abs() was the error for which the ray was marching through the surface. Removing the abs() fixed partially the error. After reading your comments, I have removed the half_pixel_size_at
to make the example more simple and understand it better. I have to enable a lambert material to debug the issue and see what was happening, therefore the next images are slightly different than the red spheres. This code generates the following image:
impl<S: SDF<f32, Vec3A> + Send + Sync> Hitable for TracedSDF<S> {
fn hit(&self, ray: &Ray, _t0: f32, t1: f32) -> Option<HitRecord> {
let dist = self.sdf.dist(ray.origin).abs();
let mut t = dist;
let mut hit = false;
let eps = 0.0015;
for _march in 0..MAX_MARCHES {
let point = ray.point_at_parameter(t);
let dist = self.sdf.dist(point);
if dist < eps {
hit = true;
break;
}
t = t + dist;
if t > t1 || t.is_nan() {
break;
}
}
if hit {
let normals = self.sdf.normals_fast(eps);
let normal = normals.normal_at(ray.point_at_parameter(t));
return Some(HitRecord {
t,
pos: ray.point_at_parameter(t),
normal,
front_face: true,
mat: &self.mat,
});
} else {
return None;
}
}
}
If I do the comparison using if dist.abs() < eps {
instead of if dist < eps {
as it is in the code listed, the sphere has a hole in the middle, as before, and I suppose for the same reason, the ray is going through without hitting.
Now, I have another weird problem. The radius of the sphere is 0.7. If I make the sphere smaller, like 0.6, it disappear completely.
But, If I add a big green sphere that act as ground, as in the book "Ray Tracer in a Weekend", the shadow of the sphere is there!
If I manage to make a simple raytracer to debug the issue i will upload it. In the meantime, any hints is really appreciated.
Dear Gray, everything works fine, thanks for your detailed answers. You can find a simple example here. https://github.com/edap/sdfu-example/blob/main/src/main.rs
I have a couple of questions (again):
fn bounding_box(&self) -> Option<Aabb> {
Some(Aabb {
min: sdf.translation
- Vec3A::new(radius(),radius(), radius()),
max: sdf.translation
+ Vec3A::new(radius(), radius(), radius()),
})
}
The problem is that I can not read the radius and the position out of `sdfu::sdf.
Hello, I am trying to use this crate in my raytracer that has been written in rust following the first book "raytracer in a weekend" https://raytracing.github.io/books/RayTracingInOneWeekend.html.
Now I would like to add sdf shapes to list of the hittables objects. I have looked at your amazing path tracer
rayn
to see how it is implemented https://github.com/fu5ha/rayn/blob/master/src/sdf.rs but unfortunately my unfamiliarity with SIMD made your code a little hard to read for me. Therefore, I have implemented a classic raymarching function in thehit
function.And I have added a simple sphere to my world.
Unfortunately, something is wrong. The central part of the sphere is missing
The first thing that I have thought is that the sphere is too big and it is clipped out. So I change the radius of the sphere from 1.0 to 0.5. An the sphere disappear completely.
I set the radius back to 1.0, and I increase the epsilon value, so, in the hit function I change this line:
to
With this result.
The "hole" in the middle of the sphere is smaller, but the sphere is also obviously bigger. Of course I have tried a small
eps
, like 0.0015, and this is the result.Now, I think that what it is happening is that the rays closer to the sphere the first time do not hit the sphere, but in the iteration in the raymarching loop
t
becomes too big and it pass through the sphere.In your path tracer, you are multiplying
eps
by a function bounded to the value oft
. https://github.com/fu5ha/rayn/blob/master/src/camera.rs#L210Before to do something similar, I would like to understand if I am doing something wrong in using your library inside a simple ray tracer, as for my understanding a fixed epsilon value should work as well.
Any hints or suggestion is really appreciated.