The canonical OGeo instance resides in OScene and is instanciated and has OGeo::convert called from OScene::init. OGeo::convert loops over the GMergedMesh within GGeo/GGeoLib converting them into optix::Group or optix::GeometryGroup and adds them to m_top(optix::Group).

The first ridx 0 GMergedMesh is non-instanced, the rest are instanced and hold the necessary transform and identity buffers.

Details of geometry tree are documented with the OGeo::convert method.

OGeo Details

Table 2, OptiX Manual

Parent Node Type Child Node Types Associated Node Types
Geometry None Material
Acceleration None  
GeometryInstance Geometry Material
GeometryGroup GeometryInstance Acceleration
Transform GeometryGroup  
Selector Transform  
Group GeometryGroup Acceleration
  • Group contains : rtGroup, rtGeometryGroup, rtTransform, or rtSelector
  • Transform houses single child : rtGroup, rtGeometryGroup, rtTransform, or rtSelector (NB not GeometryInstance)
  • GeometryGroup is a container for an arbitrary number of geometry instances, and must be assigned an Acceleration
  • Selector contains : rtGroup, rtGeometryGroup, rtTransform, and rtSelector

Geometry tree that allows instance identity

JUNO has 6 repeated pieces of geometry. The two different types of photomultiplier tubes (PMTs) are by far the most prolific with 20k of one type (20inch) and 36k of another (3inch)

The geometry tree follows that show in OptiX 6.0.0 manual Fig 3.4 x6

m_top                  (Group)             m_top_accel
   ggg                 (GeometryGroup)        m_ggg_accel           global non-instanced geometry from merged mesh 0
      ggi              (GeometryInstance)

   assembly.0          (Group)                m_assembly_accel      1:1 with instanced merged mesh (~6 of these for JUNO)

         xform.0       (Transform)                                  (at most 20k/36k different transforms)
           perxform    (GeometryGroup)
              accel[0]                            m_instance_accel  common accel within each assembly
              pergi    (GeometryInstance)                           distinct pergi for every instance, with instance_index assigned
                 omm   (Geometry)                                   the same omm and mat are child of all xform/perxform/pergi
                 mat   (Material)

         xform.1       (Transform)
           perxform    (GeometryGroup)
              pergi    (GeometryInstance)
                 omm   (Geometry)
                 mat   (Material)

         ... for all the many thousands of instances of repeated geometry ...

   assembly.1          (Group)                  (order ~6 repeated assemblies for JUNO)
        ... just like above ...
  • transforms can only be contained in “group” or another transform so add top level group with another acceleration structure
  • transforms must be assigned exactly one child of type rtGroup, rtGeometryGroup, rtTransform, or rtSelector,

Alternate Tree Layout


OptiX 7 terminology change

OptiX 7 changes terminology in a way which may inform concerning which trees can be handled in RT cores

  • Geometry Group -> Geometry AS (only primitives)
  • Group -> Instance AS
  • Transform -> just input to Instance AS at build

Why proliferate the pergi ? So can assign an instance index to it : ie know which PMT gets hit

  • Need to assign an index to each instance means need a GeometryInstance beneath the xform ?
  • “Geometry” and “Material” can also hold variables, but that doesnt help for instance_index
    as there is only one geometry and material instance for each assembly

Could the perxform GeometryGroup be common to all ?

NO, needs to be a separate GeometryGroup into which to place the distinct pergi GeometryInstance required for instanced identity

Where to put the RayLOD Selector ? RAYLOD IS NOT CURRENTLY IN USE

  • LOD : Level Of Detail
    • level0 : most precise/expensive used for ray.origin inside instance sphere
    • level1 : cheaper alternative used for ray.origin outside instance sphere

The RayLOD idea is to switch geometry based on the distance from it, using radius of outermost solid origin centered bounding sphere with safety margin see notes/issues/can-optix-selector-defer-expensive-csg.rst

Given that the same omm is used for all pergi… it would seem most appropriate to arrange the selector in common also, as all instances have the same simplified version of their geometry too..

TODO: Currently all the accelerations are using Sbvh/Bvh. Investigate if container groups might be better as “pass through” NoAccel as the geometryGroup and groups they contain have all the geometry.


Converts the GMergedMesh instances from (m_geolib)GGeoLib into optix::Group and optix::GeometryGroup and adds them to m_top(optix::Group).


The GParts instance that this operates from will usually have been concatenated from multiple other GParts instances, one for each NCSG solid. GParts concatenation happens during GMergedMesh formation in GMergedMesh::mergeVolumeAnalytic.

For repeated geometry note how all bar one of the geometry buffers are small. Only the idBuf is large and usage GPU side requires use of the instance_index.