[OptiX 7.6] Questions for Opacity Micro-Map Array

Hello,

I noticed OptiX 7.6 seemed to be (somewhat silently) released a bit while ago.
Now I’m trying to extend my wrapper library to support Opacity Micro-Map feature, but the documentation is still stucked at 7.5.

I have several questions:

  1. Is a geometry able to have per-triangle different subdivision-level, format (even no-OMM included)?
  2. Is the number of entries in OptixOpacityMicromapArrayBuildInput::perMicromapDescBuffer the same as the number of triangles of a geometry to which the OMM array bound? Or is this independent of a mesh and should this match to the sum of the counts in micromapHistogramEntries?
  3. e.g.) A mesh has 4 triangles, A, B, C, D. I’d like to set OMMs like
    A: no-OMM
    B: OMM level-3 (64 micro-tris), 4-states (2-bit)
    C: OMM level-4 (256 micro-tris), 4-states (2-bit)
    D: OMM level-3 (64 micro-tris), 4-states (2-bit)
    In this case
    – Is the size of the raw OMM array 96 bytes (64x2 + 256x2 + 64x2 [bits])?
    – Is there any per-micromap alignment requirement?
    – Are the entries of perMicromapDescBuffer like:
    0: byteOffset: 0, format: OPTIX_OPACITY_MICROMAP_FORMAT_NONE (Is this not needed if OMM array is independent of a mesh?)
    1: byteOffset: 0, format: OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE, subdivisionLevel: 3
    2: byteOffset: 16, format: OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE, subdivisionLevel: 4
    3: byteOffset: 80, format: OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE, subdivisionLevel: 3
    ?
    – Are the entries of micromapHistogramEntries like:
    0: format: OPTIX_OPACITY_MICROMAP_FORMAT_NONE, count: 0 (Is this not needed as well?)
    1: format: OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE, subdivisionLevel: 3, count: 2
    2: format: OPTIX_OPACITY_MICROMAP_FORMAT_4_STATE, subdivisionLevel: 4, count: 1
    ?

Thanks,

I’ll ask what’s up with the online documentation.

In the meantime please have a look into the doc folder of your local OptiX SDK 7.6.0 installation.
The Programming Guide chapter 5.11 explains Opacity Micromaps.
That and the two examples optixOpacityMicromap and optixCutouts show answers to your questions.

Latter uses different sub-division levels for different triangles (the checkerboard ones and the circular cutout),

The Programming Guide and optixCutouts answers question 2. It’s the sum of counts in the histogram.

That example also shows how to use OMM indices per triangle with OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_INDEXED which allows setting whole triangles to one of the four predefined states. Look for the ommIndices array inside optixCutouts.cpp.
(Your triangle A would use OPTIX_OPACITY_MICROMAP_PREDEFINED_INDEX_FULLY_OPAQUE or OPTIX_OPACITY_MICROMAP_PREDEFINED_INDEX_FULLY_TRANSPARENT then.)

There is an alignment restriction for the OMM array buffers:
#define OPTIX_OPACITY_MICROMAP_ARRAY_BUFFER_BYTE_ALIGNMENT 128ull
See OptixOpacityMicromapArrayBuildInput and optixOpacityMicromapArrayRelocate.
The OMM input data itself is byte aligned. (See OptixOpacityMicromapDesc and optixCutouts.cpp lines 963 - 965)

EDIT (Correction): OPTIX_OPACITY_MICROMAP_FORMAT_NONE is an invalid format. It should never be used. It just reserves the 0 value for the default initialization.
Per triangle indices into the OMM arrays must either be one of the four predefined values or an index to one of the OMM in that array.

The SDK examples only show procedural opacity where the state of the subdivision micro triangles is hardcoded in a checkerboard pattern or derived from a simple procedural circle formula. We’re working on some tools which allow generating OMMs from textures and arbitrary opacity functions.

ah, I have completely forgotten the offline documentation!
I’ll take a look. Thanks.

The online documentation has been updated to OptiX 7.6.0 now.

1 Like

omm_levels

I could confirm that the OMM now works correctly with OMM index buffer.

I got questions for the case without an index buffer.
When we have the index buffer, the number of OMMs in the OMM array is decoupled with the number of triangles in a mesh. So, for example we can have 17 OMMs for 20-tri mesh (3 triangles specify some pre-defined OMM indices).

  • Do we need one OMM for every triangle?
  • The programming guide says:
    The descriptors in the input buffer don't need to appear in any particular order, as long as the counts match the input histogram.
    Is this still valid? Do we have some constraints in the order of raw OMM array or OMM descriptors?
  • Is there any performance guideline for index vs no index?

Thanks,

Awesome visualization. That is exactly how it’s meant to work.

Do we need one OMM for every triangle?

Yes, OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_LINEAR needs one OMM per triangle, see the explanation in OptixOpacityMicromapArrayIndexingMode
“An implicit linear mapping of triangles to opacity micromaps in the opacity micromap array is used. triangle[i] will use opacityMicromapArray[i].”

The programming guide says:
The descriptors in the input buffer don't need to appear in any particular order, as long as the counts match the input histogram.
Is this still valid? Do we have some constraints in the order of raw OMM array or OMM descriptors?

Hmm, that particular sentence is probably only talking about the part building the histogram which doesn’t care about the order.
The OMM array itself would of course need to match the order of the triangle primitives in linear mode.

Is there any performance guideline for index vs no index?

I haven’t seen any performance comparisons between the two methods. If all triangles inside a mesh need OMMs, then I wouldn’t expect much of a difference between indexed and linear mode. It’s at most the index read more in the indexed case. This all runs in hardware on Ada boards anyway.

The envisioned use case is pretty much exactly your example above. Few triangles build some complex cutout opacity and the OMMs prevent callbacks into the anyhit program for everything except the micro triangles with unknown opacity, in your case at the borders of the leaves.
That case also wouldn’t need indexing because all of the big triangles need an OMM anyway. Using the linear mode for that would make perfect sense.

If not all triangles inside a mesh are affected by cutout opacity, that is, individual triangles can be marked with the fully transparent or fully opaque flags, that would obviously save all the trivial OMMs (subdivision level 0) you’d need for them in the linear indexing case.

Thanks for the reply.

The OMM array itself would of course need to match the order of the triangle primitives in linear mode.

I was thinking about a possibility that OptiX runtime internally reorders input raw OMMs according to the order of descriptors, but if OptiX doesn’t change the input order, now this makes sense.

Now all clear for OMM.
I’ll mark this issue as resolved.
Thanks!

Additional questions for OMM.

  • OMM supports 16-bit or 32-bit index. For example for 16-bit index, is the valid range for “normal” index 0 - 65531 (UINT16_MAX minus 4 pre-defined indices) or 0 - 32767 (INT16_MAX)?

According to the docs its 0 - 32767 (INT16_MAX).

The OPTIX_OPACITY_MICROMAP_PREDEFINED_INDEX_… indices are negative and the OptixBuildInputOpacityMicromap says int16 or int32:

typedef struct OptixBuildInputOpacityMicromap
{
...
    /// int16 or int32 buffer specifying which opacity micromap index to use for each triangle.
    /// Instead of an actual index, one of the predefined indices
    /// OPTIX_OPACITY_MICROMAP_PREDEFINED_INDEX_(FULLY_TRANSPARENT | FULLY_OPAQUE | FULLY_UNKNOWN_TRANSPARENT | FULLY_UNKNOWN_OPAQUE)
    /// can be used to indicate that there is no opacity micromap for this particular triangle 
    /// but the triangle is in a uniform state and the selected behavior is applied 
    /// to the entire triangle.
    /// This buffer is required when #OptixBuildInputOpacityMicromap::indexingMode is OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_INDEXED.
    /// Must be zero if #OptixBuildInputOpacityMicromap::indexingMode is 
    /// OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_LINEAR or OPTIX_OPACITY_MICROMAP_ARRAY_INDEXING_MODE_NONE.
    CUdeviceptr  indexBuffer;
...
};

Thanks. We may want to have clear description in the document in addition to the header file.