Optix 6.5 wireframe rendering

Hi, everybody,

i’m new to Optix (so my question could look trivial from professional point of view). My background is offline and interactive 3D graphics, so i’m just starting to dive into coding.

I’m building the application where one part of the objects should be rendered shaded and its not a problem. But the other part should be rendered as wireframes. Is it possible with OPTIX? May be there is something like OpenGL’s rendering modes(lines, points)?

Thanks in advance

Hi, welcome to OptiX! You can find one example of how to render objects in wireframe in the OptiX SDK sample called “optixCutouts”. The idea there is to optionally ignore intersections unless you’re near the edge of a polygon.

Another option is always to tessellate the wireframe mesh yourself and render that.

Good luck, let us know how it goes!


David.

Thanks for the answer!

Is it standard sample for Optix 6.5? As i cant see it among samples in my Optix 6.5 samples folder.

optixCutouts is an example inside the OptiX SDK 7.0.0.

If you’re starting a new project, I would recommend to use that OptiX version. It’s using a completely different, more modern, faster, and much more flexible API, where all surrounding host code is using CUDA for resource management.

For that faked wireframe idea, all you need to do is to calculate the distance of the barycentric coordinates from the triangle edge and ignore the intersection if it’s too far away.
For constant width “lines” this would need to happen in screen space though.
That idea will break when the visible triangle is smaller than the width obviously.

I wouldn’t use a ray tracer for wireframe rendering if that should use constant screen space line widths.
Just render your wireframes with Vulkan or OpenGL if you’re used to that.

Yes, i will try the approach with OpenGL wireframes.

Would be glad for advice about the right place and approach to compose the openGL render and Optix render.

The OptiX examples normally display the ray traced image with an OpenGL texture blit to the back buffer and then swap.

Before the swap would be the right time to render additional OpenGL primitives into the back buffer.
Depending on how sophisticated you need that, this is more or less trivial.
If it’s enough to just render them on top with no depth testing against the ray traced image, but only against the OpenGL rendering itself, simply clear the depth buffer only and render away. You would need to match the projections of the ray tracer and rasterizer obviously, which is not too difficult with a pinhole camera.
This is how gizmos or other GUI interaction elements would normally be rendered.

If the OpenGL rendering should be depth tested against the ray traced image, things get a little more complicated.
You would need to produce a depth buffer inside the ray tracer which matches the OpenGL depth projection calculations exactly.
You cannot simply use the intersection distance of the primary ray here, because that is a radial distance from the view origin. In OpenGL the z-distance is not radial but on planar planes with z-distance from the view origin. You would need to project the primary hit point world coordinates the same way OpenGL does the whole coordinate pipeline until getting the window z-coordinates. The OpenGL compatibility profile specs explain the necessary calculations in chapter 12.

The result needs to be stored into a buffer which can be copied to the OpenGL depth buffer. This is normally 24 bits fixed point. That copy might get costly though.
Another approach is to use GLSL shaders during the OpenGL rendering and fetch the ray traced depth from a floating point red-component-only texture. Then you wouldn’t need to do any fixed point conversions.

Thanks for so in depth reply, my goals are exactly GUI elements.

What buffers Optix examples are rendering to framebuffer except color and depth as i understood from your reply?

First, OptiX generally accesses CUDA buffers only. You can setup some CUDA-OpenGL interoperability though.
The OptiX SDK examples often do OpenGL interop with a PixelBufferObject (PBO) for the color image display.

More examples doing that with the older OptiX 5/6 API can be found in the OptiX Advanced Samples “Introduction” examples in this thread (search the code for m_interop):
https://forums.developer.nvidia.com/t/optix-advanced-samples-on-github/48410

With OptiX 7.0.0 things are getting more flexible. There you can interop with everything CUDA supports and to other APIs: Vulkan, DX, OpenGL.
For OpenGL that includes PBO, copies into CUDA texture arrays from device-to-device, or directly reading from or writing to surfaces.
Unfortunately the surface access doesn’t seem to be working inside OptiX 7.0.0: https://forums.developer.nvidia.com/t/surf2dread-in-optix-kernel/118601

The OptiX 7.0.0 examples in this post (same thread as above): https://forums.developer.nvidia.com/t/optix-advanced-samples-on-github/48410/4
contains a multi-GPU example which is doing no OpenGL interop (copying to host), PBO interop, and direct copy into CUDA texture array registered from OpenGL.

The no OpenGL interop case is going through the host, which is the simplest and slowest case and what you’d need to start implementing since this is also going to work if there is no NVIDIA OpenGL implementation running on a system to interop with.

Unfortunately none of the examples is rendering a depth buffer. That would really be your task to implement via the same interoperability mechanisms.

Thanks for your advises, I’ve figured out how to render OpenGL things on top of the Optix render, into the back buffer.

I still have a few question about hardware acceleration(intersection and traversal) of this project on RTX cards (all the geometry i use is GeometryTriangles). Optix 6.0 and 6.5:

  1. Is hardware acceleration(intersection and traversal) works without using attribute program (that is not “must” as documentation says)?
  2. What acceleration structure types can i use to get intersection and traversal hardware acc.?
  3. Is there anything that can cause intersection and traversal acceleration not to work if i use GeometryTriangles on RTX card?
  4. Will acceleration(intersection and traversal) be working when scene uses GeometryTriangles and other types of geometry in the same time? May be it will be working only for geometry of GeometryTriangles type in this case?
  5. Is anything i should know know to be sure both intersection and traversal acceleration is working?
  6. Is there a way to check RTX cores workload?

Thank you in advance!

  • Is hardware acceleration(intersection and traversal) works without using attribute program (that is not “must” as documentation says)?

Hardware BVH traversal and triangle intersection are independent of the presence of an attribute program.
The attribute program domain is there to separate state calculations from the intersection program to be able to use the same closesthit program code with different intersection routines. That became necessary because the hardware (HW) triangle intersection only reports barycentric coordinates and you need access to the primitive ID as well and handle the attribute calculation per primitive type.

I would generally recommend to use attribute programs in OptiX 6 because that will automatically defer the vertex attribute calculations to the latest possible time (inside the anyhit or closesthit programs). There are optimizations in OptiX which try to do that automatically in some cases before there were attribute programs
It’s more expensive to calculate these inside custom intersection programs because they are called more often.

In OptiX 7 you need to do that manually inside the anyhit or closesthit anyway and need to use the optixGetHitKind() to distinguish what primitive type was actually intersected if there are multiple intersection programs.

  • What acceleration structure types can i use to get intersection and traversal hardware acc.?

Under OptiX 6 use Trbvh. Then BVH traveral will always be used on RTX boards for any primitive type.
(I’m actually not sure if the Bvh and Sbvh aren’t mapped to the HW BVH traversal as well.)

To get HW triangle intersection you need to to use the built-in GeometryTriangles primitives. That’s all.

In OptiX 7 that is similar. For custom primitives you provide an array of AABB to the AS builder. There exists no bounding box program, you need to handle that. For built-in triangles you only need to provide the triangles array data and optional indices for the topology. There are no BVH builder types to select at all. OptiX picks the one required for the underlying HW and scene structure.

  • Is there anything that can cause intersection and traversal acceleration not to work if i use GeometryTriangles on RTX card?

You cannot actually switch off HW BVH traversal on RTX cards. The two-level AS hierarchy is fully supported in HW.
GeometryTriangles will always result in HW triangle intersections.

Scene hierarchies deeper than two AS from root to geometry as well as motion blur will slightly change the BVH traversal to handle the additional traversal calculations.

  • Will acceleration(intersection and traversal) be working when scene uses GeometryTriangles and other types of geometry in the same time? May be it will be working only for geometry of GeometryTriangles type in this case?

Yes, BVH traversal will always be HW accelerated on RTX boards.
You cannot mix GeometryTriangles and custom primitives in a single AS, so the GeometryTriangles will be running the built-in HW intersection, for the custom primitives the HW BVH traversal will callback to your intersection routine which is run on the streaming multiprocessors (SM). Non-RTX boards will simply run everything on the SMs like it always happened in previous OptiX versions before there was RTX hardware .

  • Is anything i should know know to be sure both intersection and traversal acceleration is working?

Just use GeometryTriangles and you should be good.

  • Is there a way to check RTX cores workload?

Not really, you can’t change it anyway.
You can use Nsight Compute to profile the streaming multiprocessor parts of your application, effectively all OptiX programs you provided. Make sure you compiled your PTX code with --generate-line-info to be able to map instructions to the CUDA input code.
In OptiX 6 there is also a usage report functionality which gives you some coarse information about what happens under the hood. That doesn’t exist in OptiX 7 because there everything is explicit.
For overall application performance analysis, use Nsight Systems first, for example, to see if there are unnecessary overheads when copying data around etc.
To get visual feedback of what takes time in your scene it’s recommended to implement a “time view” feature to your renderer.
Something like this (search the whole repository for USE_TIME_VIEW):
https://github.com/NVIDIA/OptiX_Apps/blob/master/apps/rtigo3/shaders/raygeneration.cu#L169
For people reading this using DXR as well, check this out:
https://devblogs.nvidia.com/profiling-dxr-shaders-with-timer-instrumentation/

Also see these related topics:
https://forums.developer.nvidia.com/t/optix-6-0-rtx-acceleration-is-supported-on-maxwell-and-newer-gpus/70206
https://forums.developer.nvidia.com/t/leveraging-rtx-hardware-capabilities-with-optix-7-0/107733

There is a SIGGRAPH 2019 OptiX 7 Performance Tools and Tricks presentation linked in this post:
https://forums.developer.nvidia.com/t/optix-talks-from-siggraph-2019/80866

Thank you for so in-depth reply!