Adding Custom Intersectors to the C++ Ray Tracing Template Library Visionaray
TTechnical Report (2019)
Adding Custom Intersectors to the C++ Ray Tracing TemplateLibrary Visionaray
Stefan Zellmann † Figure 1: Use cases where ray tracing algorithms were extended using custom intersectors. From left to right: billboards, the alpha maskstored in the billboard images is ignored. Second from left: the alpha mask from the billboard images is used to conditionally continue BVHtraversal when the surface has zero opacity near the hit point. Second from right: procedural alpha mask applied using custom intersectors.Right: debug image, the number of BVH nodes and the number of primitives inside the encountered leaf nodes is used to generate a heatmap. This is done by intercepting the BVH traversal routine with a custom intersector that counts the number of ray object interactions.
Abstract
Most ray tracing libraries allow the user to provide custom functionality that is executed when a potential ray surface interactionwas encountered to determine if the interaction was valid or traversal should be continued. This is e.g. useful for alpha maskvalidation and allows the user to reuse existing ray object intersection routines rather than reimplementing them. Augmentingray traversal with custom intersection logic requires some kind of callback mechanism that injects user code into existinglibrary routines. With template libraries, this injection can happen statically since the user compiles the binary code herself. Wepresent an implementation of this “custom intersector” approach and its integration into the C++ ray tracing template libraryVisionaray.
1. Introduction
Typical ray tracing libraries provide a default implementation forsome primitive type—e.g. for triangles—but allow the user to ex-tend the library in several ways. One such way might be supportfor completely new primitive types that behave differently than thedefault primitive type. Often, the functionality that the user desireshowever generally maps to the default primitive type, but is insteadan extension to the default behavior of that type. One such exampleis support for alpha masks to selectively carve out areas from pla-nar surfaces based on a 2-d texture lookup. That functionality canbe implemented by extending the ray primitive intersection rou-tine; the traversal algorithm that tests the ray against a number of † [email protected], Department of Computer Science, University ofCologne surfaces therefore first performs the default intersection test, butinstead of immediately reporting an intersection first performs alookup in the alpha texture and only reports the hit if the lookup in-dicated the primitive was fully opaque at the intersection position.The functionality just described is usually implemented by ex-tending the intersection algorithm which will call some type of call-back mechanism whenever a potential hit was reported, and onlyreport an actual hit if the callback mechanism also reports an in-tersection. A default implementation might just always report anintersection, no matter what the actual intersection position was.This type of interface to the library can for example be found inEmbree [WWB ∗
14] where it is called an intersection filter or inOptiX [PBD ∗
10] where the functionality can be achieved by im-plementing a custom any-hit program .In the context of libraries like Embree or OptiX that the program- a r X i v : . [ c s . G R ] D ec Zellmann / Adding Custom Intersectors to Visionaray mer integrates into her application by means of static or dynamiclinking, this extension mechanism must be evaluated at runtime:the library will perform some type of runtime check if an intersec-tion filter or any-hit program was registered and only execute somecustom functionality if a function pointer or some other means toconditionally execute the user-supplied routine was properly ini-tialized.With template libraries like Visionaray [ZWL17], this check caninstead be performed at compile time and will incur zero cost if nocustom code was supplied by the user. As ray surface intersectionsare evaluated in the innermost loop of the ray tracing algorithm,avoiding additional runtime checks at this phase might improveoverall performance.In contrast to typical ray tracing libraries like Embree or OptiX,Visionaray is a ray tracing template library where most of the func-tionality resides in C++ header files and is directly compiled intothe user’s application. This has the advantage that the code can beinlined and optimized by the compiler in the context of the applica-tion program. The approach also has certain disadvantages, such asincreased compile time for the application programmer, or the factthat the application programer needs to make sure and rely on hercompiler that the program is properly optimized. An advantage ofthe approach however is that code that is not needed is never actu-ally compiled into the application and can thus not have a negativeimpact for example on instruction cache utilization.In this paper we describe the integration of custom intersectors as an application programming interface for static routines that theuser implements and passes to Visionaray at compile time.
2. Related Work
Visionaray provides support for several features that are requiredto develop ray tracing algorithms, such as a streamlined texture in-terface that can be leveraged on both CPUs with vector instruc-tions as well as on NVIDIA GPUs [ZPL15]. Visionaray supportsseveral types of intersection queries, including the multi-hit querytype [ZHL17]. Support for multiple primitive, material or lighttypes in the same ray tracing program is provided by means of com-pile type polymorphism. The effectiveness of that approach wasthoroughly evaluated in [ZL17]. We used Visionaray and its var-ious library subsystems such as the vector math system or SIMDlibrary component to implement several algorithms, e.g. the onesfrom [ZSL18], [ZHL19], [ZSL19], and [ZML19].
3. Integration of Custom Intersectors into Visionaray
In this section we first describe the application programming in-terface (API) by which custom intersectors can be used by the ap-plication programmer, and then provide details about how that wasinternally implemented in the library.
Visionaray has a customization point interface where the user canoverwrite or augment behavior by implementing free functions forcustom types. Custom geometric primitives e.g. can be added by implementing a set of free functions, one of them being the in-tersect function that tests if a ray intersects the primitive: template
Custom intersectors allow to augment the behavior of existing primitive types like triangles; the user may e.g. be perfectly finewith the triangle intersection routine as such (and may also wishto reuse the existing builtin triangle type instead of implementinga completely new one), but wants to add an alpha mask from animage texture.The API for that consists of deriving from the ba-sic_intersector template using the “curiously recurring tem-plate pattern” (CRTP): struct custom_intersector: basic_intersector
The user then implements her own operator() as a memberfunction, with the signature of the intersect function from be-fore, with the ray as first and the custom primitive as second pa-rameter: ...template
Visionaray supports several visibility queries; usually, the ray is ellmann / Adding Custom Intersectors to Visionaray tested against a bounding volume hierarchy (BVH) built over someprimitives, and either the closest hit point (closest-hit query), thefirst encountered hit point (any-hit query), or the first N hit points(multi-hit query) are returned. The interface for the various queriesis similar and exemplarily is presented here for the closest-hitquery: // Default overloadtemplate
Visionaray’s bounding volume implementation that is based on the while-while traversal scheme from [AL09] calls intersect twice. A high-level representation of the traversal scheme lookslike this: procedure
INTERSECT (ray, BVH) while ray not terminated dowhile node is inner do INTERSECT (ray, node.bounds) end while (cid:46)
Found a leaf while node contains untested primitives do HitRecord ← INTERSECT (ray, node.prims++) end whileend whileend procedure
The traversal function, at compile time, is passed the custom inter-sector class, and the two calls to intersect —the one that tests the ray against the bounding box of the BVH nodes and the one thattests against the individual primitives—are statically replaced withthe calls to operator() provided by the custom intersector.Also note how intersect inside the BVH traversal routine isnot only called for each geometric primitive, but also when the rayis tested against the BVH nodes’ bounds (which have type aabb with Visionaray). Custom intersectors thus cannot only be used tointercept the behavior of ray vs. primitive intersection, but also thatof testing rays against BVH nodes. This can be accomplished byadding an operator() overload to the custom intersector thattakes an aabb as second parameter.An implementation detail worth mentioning is that the rayvs. BVH traversal function in Visionaray is also called inter-sect . The reasoning behind this is that the visibility queries( closest_hit , any_hit and multi_hit ) will iterate lin-early over a list, where BVHs may themselves act as (compound)primitives. This allows us to easily implement object instancing,where the BVH will store BVHs as primitives, and where the ob-ject hierarchy may optionally have more than one root node. Con-versely, in certain cases the user might decide that a BVH is notrequired and just pass iterators to a linear list of primitives to thequery routines. Special care is necessary to support this behavior:when the visibility query is executed on a list of primitives thatare not composed into a BVH, the custom intersector replaces therespective call to intersect inside the traveral loop. When thequery is however executed on a list of BVHs, the custom intersec-tor is passed on to the BVH intersection routine, which will replaceits respective calls to intersect . Discerning the two implemen-tations is done at compile time using the “substitution failure is notan error” (SFINAE) pattern.
4. Use Cases
Custom intersectors can e.g. be used to implement the use casesfrom Figure 1. 3-d models often come with separate alpha masksstored in texture images that are used to carve out details from theotherwise coarse geometry that serves as an impostor or a billboard.This can easily be implemented by providing a custom intersectorwhich stores a pointer to the texture and texture coordinate listsas member variables. The custom intersector provides an opera-tor() that intercepts interactions with the surface geometry andperforms a texture lookup using the barycentric coordinates at thehit point to determine if the surface was actually hit. It will thenmanipulate the hit point based on the alpha information from themask texture and only then return the hit record: template
Zellmann / Adding Custom Intersectors to Visionaray tex_coords[hr.prim_id * 3 + 2],hr.u, hr.v);vec4 color = tex2D(tex, coord);hr.hit &= color.w >= .01f;return hr;}
Another use case that is depicted in the second from right imageof Figure 1 is procedural alpha masking which can be implementedin a similar way that alpha masking with texture images is imple-mented, but uses a procedural to determine visibility when passedthe uv coordinates.A third use case that is depicted in the right image of Figure 1is spotting and visualizing performance issues with the intersec-tion routine or the BVH traversal. Therefore, a custom intersectoris implemented that just counts the number of interactions. A fullimplementation might look like this: struct bvh_costs : basic_intersector
5. Conclusion
We presented custom intersectors as a way to augment the raytracing template library Visionaray. Custom intersectors or simi-lar concepts are supported by many ray tracing libraries, but dueto the static and compile time nature of Visionaray, the feature issupported in a unique way that is different from the usual func-tion pointer approach that other libraries implement. We presentedthe API to make use of custom intersectors, some implementa-tion notes, and also some sample implementations that exemplarilypresent how to use that feature with Visionaray.
References [AL09] A
ILA
T., L
AINE
S.: Understanding the efficiency of ray traver-sal on GPUs. In
Proceedings of the Conference on High PerformanceGraphics 2009 (New York, NY, USA, 2009), HPG ’09, ACM, pp. 145–149. 3[PBD ∗
10] P
ARKER
S. G., B
IGLER
J., D
IETRICH
A., F
RIEDRICH
H.,H
OBEROCK
J., L
UEBKE
D., M C A LLISTER
D., M C G UIRE
M., M OR - LEY
K., R
OBISON
A., S
TICH
M.: OptiX: A general purpose ray tracingengine.
ACM Trans. Graph. 29 , 4 (July 2010), 66:1–66:13. 1[WWB ∗
14] W
ALD
I., W
OOP
S., B
ENTHIN
C., J
OHNSON
G. S., E
RNST
M.: Embree: A kernel framework for efficient CPU ray tracing.
ACMTrans. Graph. 33 , 4 (July 2014), 143:1–143:8. 1[ZHL17] Z
ELLMANN
S., H
OEVELS
M., L
ANG
U.: Ray traced volumeclipping using multi-hit BVH traversal. In
Proceedings of Visualizationand Data Analysis (VDA) (2017), IS&T. 2[ZHL19] Z
ELLMANN
S., H
ELLMANN
M., L
ANG
U.: A linear time BVHconstruction algorithm for sparse volumes. In
Proceedings of the 12thIEEE Pacific Visualization Symposium (2019), IEEE. 2[ZL17] Z
ELLMANN
S., L
ANG
U.: C++ compile time polymorphism forray tracing. In
Proceedings of the Conference on Vision, Modeling andVisualization (Goslar Germany, Germany, 2017), VMV ’17, Eurograph-ics Association, pp. 129–136. 2[ZML19] Z
ELLMANN
S., M
EURER
D., L
ANG
U.: Hybrid grids forsparse volume rendering. In
IEEE VIS 2019 - Short Papers (2019). 2[ZPL15] Z
ELLMANN
S., P
ERCAN
Y., L
ANG
U.: Advanced texture fil-tering: a versatile framework for reconstructing multi-dimensional imagedata on heterogeneous architectures. In
Visualization and Data Analy-sis 2015 (2015), Kao D. L., Hao M. C., Livingston M. A., Wischgoll T.,(Eds.), vol. 9397, International Society for Optics and Photonics, SPIE,pp. 110 – 120. 2[ZSL18] Z
ELLMANN
S., S
CHULZE
J. P., L
ANG
U.: Rapid k-d tree con-struction for sparse volume data. In
Eurographics Symposium on ParallelGraphics and Visualization (2018), Childs H., Cucchietti F., (Eds.), TheEurographics Association. 2[ZSL19] Z
ELLMANN
S., S
CHULZE
J. P., L
ANG
U.: Binned k-d tree con-struction for sparse volume data on multi-core and GPU systems.
IEEETransactions on Visualization and Computer Graphics (2019), 1–1. 2[ZWL17] Z
ELLMANN
S., W
ICKEROTH
D., L
ANG
U.: Visionaray: Across-platform ray tracing template library. In