rtcBuildBVH(3)
π NAME π
rtcBuildBVH β builds a BVH β¨
like, this is the Embree Ray Tracing Kernels 4 (section 3) manual page for rtcBuildBVH, and bestie, it is the glow-up function. it builds a BVH. that's it. that's the whole vibe. π
π¦ SYNOPSIS π¦
#include <embree4/rtcore.h>
struct RTC_ALIGN(32) RTCBuildPrimitive
{
float lower_x, lower_y, lower_z;
unsigned int geomID;
float upper_x, upper_y, upper_z;
unsigned int primID;
};
typedef void* (*RTCCreateNodeFunction) (
RTCThreadLocalAllocator allocator,
unsigned int childCount,
void* userPtr
);
typedef void (*RTCSetNodeChildrenFunction) (
void* nodePtr,
void** children,
unsigned int childCount,
void* userPtr
);
typedef void (*RTCSetNodeBoundsFunction) (
void* nodePtr,
const struct RTCBounds** bounds,
unsigned int childCount,
void* userPtr
);
typedef void* (*RTCCreateLeafFunction) (
RTCThreadLocalAllocator allocator,
const struct RTCBuildPrimitive* primitives,
size_t primitiveCount,
void* userPtr
);
typedef void (*RTCSplitPrimitiveFunction) (
const struct RTCBuildPrimitive* primitive,
unsigned int dimension,
float position,
struct RTCBounds* leftBounds,
struct RTCBounds* rightBounds,
void* userPtr
);
typedef bool (*RTCProgressMonitorFunction)(
void* userPtr, double n
);
enum RTCBuildFlags
{
RTC_BUILD_FLAG_NONE,
RTC_BUILD_FLAG_DYNAMIC
};
struct RTCBuildArguments
{
size_t byteSize;
enum RTCBuildQuality buildQuality;
enum RTCBuildFlags buildFlags;
unsigned int maxBranchingFactor;
unsigned int maxDepth;
unsigned int sahBlockSize;
unsigned int minLeafSize;
unsigned int maxLeafSize;
float traversalCost;
float intersectionCost;
RTCBVH bvh;
struct RTCBuildPrimitive* primitives;
size_t primitiveCount;
size_t primitiveArrayCapacity;
RTCCreateNodeFunction createNode;
RTCSetNodeChildrenFunction setNodeChildren;
RTCSetNodeBoundsFunction setNodeBounds;
RTCCreateLeafFunction createLeaf;
RTCSplitPrimitiveFunction splitPrimitive;
RTCProgressMonitorFunction buildProgress;
void* userPtr;
};
struct RTCBuildArguments rtcDefaultBuildArguments();
void* rtcBuildBVH(
const struct RTCBuildArguments* args
);
πΈ DESCRIPTION πΈ
okay so, the way that rtcBuildBVH works is that it lets you build a BVH in a user-defined format over arbitrary primitives. iconic. you bring the primitives, it brings the tree. π³β¨
every single argument to the function goes through the RTCBuildArguments structure. and here's the non-negotiable part, bestie: the first member of that structure must be set to the size of the structure in bytes (the bytesSize member) β that's what lets future extensions of the structure happen without breaking you. π
the recommended move is to initialize your build arguments structure using the rtcDefaultBuildArguments function, fr fr.
so rtcBuildBVH gets handed:
- the BVH to build β
bvhmember - the array of primitives β
primitivesmember - the capacity of that array β
primitiveArrayCapacitymember - the number of primitives actually stored inside the array β
primitiveCountmember - callback function pointers
- and a user-defined pointer β
userPtrmember β that gets passed to all callback functions whenever they're invoked
you can free the primitives array yourself once the BVH is built, no hard feelings. π«Ά
β οΈ all callback functions are typically called from multiple threads, so their implementations must be thread-safe. no cap.
π§ the four mandatory callbacks
four callback functions must be registered, and they get invoked during the build:
createNodemember β creates BVH nodessetNodeChildrenmember β sets the pointers to all childrensetNodeBoundsmember β sets the bounding boxes of all childrencreateLeafmember β creates a leaf node
π the optional ones
- the function pointer to the primitive split function (
splitPrimitivemember) may beNULLβ however, then no spatial splitting in high quality mode is possible. your loss, honestly. - the function pointer used to report the build progress (
buildProgressmember) is optional and may also beNULL.
π build settings, aka the fun part
further, some build settings get passed in to configure the BVH build:
- the build quality settings (
buildQualitymember) let you pick between a faster, low quality build β which is good for dynamic scenes β and a standard quality build for static scenes. choose your fighter. π₯ - the desired maximum branching factor of the BVH β
maxBranchingFactormember - the maximum depth the BVH should have β
maxDepthmember - the block size for the SAH heuristic β
sahBlockSizemember - the minimum and maximum leaf size β
minLeafSizeandmaxLeafSizemembers - the estimated costs of one traversal step and one primitive intersection β
traversalCostandintersectionCostmembers
and when you enable the RTC_BUILD_FLAG_DYNAMIC build flags (buildFlags member), re-build performance for dynamic scenes is improved β at the cost of higher memory requirements. trade-offs, bestie, they're giving ~balance~. βοΈ
π spatial splits need extra room
to spatially split primitives in high quality mode, the builder needs extra space at the end of the build primitive array to store split primitives. the total capacity of the build primitive array is passed using the primitiveArrayCapacity member, and it should be about twice the number of primitives when you're using spatial splits. plan accordingly. π
π«§ allocators, or: the 10Γ thing
the RTCCreateNodeFunc and RTCCreateLeafFunc callbacks get passed a thread local allocator object, and you should use it for fast allocation of nodes via the rtcThreadLocalAlloc function.
π₯ we strongly recommend using this allocation mechanism, because alternative approaches like standard malloc can be over 10Γ slower.
the allocator object passed to the create callbacks may be used only inside the current thread. memory allocated using rtcThreadLocalAlloc is automatically freed when the RTCBVH object is deleted. if you roll your own memory allocation scheme instead, you have to free that memory yourself once the RTCBVH object is no longer used. your memory, your problem. π
β the callbacks in detail
- the
RTCCreateNodeFunccallback additionally gets the number of children for this node in the range from 2 tomaxBranchingFactorβ that's thechildCountargument. - the
RTCSetNodeChildFunccallback function gets a pointer to the node as input (nodePtrargument), an array of pointers to the children (childPtrsargument), and the size of this array (childCountargument). - the
RTCSetNodeBoundsFunccallback function gets a pointer to the node as input (nodePtrargument), an array of pointers to the bounding boxes of the children (boundsargument), and the size of this array (childCountargument). - the
RTCCreateLeafFunccallback additionally gets an array of primitives as input (primitivesargument), and the size of this array (primitiveCountargument). the callback should read thegeomIDandprimIDmembers from the passed primitives to construct the leaf. β¨ - the
RTCSplitPrimitiveFunccallback is invoked in high quality mode to split a primitive (primitiveargument) at the specified position (positionargument) and dimension (dimensionargument). the callback should return bounds of the clipped left and right parts of the primitive (leftBoundsandrightBoundsarguments). - the
RTCProgressMonitorFunctioncallback function is called with the estimated completion ratenin the range[0, 1]. returningtruefrom the callback lets the build continue; returningfalsecancels the build. that's your little emergency brake, use it wisely. π
π― EXIT STATUS π―
on failure an error code is set that can be queried using rtcGetDeviceError. so like, always check, bestie. π
π SEE ALSO π
[rtcNewBVH]
and that's the whole page, you ate it up π
β¨ this was rtcBuildBVH(3) straight outta the Embree Ray Tracing Kernels 4 manual, and it's giving main character energy from the first line to the last. go build something gorgeous. π¦πππΈπ«Ά
π¦ where this page comes from
- alpine 3.24: embree-doc 4.4.1-r0 Β· Apache-2.0
- arch rolling: embree 4.4.1-1 Β· Apache-2.0
- fedora 43: embree 4.4.1-1.fc43 Β· Apache-2.0
- fedora 44: embree 4.4.1-1.fc44 Β· Apache-2.0
- nixpkgs unstable: embree 4.4.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms