Blender V5.0
cycles/bvh/octree.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5/* The volume octree is used to determine the necessary step size when rendering the volume. One
6 * volume per object per shader is built, and a node splits in eight when the density difference
7 * inside the node exceeds a certain threshold. */
8
9#ifndef __OCTREE_H__
10#define __OCTREE_H__
11
12#include "util/boundbox.h"
13#include "util/task.h"
14
15#ifdef WITH_OPENVDB
16# include <openvdb/openvdb.h>
17#endif
18
19#include <atomic>
20
22
23class Device;
24class Object;
25class Progress;
26class Shader;
27struct KernelOctreeNode;
28
29struct OctreeNode {
30 /* Bounding box of the node. */
32
33 /* Depth of the node in the octree. */
34 int depth;
35
36 /* Minimal and maximal volume density inside the node. */
37 Extrema<float> sigma = {0.0f, 0.0f};
38
39 OctreeNode() : bbox(BoundBox::empty), depth(0) {}
40 OctreeNode(BoundBox bbox_, int depth_) : bbox(bbox_), depth(depth_) {}
41 virtual ~OctreeNode() = default;
42
43 /* Visualize node. */
44 void visualize(std::string &str) const;
45};
46
57
58class Octree {
59 public:
60 Octree(const BoundBox &bbox);
61 ~Octree() = default;
62
63 /* Build the octree according to the volume density. */
64#ifdef WITH_OPENVDB
65 void build(Device *, Progress &, openvdb::BoolGrid::ConstPtr &, const Object *, const Shader *);
66#else
67 void build(Device *, Progress &, const Object *, const Shader *);
68#endif
69
70 /* Convert the octree into an array of nodes for uploading to the kernel. */
71 void flatten(KernelOctreeNode *, const int, const std::shared_ptr<OctreeNode> &, int &) const;
72 void set_flattened(const bool = true);
73 bool is_flattened() const;
74
75 /* Flatten a 3D coordinate in the grid to a 1D index. */
76 int flatten_index(int x, int y, int z) const;
77 /* Convert from index to the position of the lower left corner of the voxel. */
78 float3 index_to_position(int x, int y, int z) const;
79 /* Size of a voxel. */
80 float3 voxel_size() const;
81
82 int get_num_nodes() const;
83 std::shared_ptr<OctreeNode> get_root() const;
84 bool is_built() const;
85
86 /* Draw octree nodes as empty boxes with Blender Python API. */
87 void visualize(std::ofstream &file, const std::string object_name) const;
88
89 private:
90 /* The bounding box of the octree is divided into a regular grid with the same resolution in each
91 * dimension. */
92 int resolution_;
93 /* Extrema of volume densities in the grid. */
94 vector<Extrema<float>> sigmas_;
95 /* Compute the extrema of all the `sigmas_` in a coordinate bounding box defined by `index_min`
96 * and `index_max`. */
97 Extrema<float> get_extrema(const int3 index_min, const int3 index_max) const;
98 /* Randomly sample positions inside the grid to evaluate the shader for the density. */
99#ifdef WITH_OPENVDB
100 void evaluate_volume_density(
101 Device *, Progress &, openvdb::BoolGrid::ConstPtr &, const Object *, const Shader *);
102#else
103 void evaluate_volume_density(Device *, Progress &, const Object *, const Shader *);
104#endif
105 /* Convert from position in object space to grid index space. */
106 float3 position_to_index_scale_;
107 float3 index_to_position_scale_;
108 float3 position_to_index(const float3 p) const;
109 int3 position_to_floor_index(const float3 p) const;
110 int3 position_to_ceil_index(const float3 p) const;
111
112 /* Whether a node should be split into child nodes. */
113 bool should_split(std::shared_ptr<OctreeNode> &node) const;
114 /* Scale the node size so that the octree has the similar subdivision levels in viewport and
115 * final render. */
116 float volume_scale(const Object *object) const;
117 float scale_;
118 /* Recursively build a node and its child nodes. */
119 void recursive_build(std::shared_ptr<OctreeNode> &);
120 /* Turn a node into an internal node. */
121 std::shared_ptr<OctreeInternalNode> make_internal(std::shared_ptr<OctreeNode> &node);
122
123 /* Root node. */
124 std::shared_ptr<OctreeNode> root_;
125
126 /* Bounding box min of the octree, used for computing the indices. */
127 float3 bbox_min;
128
129 /* Whether the octree is already built. */
130 bool is_built_;
131
132 /* Whether the octree is already flattened into an array. */
133 bool is_flattened_;
134
135 /* Number of nodes in the octree. Incremented while building the tree. */
136 std::atomic<int> num_nodes_ = 1;
137
138 /* Task pool for building the octree in parallel. */
139 TaskPool task_pool_;
140};
141
143
144#endif /* __OCTREE_H__ */
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
void visualize(std::ofstream &file, const std::string object_name) const
int get_num_nodes() const
float3 voxel_size() const
int flatten_index(int x, int y, int z) const
void flatten(KernelOctreeNode *, const int, const std::shared_ptr< OctreeNode > &, int &) const
void set_flattened(const bool=true)
float3 index_to_position(int x, int y, int z) const
std::shared_ptr< OctreeNode > get_root() const
void build(Device *, Progress &, const Object *, const Shader *)
bool is_flattened() const
Octree(const BoundBox &bbox)
bool is_built() const
#define CCL_NAMESPACE_END
#define str(s)
OctreeInternalNode(OctreeNode &node)
vector< std::shared_ptr< OctreeNode > > children_
virtual ~OctreeNode()=default
Extrema< float > sigma
OctreeNode(BoundBox bbox_, int depth_)
void visualize(std::string &str) const