Disabling Back Face Culling on Linear Curve Primitives

Hello, I am with a research group implementing physically accurate GPU accelerated simulations for light in biological tissues. I am trying to implement ray tracing of linear curve primitives, and for this I will need to trace intersections of rays originating from inside the linear curve primitives. Is there a feature that can disable back-face culling, and is it present in OptiX 7.6.0?

Best,
Aiden

Hi @AidenLewis,

Currently through OptiX 7.7 as well as the next unreleased version of OptiX, the curve primitives (including linear) are always as ‘backface culled’ as possible meaning that rays originating from inside the curve primitive will try to ‘exit’ without hitting the primitive surface. Only rays originating from outside the surface will register hits when the rays ‘enter’ the surface. This exit-culling isn’t really guaranteed, it’s more of a best-effort, and it happens to help a lot with issues like self-shadowing. Our curve primitives are designed primarily for far-away viewing, for hair rendering or something similar (fur, carpet, fuzzy cloth, etc.), where the curves are typically the width of a few pixels down to sub-pixel size on-screen.

Adding some API to disable the exit culling is something we can consider, but just to be honest, it could take a while to decide, and implement, and release. You are the first person to request it. ;) We would need time to discuss the feasibility, and of course I can’t guarantee we’d agree to it, in part because it might not be feasible for the cubic and quadratic primitive types. One alternative might be to design a custom primitive intersection program that handles the shape & culling behavior you need.

I’m curious to hear more about what you need, if you’re able & willing to share such info. Do you need exit hits for handling refractions? Are the capsule shaped OptiX linear primitive exactly what you need, or will they approximate a curved surface? If you’re modeling tubular structures with them, then presumably you’d chain them end-to-end similar to what we do in our hair sample? In that scenario, rays originating from inside one primitive might hit the endcap of a neighboring primitive before they hit the inside surface of the enclosing capsule. Do you expect to encounter that, and would you need to do something special to handle that situation? Do you need to try to guarantee that all rays will stop at an exit point, or will catching “most” of them be sufficient?

–
David.

To give a simple summary:
Our program is stepping rays through different 3D volumes of materials and re-launching them in random directions with step sizes based on the underlying properties of the materials. At each step, data on volumetric absorption of the light ray is saved.

We are implementing this by using primitives to bound the different materials, and using closest_hit to quickly search for material changes as the rays move around. The long term idea is to use NVIDIA hardware to accelerate very complex biological geometries like 3D blood vessel networks which would be slow to model and ray trace without primitives and acceleration structures.

Currently we implemented spheres superimposed on a mesh defined by closed surfaces of OptiX triangles. The simulation logic is that the implicitly defined geometries just override the properties of any underlying triangle meshes. This means that intersections from primitive to primitive should not make a difference.

My impression was that we could chain together segments of the linear curves defined by 2 vertices, to create approximations of biological tubular structures. If we can trace back-facing hits on the linear curve the same way as spheres, this should work. Is it feasible to create a custom primitive that works almost identically to linear curves but does not have back-face culling?

Thanks, I will take this info to the team and we’ll talk about the feasibility of exposing exit hit behavior in the API. Yes, it’s possible to do what you want with a custom primitive. Would it work in your case if you had to specify in your optixTrace() call whether you wanted enter or exit hits, and you could only choose one at a time? (I think this implies that your code would need to know whether you were originating inside or outside of a primitive.)

–
David.

Yes, that should work as we are tracking whether or not the rays are originating inside the primitives.

To follow up, I am thinking of modifying our closesthit program to check for intersections with curve primitives, then loop through a custom ray tracing function until the ray exits the curve or enters a new curve.

What would be the most efficient/easiest way to obtain the primitive type and data for a closesthit? Would optixGetLinearCurveVertexData() work for this application?

To follow up, I am thinking of modifying our closesthit program to check for intersections with curve primitives, then loop through a custom ray tracing function until the ray exits the curve or enters a new curve.

That sounds strange and would basically need to calculate the ray intersections with the backfaces of the linear curves, and if you can do that, it would make much more sense to implement that inside a custom intersection program for the geometric primitive behavior you require. Then the rest of your ray tracing algorithms wouldn’t need to change at all.

What would be the most efficient/easiest way to obtain the primitive type and data for a closesthit? Would optixGetLinearCurveVertexData() work for this application?

That OptiX device function fetches linear curve vertex data directly from the acceleration structure (AS).
That is one way to do it but only works if the AS was built with OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS
Find more explanations inside this OptiX Programming Guide chapter https://raytracing-docs.nvidia.com/optix7/guide/index.html#curves#curves-and-the-hit-program

The other way would be to store the vertex attributes into device buffers (where you needed the vertex positions anyway to build the AS) and then fetch each intersected primitive’s attributes from those device buffers with the proper pointers and the intersected primitive ID.
For example, I’m doing that for cubic B-spline curves here: https://github.com/NVIDIA/OptiX_Apps/blob/master/apps/MDL_renderer/shaders/hit.cu#L1314

That example is using a specific closest hit program for these curve primitives because the MDL shader is different for hair, so it knows what primitive type it intersected.

But if you want to reuse the same closest hit program for different geometric primitives, means the Shader Binding Table has hit records with different intersection programs but the same closest hit program, you use the optixGetHitKind information to determine which primitive type you hit via optixGetPrimtiveType
The same hit kind result also allows checking for the face side when the primitive supports it (built-in triangles and spheres do).
Inside the hit kind there are some values (0 - 127) reserved for custom primitives, which you can use inside optixReportIntersection to communicate what custom primitive type was intersected and on which side if you need that.
See: https://raytracing-docs.nvidia.com/optix7/guide/index.html#device_side_functions#intersection-information

Hi @dhart,

I am very glad to find this topic! I am using a microscopic cloth model with Optix and have also encountered the requirement of disabling backface culling. The model focuses on micro-geometry of fibers and it works well with Embree before, which provides API to switch off backface culling. Can I ask if you have any plans for adding a similar API now? Thanks. :)

Best,
Chenghao

Hi @chenghao.wu-2, welcome!

Are you also looking at using primarily the linear curves in OptiX, or are you asking about cubic or quadratic curves?

The very best advice I can give right at this moment is probably to consider writing an intersection program that handles the cases you need. I don’t know yet if OptiX curves will support disabling backface culling in the future, but currently they do not. I can say that even if we did support both enter-hit and exit-hit queries, our curve types still may not be designed to handle what you need. Note how at the top of the thread I mentioned that exit-culling is not guaranteed. We designed this primitive around common needs for games and film, with fur and hair specifically in mind, and these primitives might not work well for the kinds of use cases mentioned in this thread, with microscopic and/or volumetric simulation that has high accuracy requirements and needs to essentially support inside/outside testing for any given point along a ray.

–
David.

1 Like