Open marcardenas opened 6 months ago
I'm looking for the same thing, and I'm not having a lot of success trying to calculate this myself.
I was hoping I could use a BoxStencil
or GradStencil
to get the gradient, by calculating the world-space intersection (auto ws = ray.eye() + t0 * ray.dir()
) and transforming that to index-space coordinates (is = grid->worldToIndex(is)
) then querying the stencil (stencil.moveTo(is); gradient = stencil.gradient()
), but using GradStencil
produces a compiler error error: no instance of function template "nanovdb::math::RoundDown" matches the argument list
and using BoxStencil
I get a gradient but it seems to be quantized to the index-space grid. Maybe I'm missing something about how these stencils work?
Edit:
It seems I'm probably not even understanding how nanovdb::math::ZeroCrossing
works, because when plotting just the z-coordinate obtained by ray.eye() + t0 * ray.dir()
I see the values are quantized to the voxel grid, ie: if I have a 100x100x100 VDB and raytrace it at 1024x1024 resolution using fractional x,y coordinates, it looks like the intersection is calculated using nearest-neighbor sampling and not interpolated in any way? Is this intentional?
Edit2:
Indeed it seems the t0
returned by nanovdb::math::ZeroCrossing
is always an integer value (at least for my VDB with voxel size = 1.0f), which makes it pretty much useless for tracing a level set.
After studying the NanoVDB documentation & code a little bit more I think I now understand how these are supposed to work.
@marcardenas
As I understand it, the NanoVDB intersector (nanvodb::math::ZeroCrossing
) is just the HDDA and it will get you an intersection t0
at voxel resolution (the documentation mentions this: t0
and v
will receive the intersection time and grid value of the voxel behind the intersection). This means that to get the actual surface intersection time/coordinates, and subsequently from that the interpolated gradient, you will have perform some iterative approximation along the ray, sampling distance values to determine the iteration step. I use a 2x2x2 sampler created by nanovdb::math::createSampler<1>
for sampling distance values and gradients.
I had some success with this approach using a very simple iterative approximation that steps along the ray, in the direction towards the surface as determined by the distance value (negative distance = reverse direction, positive distance = forward direction), halving the step size at each iteration, up to at most 8 steps). The resulting coordinates I use to sample the gradient. This seems to work well for interior points but not for edges of the level-set, as nanovdb::math::ZeroCrossing
also returns true for rays that hit a zero-crossing voxel but not actually hit the level-set surface (at least that's my analysis right now).
So all in all it seems the NanoVDB raytracing interfaces are lower level than OpenVDB (which makes sense I guess) and you will have to do more work to get what you want. It would be nice if either the documentation would mention some of this, even better if there was an example of some very simple raytracer that just uses primary rays and shades intersections using ray.dot(normal)
.
Hi all!
Is there any way to compute normal after intersecting ray in a level set grid in NanoVDB? OpenVDB's LevelSetRayIntersector provides a method called intersectsWS() which among other return values, provides you with the normal vector.
Thanks