rtcBuildBVH(3)

πŸ“¦ version 3.13.5, in epel 9, fedora 43, fedora 44

πŸ’– rtcBuildBVH(3) πŸ’–

okay bestie, welcome to Embree Ray Tracing Kernels 3, and today's main character is rtcBuildBVH β€” the girl who builds you a whole BVH. no cap. let's get into it πŸ¦‹


✨ NAME ✨

rtcBuildBVH β€” builds a BVH. that's it, that's the job, and she ate. πŸ’…


🌸 SYNOPSIS 🌸

first of all, the lore:

#include <embree3/rtcore.h>

then the primitive struct, which is aligned, as she should be:

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;
};

now the callback girlies πŸ’…:

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
);

the flags, the vibes:

enum RTCBuildFlags
{
  RTC_BUILD_FLAG_NONE,
  RTC_BUILD_FLAG_DYNAMIC
};

and the big one, the build args struct β€” she's long, and every single member matters:

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;
};

and the two functions you actually call:

struct RTCBuildArguments rtcDefaultBuildArguments();

void* rtcBuildBVH(
  const struct RTCBuildArguments* args
);

πŸ‘‘ DESCRIPTION πŸ‘‘

so. the rtcBuildBVH function can be used to build a BVH in a user-defined format over arbitrary primitives. like, whatever primitives you want. iconic. 🫢

every single argument goes in through the RTCBuildArguments structure. and listen β€” the first member of that struct must be set to the size of the structure in bytes (that's the byteSize member). that's literally the whole reason it's there: it lets the structure get extended in the future without breaking everything. the recommended move is to initialize your build arguments with the rtcDefaultBuildArguments function. do it, bestie. don't be a hero. πŸ™ˆ

rtcBuildBVH gets handed:

  • the BVH to build β€” bvh member
  • the array of primitives β€” primitives member
  • the capacity of that array β€” primitiveArrayCapacity member
  • the number of primitives stored inside the array β€” primitiveCount member
  • callback function pointers, plus a user-defined pointer (userPtr member) that gets passed to all callback functions when they're invoked

the primitives array can be freed by the application after the BVH is built. okay? after. πŸŽ€

⚠️ all callback functions are typically called from multiple threads, so their implementation must be thread-safe. no exceptions, no "but it worked on my machine".

four callback functions must be registered, and they get invoked during the build:

  1. createNode member β€” creates BVH nodes
  2. setNodeChildren member β€” sets the pointers to all children
  3. setNodeBounds member β€” sets the bounding boxes of all children
  4. createLeaf member β€” creates a leaf node

the function pointer to the primitive split function (splitPrimitive member) may be NULL β€” but then no spatial splitting in high quality mode is possible. so like, your call, but that's the tradeoff. the function pointer used to report the build progress (buildProgress member) is optional and may also be NULL.


🧚 build settings, aka the tuning section 🧚

some build settings get passed in to configure the BVH build:

  • the build quality settings (buildQuality member) let you pick between a faster, low quality build which is good for dynamic scenes, and a standard quality build for static scenes.
  • maxBranchingFactor member β€” the desired maximum branching factor of the BVH
  • maxDepth member β€” the maximum depth the BVH should have
  • sahBlockSize member β€” the block size for the SAH heuristic
  • minLeafSize and maxLeafSize member β€” the minimum and maximum leaf size
  • traversalCost and intersectionCost members β€” the estimated costs of one traversal step and one primitive intersection

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. nothing's free, babe. πŸ’€


πŸ“ spatial splits & capacity πŸ“

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 should be about twice the number of primitives when using spatial splits. ✨


πŸ’œ the allocator (do not skip this) πŸ’œ

the RTCCreateNodeFunc and RTCCreateLeafFunc callbacks are passed a thread local allocator object that should be used for fast allocation of nodes using the rtcThreadLocalAlloc function.

πŸ”₯ we strongly recommend using this allocation mechanism, because alternative approaches like standard malloc can be over 10Γ— slower. over ten times!! bestie!!

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. but if you use your own memory allocation scheme, you have to free the memory yourself when the RTCBVH object is no longer used. 😭


🌈 what each callback actually gets 🌈

  • the RTCCreateNodeFunc callback additionally gets the number of children for this node in the range from 2 to maxBranchingFactor (that's the childCount argument).
  • the RTCSetNodeChildFunc callback function gets a pointer to the node as input (nodePtr argument), an array of pointers to the children (childPtrs argument), and the size of this array (childCount argument).
  • the RTCSetNodeBoundsFunc callback function gets a pointer to the node as input (nodePtr argument), an array of pointers to the bounding boxes of the children (bounds argument), and the size of this array (childCount argument).
  • the RTCCreateLeafFunc callback additionally gets an array of primitives as input (primitives argument), and the size of this array (primitiveCount argument). the callback should read the geomID and primID members from the passed primitives to construct the leaf. πŸ‘‘
  • the RTCSplitPrimitiveFunc callback is invoked in high quality mode to split a primitive (primitive argument) at the specified position (position argument) and dimension (dimension argument). the callback should return bounds of the clipped left and right parts of the primitive (leftBounds and rightBounds arguments).
  • the RTCProgressMonitorFunction callback function is called with the estimated completion rate n in the range [0, 1]. returning true from the callback lets the build continue; returning false cancels the build. so dramatic, love that for her. πŸ’…

πŸ’€ EXIT STATUS πŸ’€

on failure an error code is set that can be queried using rtcGetDeviceError. so like, check it. please. πŸ₯Ί


πŸ¦‹ SEE ALSO πŸ¦‹

  • [rtcNewBVH]

and that's the whole page, bestie β€” no notes, she's perfect. this was rtcBuildBVH(3) from Embree Ray Tracing Kernels 3. go build something gorgeous with it. periodt. πŸ’–βœ¨πŸŽ€πŸŒˆπŸ«Ά

πŸ“¦ where this page comes from