Blender V5.0
light_tree.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "scene/light.h"
8#include "scene/scene.h"
9
10#include "util/boundbox.h"
11#include "util/task.h"
12#include "util/types.h"
13#include "util/vector.h"
14
15#include <atomic>
16#include <variant>
17
19
20/* Orientation Bounds
21 *
22 * Bounds the normal axis of the lights,
23 * along with their emission profiles */
25 float3 axis; /* normal axis of the light */
26 float theta_o; /* angle bounding the normals */
27 float theta_e; /* angle bounding the light emissions */
28
30
31 __forceinline OrientationBounds(const float3 &axis_, float theta_o_, float theta_e_)
32 : axis(axis_), theta_o(theta_o_), theta_e(theta_e_)
33 {
34 }
35
36 enum empty_t { empty = 0 };
37
38 /* If the orientation bound is set to empty, the values are set to minimums
39 * so that merging it with another non-empty orientation bound guarantees that
40 * the return value is equal to non-empty orientation bound. */
42 : axis(make_float3(0, 0, 0)), theta_o(FLT_MIN), theta_e(FLT_MIN)
43 {
44 }
45
47 {
48 return is_zero(axis);
49 }
50
51 float calculate_measure() const;
52};
53
55
56/* --------------------------------------------------------------------
57 * Light Tree Construction
58 *
59 * The light tree construction is based on PBRT's BVH construction.
60 */
61
62/* Light Tree uses the bounding box, the orientation bounding cone, and the energy of a cluster to
63 * compute the Surface Area Orientation Heuristic (SAOH). */
67 float energy = 0.0f;
68
69 enum empty_t { empty = 0 };
70
72
74
77 const float &energy)
79 {
80 }
81
83
84 = default;
85
87 {
88 return energy == 0;
89 }
90
91 __forceinline void add(const LightTreeMeasure &measure)
92 {
93 if (!measure.is_zero()) {
94 bbox.grow(measure.bbox);
95 bcone = merge(bcone, measure.bcone);
96 energy += measure.energy;
97 }
98 }
99
100 /* Taken from Eq. 2 in the paper. */
102 {
103 if (is_zero()) {
104 return 0.0f;
105 }
106
107 const float area = bbox.area();
108 const float area_measure = area == 0 ? len(bbox.size()) : area;
109 return energy * area_measure * bcone.calculate_measure();
110 }
111
113 {
114 *this = {};
115 }
116
117 bool transform(const Transform &tfm)
118 {
119 float scale_squared;
120 if (transform_uniform_scale(tfm, scale_squared)) {
121 bbox = bbox.transformed(&tfm);
122 bcone.axis = transform_direction(&tfm, bcone.axis) * inversesqrtf(scale_squared);
123 energy *= scale_squared;
124 return true;
125 }
126 return false;
127 }
128};
129
131
132struct LightTreeNode;
133
134/* Light Linking. */
136 /* Bitmask for membership of primitives in this node. */
138
139 /* When all primitives below this node have identical light set membership, this
140 * part of the light tree can be shared between specialized trees. */
141 bool shareable = true;
143
146
147 void add(const uint64_t prim_set_membership)
148 {
149 if (set_membership == 0) {
150 set_membership = prim_set_membership;
151 }
152 else if (prim_set_membership != set_membership) {
153 set_membership |= prim_set_membership;
154 shareable = false;
155 }
156 }
157
158 void add(const LightTreeLightLink &other)
159 {
160 /* other.set_membership is zero when expanding with an empty bucket: in this case there is no
161 * need to mark node as not shareable. */
162 if (other.set_membership == 0) {
163 return;
164 }
165
166 if (set_membership == 0) {
168 shareable = other.shareable;
169 }
170 else if (other.set_membership != set_membership) {
172 shareable = false;
173 }
174 else if (!other.shareable) {
175 shareable = false;
176 }
177 }
178};
179
181
182/* Light Tree Emitter
183 * An emitter is a built-in light, an emissive mesh, or an emissive triangle. */
185 /* If the emitter is a mesh, point to the root node of its subtree. */
187
188 union {
189 int light_id; /* Index into device lights array. */
190 int prim_id; /* Index into an object's local triangle index. */
191 };
192
196
198
199 LightTreeEmitter(Object *object, const int object_id); /* Mesh emitter. */
200 LightTreeEmitter(Scene *scene,
201 const int prim_id,
202 const int object_id,
203 bool need_transformation = false);
204
206 {
207 return root != nullptr;
208 };
209
211 {
212 return !is_mesh() && prim_id >= 0;
213 };
214
216 {
217 return !is_mesh() && light_id < 0;
218 };
219};
220
221/* Light Tree Bucket
222 * Struct used to determine splitting costs in the light BVH. */
226 int count = 0;
227 static const int num_buckets = 12;
228
229 LightTreeBucket() = default;
230
237
238 void add(const LightTreeEmitter &emitter)
239 {
240 measure.add(emitter.measure);
241 light_link.add(emitter.light_set_membership);
242 count++;
243 }
244};
245
247
248/* Light Tree Node */
254
255 /* A bitmask of `LightTreeNodeType`, as in the building process an instance node can also be a
256 * leaf or an inner node. */
257 int type;
258
259 struct Leaf {
260 /* The number of emitters a leaf node stores. */
261 int num_emitters = -1;
262 /* Index to first emitter. */
264 };
265
266 struct Inner {
267 /* Inner node has two children. */
269 };
270
271 struct Instance {
273 };
274
275 std::variant<Leaf, Inner, Instance> variant_type;
276
277 LightTreeNode(const LightTreeMeasure &measure, const uint &bit_trial)
278 : measure(measure), bit_trail(bit_trial), variant_type(Inner())
279 {
281 }
282
283 ~LightTreeNode() = default;
284
285 __forceinline void add(const LightTreeEmitter &emitter)
286 {
287 measure.add(emitter.measure);
288 light_link.add(emitter.light_set_membership);
289 }
290
292 {
293 return std::get<Leaf>(variant_type);
294 }
295
297 {
298 return std::get<Leaf>(variant_type);
299 }
300
302 {
303 return std::get<Inner>(variant_type);
304 }
305
307 {
308 return std::get<Inner>(variant_type);
309 }
310
312 {
313 return std::get<Instance>(variant_type);
314 }
315
317 {
318 return std::get<Instance>(variant_type);
319 }
320
321 void make_leaf(const int first_emitter_index, const int num_emitters)
322 {
323 variant_type = Leaf();
324 Leaf &leaf = get_leaf();
325
326 leaf.first_emitter_index = first_emitter_index;
327 leaf.num_emitters = num_emitters;
329 }
330
331 void make_distant(const int first_emitter_index, const int num_emitters)
332 {
333 variant_type = Leaf();
334 Leaf &leaf = get_leaf();
335
336 leaf.first_emitter_index = first_emitter_index;
337 leaf.num_emitters = num_emitters;
339 }
340
341 void make_instance(LightTreeNode *reference, const int object_id)
342 {
344 Instance &instance = get_instance();
345
346 instance.reference = reference;
347 this->object_id = object_id;
349 }
350
352 {
354 if (type == LIGHT_TREE_INSTANCE) {
355 return get_instance().reference;
356 }
357 return this;
358 }
359
361 {
362 return type & LIGHT_TREE_INSTANCE;
363 }
364
366 {
367 return type & LIGHT_TREE_LEAF;
368 }
369
371 {
372 return type & LIGHT_TREE_INNER;
373 }
374
376 {
377 return type == LIGHT_TREE_DISTANT;
378 }
379};
380
381/* Light BVH
382 *
383 * BVH-like data structure that keeps track of lights
384 * and considers additional orientation and energy information */
387
388 /* Local lights, distant lights and mesh lights are added to separate vectors for light tree
389 * construction. They are all considered as `emitters_`. */
390 vector<LightTreeEmitter> emitters_;
391 vector<LightTreeEmitter> local_lights_;
392 vector<LightTreeEmitter> distant_lights_;
393 vector<LightTreeEmitter> mesh_lights_;
394
395 std::unordered_map<Mesh *, int> offset_map_;
396
397 Progress &progress_;
398
399 uint max_lights_in_leaf_;
400
401 public:
402 std::atomic<int> num_nodes = 0;
403 size_t num_triangles = 0;
404
405 /* Bitmask of receiver light sets used. Default set is always used. */
407
408 /* An inner node itself or its left and right child. */
409 enum Child {
410 self = -1,
411 left = 0,
412 right = 1,
413 };
414
415 LightTree(Scene *scene, DeviceScene *dscene, Progress &progress, const uint max_lights_in_leaf);
416
417 /* Returns a pointer to the root node. */
418 LightTreeNode *build(Scene *scene, DeviceScene *dscene);
419
420 /* NOTE: Always use this function to create a new node so the number of nodes is in sync. */
422 {
423 num_nodes++;
424 return make_unique<LightTreeNode>(measure, bit_trial);
425 }
426
427 size_t num_emitters() const
428 {
429 return emitters_.size();
430 }
431
433 {
434 return emitters_.data();
435 }
436
437 private:
438 /* Thread. */
440 /* Do not spawn a thread if less than this amount of emitters are to be processed. */
441 enum { MIN_EMITTERS_PER_THREAD = 4096 };
442
443 void recursive_build(Child child,
444 LightTreeNode *inner,
445 const int start,
446 const int end,
447 LightTreeEmitter *emitters,
448 const uint bit_trail,
449 int depth);
450
451 bool should_split(LightTreeEmitter *emitters,
452 const int start,
453 int &middle,
454 const int end,
455 LightTreeMeasure &measure,
456 LightTreeLightLink &light_link,
457 int &split_dim);
458
459 /* Check whether the light tree can use this triangle as light-emissive. */
460 bool triangle_usable_as_light(Mesh *mesh, const int prim_id);
461
462 /* Add all the emissive triangles of a mesh to the light tree. */
463 void add_mesh(Scene *scene, Mesh *mesh, const int object_id);
464};
465
unsigned int uint
struct Mesh Mesh
struct Scene Scene
unsigned long long int uint64_t
std::atomic< int > num_nodes
Definition light_tree.h:402
const LightTreeEmitter * get_emitters() const
Definition light_tree.h:432
LightTree(Scene *scene, DeviceScene *dscene, Progress &progress, const uint max_lights_in_leaf)
unique_ptr< LightTreeNode > create_node(const LightTreeMeasure &measure, const uint &bit_trial)
Definition light_tree.h:421
uint64_t light_link_receiver_used
Definition light_tree.h:406
size_t num_triangles
Definition light_tree.h:403
LightTreeNode * build(Scene *scene, DeviceScene *dscene)
size_t num_emitters() const
Definition light_tree.h:427
#define __forceinline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
TaskPool * task_pool
#define assert(assertion)
@ LIGHT_TREE_INSTANCE
@ LIGHT_TREE_DISTANT
@ LIGHT_TREE_INNER
@ LIGHT_TREE_LEAF
LightTreeMeasure operator+(const LightTreeMeasure &a, const LightTreeMeasure &b)
OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds &cone_b)
ccl_device_inline float inversesqrtf(const float f)
Definition math_base.h:529
ccl_device_inline bool is_zero(const float2 a)
void add(const LightTreeEmitter &emitter)
Definition light_tree.h:238
LightTreeBucket()=default
LightTreeLightLink light_link
Definition light_tree.h:225
static const int num_buckets
Definition light_tree.h:227
LightTreeMeasure measure
Definition light_tree.h:224
LightTreeBucket(const LightTreeMeasure &measure, const LightTreeLightLink &light_link, const int &count)
Definition light_tree.h:231
__forceinline bool is_mesh() const
Definition light_tree.h:205
__forceinline bool is_triangle() const
Definition light_tree.h:210
unique_ptr< LightTreeNode > root
Definition light_tree.h:186
uint64_t light_set_membership
Definition light_tree.h:195
LightTreeMeasure measure
Definition light_tree.h:197
LightTreeEmitter(Object *object, const int object_id)
__forceinline bool is_light() const
Definition light_tree.h:215
__forceinline LightTreeMeasure(empty_t)
Definition light_tree.h:73
OrientationBounds bcone
Definition light_tree.h:66
bool transform(const Transform &tfm)
Definition light_tree.h:117
__forceinline LightTreeMeasure()=default
__forceinline void reset()
Definition light_tree.h:112
__forceinline float calculate()
Definition light_tree.h:101
__forceinline LightTreeMeasure(const LightTreeMeasure &other)=default
__forceinline LightTreeMeasure(const BoundBox &bbox, const OrientationBounds &bcone, const float &energy)
Definition light_tree.h:75
__forceinline void add(const LightTreeMeasure &measure)
Definition light_tree.h:91
__forceinline bool is_zero() const
Definition light_tree.h:86
unique_ptr< LightTreeNode > children[2]
Definition light_tree.h:268
LightTreeNode * reference
Definition light_tree.h:272
LightTreeNode(const LightTreeMeasure &measure, const uint &bit_trial)
Definition light_tree.h:277
void make_instance(LightTreeNode *reference, const int object_id)
Definition light_tree.h:341
__forceinline void add(const LightTreeEmitter &emitter)
Definition light_tree.h:285
__forceinline Inner & get_inner()
Definition light_tree.h:301
__forceinline Instance & get_instance()
Definition light_tree.h:311
__forceinline bool is_leaf() const
Definition light_tree.h:365
void make_leaf(const int first_emitter_index, const int num_emitters)
Definition light_tree.h:321
LightTreeNode * get_reference()
Definition light_tree.h:351
LightTreeMeasure measure
Definition light_tree.h:250
std::variant< Leaf, Inner, Instance > variant_type
Definition light_tree.h:275
void make_distant(const int first_emitter_index, const int num_emitters)
Definition light_tree.h:331
__forceinline bool is_inner() const
Definition light_tree.h:370
LightTreeLightLink light_link
Definition light_tree.h:251
__forceinline bool is_instance() const
Definition light_tree.h:360
__forceinline Leaf & get_leaf()
Definition light_tree.h:291
__forceinline bool is_distant() const
Definition light_tree.h:375
__forceinline const Inner & get_inner() const
Definition light_tree.h:306
~LightTreeNode()=default
__forceinline const Leaf & get_leaf() const
Definition light_tree.h:296
__forceinline const Instance & get_instance() const
Definition light_tree.h:316
__forceinline OrientationBounds(const float3 &axis_, float theta_o_, float theta_e_)
Definition light_tree.h:31
__forceinline bool is_empty() const
Definition light_tree.h:46
__forceinline OrientationBounds()=default
__forceinline OrientationBounds(empty_t)
Definition light_tree.h:41
float calculate_measure() const
ccl_device_inline bool transform_uniform_scale(const Transform &tfm, float &scale)
Definition transform.h:368
ccl_device_inline float3 transform_direction(const ccl_private Transform *t, const float3 a)
Definition transform.h:127
uint len