WIP: Test Embree alternative to Blender BVH trees #108148

Draft
Lukas Tönne wants to merge 12 commits from LukasTonne/blender:bvh-embree into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Member

Test branch to compare performance of Embree BVH trees to Blender's own implementation and determine feasibility for replacement.

We want to compare the Embree library to Blender's own BVH tree implementation. The goal of this task is to find where Blender's BVH features don't have clear Embree equivalents, or where Embree might provide additional features that Blender can take advantage of.

k-DOP nodes vs. plain bounding boxes

Blender BVH has ancient feature: k-DOP bounding volumes. This is barely documented.

TL;DR: It's probably outdated and virtually useless, would suggest abandoning it if we move to Embree. If you want to know how it works, i attempt an explanation below.

My understanding is that a discrete oriented polytope (DOP) is a bounding volume that can include more bounding planes than a standard axis-aligned bounding box (AABB). These planes are constructed by combinations of the cardinal axes X, Y, Z. A bounding box only has bounding planes in the X, Y, Z, -X, -Y, and -Z directions. Combining two axes creates a diagonal plane along the edges, while combining 3 axes adds diagonal corner planes.

A selection of possible DOP bounding volumes: a simple cube, a prism with diagonals on edges, a polytope with diagonal planes on corners

Blender encodes the directions used to enclose BVH nodes in the axis variable, which is the k in "k-DOP" (not to be confused with the tree_type which is the number of children per node).

  • The 6 faces of a cube are associated with the positive and negative cardinal directions +X, +Y, +Z, -X, -Y, -Z
  • The 12 edges are associated with double axis combinations +X+Y, -X+Y, +X-Y, -X-Y, +X+Z, -X+Z, +X-Z, -X-Z, +Y+Z, -Y+Z, +Y-Z, -Y-Z
  • The 8 corners are associated with triple axis combinations +X+Y+Z, -X+Y+Z, +X-Y+Z, -X-Y+Z, +X+Y-Z, -X+Y-Z, +X-Y-Z, -X-Y-Z

In total this yields 26 possible directions and their combinations. However, Blender BVH only supports certain combinations:

  • 6 (faces only)
  • 8 (corners only)
  • 14 (faces + corners)
  • 18 (faces + edges)
  • 26 (faces + edges + corners)

⚠️ There are code comments labeling axis values of 6 as "OBB" and, depending on where you look, either 7 or 8 as "AABB" (source 1, source 2). I'm not sure what is going on there, a set of 6 axes should be enough for an AABB. Declaring something an OBB tree also doesn't make much sense, unless a rotation value of some kind was stored per node. A mystery ...

The advantage of DOP volumes over plain bounding boxes is that they can enclose geometry more tightly, which can lead to fewer false-positive broadphase checks. The overlap check of such polytopes is still cheap due to using only basic combinations of cardinal axes.

However, this feature seems to be very rarely used. The gain in performance seems marginal and the implementation becomes much more complex. The almost total lack of documentation means that hardly anyone uses axis and tree_type values deliberately and most just copy from existing places.

IMO this feature can be dropped from Blender to simplify BVH usage and be compatible with Embree.

High-level BVH build methods

bvhutils provides wrappers in BLI around the simpler kdopbvh API. If the kdopbvh API can be made to use Embree BVH then not many changes should be needed in bvhutils.

Build from vertices (points):

  • bvhtree_from_editmesh_verts
  • bvhtree_from_editmesh_verts_ex
  • bvhtree_from_mesh_verts_ex

Build from edges:

  • bvhtree_from_editmesh_edges
  • bvhtree_from_editmesh_edges_ex
  • bvhtree_from_mesh_edges_ex

Build from triangles:

  • bvhtree_from_editmesh_looptri
  • bvhtree_from_editmesh_looptri_ex
  • bvhtree_from_mesh_looptri_ex

Higher level wrappers (may support different primitive types):

  • BKE_bvhtree_from_mesh_get
  • BKE_bvhtree_from_editmesh_get
  • BKE_bvhtree_from_pointcloud_get

Trees are freed again with

  • free_bvhtree_from_editmesh
  • free_bvhtree_from_mesh
  • free_bvhtree_from_pointcloud

Embree equivalents for Blender BVH API

Embree BVH trees are more structured than Blender BVH: Each tree can contain multiple scenes, which in turn can contain multiple geometries. The Blender BVH tree can be represented as a single geometry in a single scene. Embree scenes support features like compression flags and build quality settings for which Blender BVH does not have equivalents.

Geometries can be shared between multiple scenes. This kind of data sharing is implemented in Blender through the BVH cache and the general scene/object hierarchy, but there is no overall scene BVH. This means that in order to query the entire scene Blender has to search through object BVH trees linearly instead of taking advantage of bounding boxes. For the time being we'll keep it that way, supporting scene-wide BVH construction with Embree should be a future task.

Embree also requires a device object. This should be persistent during the lifetime of a Blender instance. We will only be using a standard CPU device, Blender BVH trees are not currently used with GPU code.

Build functions

Blender BVH Embree BVH
BLI_bvhtree_new rtcNewScene + rtcNewGeometry + rtcAttachGeometry
BLI_bvhtree_free rtcReleaseGeometry + rtcReleaseScene Embree objects are internally user-counted.
BLI_bvhtree_insert rtcSetNewGeometryBuffer Embree allocates buffers but leaves it to us to fill them.
BLI_bvhtree_balance rtcCommitGeometry
BLI_bvhtree_update_node n/a There doesn't seem to be an update method for individual buffer elements.
BLI_bvhtree_update_tree rtcUpdateGeometryBuffer

Tree info

Embree does not seem to provide much info about a BVH tree after construction. For specifying details the rtcBuildBVH function can be used. This includes the branching factor (tree_type in current BVH).

Epsilon is a fudge factor to resolve tangent ray intersections. Embree does not have (or need?) an API for that, it may just be better at handling float precision corner cases.

Blender BVH Embree BVH
BLI_bvhtree_get_len n/a The number of elements is passed during buffer construction.
BLI_bvhtree_get_tree_type n/a
BLI_bvhtree_get_epsilon n/a
BLI_bvhtree_get_bounding_box rtcGetSceneBounds, rtcGetSceneLinearBounds rtcGetSceneLinearBounds provides two bounds for start and end time which can be linearly interpolated.

Query methods

Query methods with a 1 suffix usually have variants for handling 4, 8, or 16 elements in parallel (SIMD) which Blender's BVH does not support.

Blender BVH Embree BVH
BLI_bvhtree_overlap rtcCollide
BLI_bvhtree_overlap_ex rtcCollide
BLI_bvhtree_overlap_self rtcCollide Just a convenience wrapper around BLI_bvhtree_overlap_ex
BLI_bvhtree_overlap_thread_num n/a? Used for multi-threaded overlap tests with thread-local storage. rtcCollide does not appear to be multi-threaded itself, but near-phase checks could be parallelized.
BLI_bvhtree_intersect_plane ? Maybe could be done using filter functions with a collision query.
BLI_bvhtree_find_nearest rtcPointQuery rtcPointQuery runs callback for alll intersections, just need to return the min
BLI_bvhtree_find_nearest_ex rtcPointQuery
BLI_bvhtree_find_nearest_first rtcPointQuery
BLI_bvhtree_find_nearest_projected ? Probably just a variation on rtcPointQuery with additional filtering
BLI_bvhtree_range_query rtcPointQuery rtcPointQuery already uses a callback for all intersections
BLI_bvhtree_ray_cast rtcIntersect1
BLI_bvhtree_ray_cast_ex rtcIntersect1
BLI_bvhtree_ray_cast_all rtcOccluded1
BLI_bvhtree_ray_cast_all_ex rtcOccluded1
BLI_bvhtree_bb_raycast n/a Very simple ray<->aabb intersection test, does not actually use a BVH
BLI_bvhtree_walk_dfs ? This one could be tricky, but it doesn't seem to be used at all
Test branch to compare performance of Embree BVH trees to Blender's own implementation and determine feasibility for replacement. We want to compare the Embree library to Blender's own BVH tree implementation. The goal of this task is to find where Blender's BVH features don't have clear Embree equivalents, or where Embree might provide additional features that Blender can take advantage of. ## k-DOP nodes vs. plain bounding boxes Blender BVH has ancient feature: k-DOP bounding volumes. This is barely documented. **TL;DR**: It's _probably_ outdated and virtually useless, would suggest abandoning it if we move to Embree. If you want to know how it works, i attempt an explanation below. My understanding is that a _discrete oriented polytope_ (DOP) is a bounding volume that can include more bounding planes than a standard axis-aligned bounding box (AABB). These planes are constructed by combinations of the cardinal axes X, Y, Z. A bounding box only has bounding planes in the X, Y, Z, -X, -Y, and -Z directions. Combining two axes creates a diagonal plane along the edges, while combining 3 axes adds diagonal corner planes. ![A selection of possible DOP bounding volumes: a simple cube, a prism with diagonals on edges, a polytope with diagonal planes on corners](/attachments/0c16bf63-5698-49e4-b8aa-c01e63a3400e) Blender encodes the directions used to enclose BVH nodes in the `axis` variable, which is the _k_ in "k-DOP" (not to be confused with the `tree_type` which is the number of children per node). - The 6 faces of a cube are associated with the positive and negative cardinal directions +X, +Y, +Z, -X, -Y, -Z - The 12 edges are associated with double axis combinations +X+Y, -X+Y, +X-Y, -X-Y, +X+Z, -X+Z, +X-Z, -X-Z, +Y+Z, -Y+Z, +Y-Z, -Y-Z - The 8 corners are associated with triple axis combinations +X+Y+Z, -X+Y+Z, +X-Y+Z, -X-Y+Z, +X+Y-Z, -X+Y-Z, +X-Y-Z, -X-Y-Z In total this yields 26 possible directions and their combinations. However, Blender BVH only supports certain combinations: - 6 (faces only) - 8 (corners only) - 14 (faces + corners) - 18 (faces + edges) - 26 (faces + edges + corners) > :warning: There are code comments labeling axis values of 6 as "OBB" and, depending on where you look, either 7 or 8 as "AABB" ([source 1](https://projects.blender.org/blender/blender/src/commit/793446cbdcc28709b0bfd858c7077f5d31560162/source/blender/blenlib/intern/BLI_kdopbvh.c#L85), [source 2](https://projects.blender.org/blender/blender/src/branch/main/source/blender/blenlib/intern/BLI_kdopbvh.c#L892-L899)). I'm not sure what is going on there, a set of 6 axes should be enough for an AABB. Declaring something an OBB tree also doesn't make much sense, unless a rotation value of some kind was stored per node. A mystery ... The advantage of DOP volumes over plain bounding boxes is that they can enclose geometry more tightly, which can lead to fewer false-positive broadphase checks. The overlap check of such polytopes is still cheap due to using only basic combinations of cardinal axes. _However_, this feature seems to be very rarely used. The gain in performance seems marginal and the implementation becomes much more complex. The almost total lack of documentation means that hardly anyone uses `axis` and `tree_type` values deliberately and most just copy from existing places. IMO this feature can be dropped from Blender to simplify BVH usage and be compatible with Embree. ## High-level BVH build methods `bvhutils` provides wrappers in BLI around the simpler `kdopbvh` API. If the `kdopbvh` API can be made to use Embree BVH then not many changes should be needed in `bvhutils`. Build from vertices (points): - `bvhtree_from_editmesh_verts` - `bvhtree_from_editmesh_verts_ex` - `bvhtree_from_mesh_verts_ex` Build from edges: - `bvhtree_from_editmesh_edges` - `bvhtree_from_editmesh_edges_ex` - `bvhtree_from_mesh_edges_ex` Build from triangles: - `bvhtree_from_editmesh_looptri` - `bvhtree_from_editmesh_looptri_ex` - `bvhtree_from_mesh_looptri_ex` Higher level wrappers (may support different primitive types): - `BKE_bvhtree_from_mesh_get` - `BKE_bvhtree_from_editmesh_get` - `BKE_bvhtree_from_pointcloud_get` Trees are freed again with - `free_bvhtree_from_editmesh` - `free_bvhtree_from_mesh` - `free_bvhtree_from_pointcloud` ## Embree equivalents for Blender BVH API Embree BVH trees are more structured than Blender BVH: Each tree can contain multiple [scenes](https://raw.githubusercontent.com/embree/embree/master/readme.pdf#section.4.2), which in turn can contain multiple [geometries](https://raw.githubusercontent.com/embree/embree/master/readme.pdf#section.4.3). The Blender BVH tree can be represented as a single geometry in a single scene. Embree scenes support features like [compression flags](https://raw.githubusercontent.com/embree/embree/master/readme.pdf#rtcsetsceneflags) and [build quality settings](https://raw.githubusercontent.com/embree/embree/master/readme.pdf#rtcsetscenebuildquality) for which Blender BVH does not have equivalents. Geometries can be shared between multiple scenes. This kind of data sharing is implemented in Blender through the BVH cache and the general scene/object hierarchy, but there is no overall scene BVH. This means that in order to query the entire scene Blender has to search through object BVH trees linearly instead of taking advantage of bounding boxes. For the time being we'll keep it that way, supporting scene-wide BVH construction with Embree should be a future task. Embree also requires a [device](https://raw.githubusercontent.com/embree/embree/master/readme.pdf#section.4.1) object. This should be persistent during the lifetime of a Blender instance. We will only be using a standard CPU device, Blender BVH trees are not currently used with GPU code. ### Build functions |Blender BVH|Embree BVH|| |---|---|---| |`BLI_bvhtree_new`|`rtcNewScene` + `rtcNewGeometry` + `rtcAttachGeometry`|| |`BLI_bvhtree_free`|`rtcReleaseGeometry` + `rtcReleaseScene`|Embree objects are internally user-counted.| |`BLI_bvhtree_insert`|`rtcSetNewGeometryBuffer`|Embree allocates buffers but leaves it to us to fill them.| |`BLI_bvhtree_balance`|`rtcCommitGeometry`|| |`BLI_bvhtree_update_node`|n/a|There doesn't seem to be an update method for individual buffer elements.| |`BLI_bvhtree_update_tree`|`rtcUpdateGeometryBuffer`|| ### Tree info Embree does not seem to provide much info about a BVH tree _after_ construction. For specifying details the `rtcBuildBVH` function can be used. This includes the branching factor (`tree_type` in current BVH). Epsilon is a fudge factor to resolve tangent ray intersections. Embree does not have (or need?) an API for that, it may just be better at handling float precision corner cases. |Blender BVH|Embree BVH|| |---|---|---| |`BLI_bvhtree_get_len`|n/a|The number of elements is passed during buffer construction.| |`BLI_bvhtree_get_tree_type`|n/a|| |`BLI_bvhtree_get_epsilon`|n/a|| |`BLI_bvhtree_get_bounding_box`|`rtcGetSceneBounds`, `rtcGetSceneLinearBounds`|`rtcGetSceneLinearBounds` provides _two_ bounds for start and end time which can be linearly interpolated.| ### Query methods Query methods with a `1` suffix usually have variants for handling 4, 8, or 16 elements in parallel (SIMD) which Blender's BVH does not support. |Blender BVH|Embree BVH|| |---|---|---| |`BLI_bvhtree_overlap`|`rtcCollide`|| |`BLI_bvhtree_overlap_ex`|`rtcCollide`|| |`BLI_bvhtree_overlap_self`|`rtcCollide`|Just a convenience wrapper around `BLI_bvhtree_overlap_ex`| |`BLI_bvhtree_overlap_thread_num`|n/a?|Used for multi-threaded overlap tests with thread-local storage. `rtcCollide` does not appear to be multi-threaded itself, but near-phase checks could be parallelized.| |`BLI_bvhtree_intersect_plane`|?|Maybe could be done using filter functions with a collision query.| |`BLI_bvhtree_find_nearest`|`rtcPointQuery`|`rtcPointQuery` runs callback for alll intersections, just need to return the min| |`BLI_bvhtree_find_nearest_ex`|`rtcPointQuery`|| |`BLI_bvhtree_find_nearest_first`|`rtcPointQuery`|| |`BLI_bvhtree_find_nearest_projected`|?|Probably just a variation on `rtcPointQuery` with additional filtering| |`BLI_bvhtree_range_query`|`rtcPointQuery`|`rtcPointQuery` already uses a callback for all intersections| |`BLI_bvhtree_ray_cast`|`rtcIntersect1`|| |`BLI_bvhtree_ray_cast_ex`|`rtcIntersect1`|| |`BLI_bvhtree_ray_cast_all`|`rtcOccluded1`|| |`BLI_bvhtree_ray_cast_all_ex`|`rtcOccluded1`|| |`BLI_bvhtree_bb_raycast`|n/a|Very simple ray<->aabb intersection test, does not actually use a BVH| |`BLI_bvhtree_walk_dfs`|?|This one could be tricky, but it doesn't seem to be used at all|
Lukas Tönne added 12 commits 2023-05-22 15:04:29 +02:00
Lukas Tönne added this to the Nodes & Physics project 2023-05-22 15:04:57 +02:00
This pull request has changes conflicting with the target branch.
  • CMakeLists.txt
  • source/blender/blenkernel/BKE_mesh_sample.hh
  • source/blender/blenkernel/BKE_mesh_types.h
  • source/blender/blenkernel/BKE_node.h
  • source/blender/blenkernel/CMakeLists.txt
  • source/blender/blenkernel/intern/mesh.cc
  • source/blender/blenkernel/intern/mesh_runtime.cc
  • source/blender/makesdna/DNA_mesh_types.h
  • source/blender/nodes/NOD_static_types.h
  • source/blender/nodes/geometry/node_geometry_register.cc

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u bvh-embree:LukasTonne-bvh-embree
git checkout LukasTonne-bvh-embree
Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#108148
No description provided.