Blender V4.3
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#ifndef __LIGHT_TREE_H__
6#define __LIGHT_TREE_H__
7
8#include "scene/light.h"
9#include "scene/scene.h"
10
11#include "util/boundbox.h"
12#include "util/task.h"
13#include "util/types.h"
14#include "util/vector.h"
15
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 : bbox(other.bbox), bcone(other.bcone), energy(other.energy)
84 {
85 }
86
88 {
89 return energy == 0;
90 }
91
92 __forceinline void add(const LightTreeMeasure &measure)
93 {
94 if (!measure.is_zero()) {
95 bbox.grow(measure.bbox);
96 bcone = merge(bcone, measure.bcone);
97 energy += measure.energy;
98 }
99 }
100
101 /* Taken from Eq. 2 in the paper. */
103 {
104 if (is_zero()) {
105 return 0.0f;
106 }
107
108 float area = bbox.area();
109 float area_measure = area == 0 ? len(bbox.size()) : area;
110 return energy * area_measure * bcone.calculate_measure();
111 }
112
114 {
115 *this = {};
116 }
117
118 bool transform(const Transform &tfm)
119 {
120 float scale_squared;
121 if (transform_uniform_scale(tfm, scale_squared)) {
122 bbox = bbox.transformed(&tfm);
123 bcone.axis = transform_direction(&tfm, bcone.axis) * inversesqrtf(scale_squared);
124 energy *= scale_squared;
125 return true;
126 }
127 return false;
128 }
129};
130
132
133struct LightTreeNode;
134
135/* Light Linking. */
137 /* Bitmask for membership of primitives in this node. */
139
140 /* When all primitives below this node have identical light set membership, this
141 * part of the light tree can be shared between specialized trees. */
142 bool shareable = true;
144
147
148 void add(const uint64_t prim_set_membership)
149 {
150 if (set_membership == 0) {
151 set_membership = prim_set_membership;
152 }
153 else if (prim_set_membership != set_membership) {
154 set_membership |= prim_set_membership;
155 shareable = false;
156 }
157 }
158
159 void add(const LightTreeLightLink &other)
160 {
161 if (set_membership == 0) {
162 set_membership = other.set_membership;
163 shareable = other.shareable;
164 }
165 else if (other.set_membership != set_membership) {
166 set_membership |= other.set_membership;
167 shareable = false;
168 }
169 else if (!other.shareable) {
170 shareable = false;
171 }
172 }
173};
174
176
177/* Light Tree Emitter
178 * An emitter is a built-in light, an emissive mesh, or an emissive triangle. */
180 /* If the emitter is a mesh, point to the root node of its subtree. */
181 unique_ptr<LightTreeNode> root;
182
183 union {
184 int light_id; /* Index into device lights array. */
185 int prim_id; /* Index into an object's local triangle index. */
186 };
187
191
193
194 LightTreeEmitter(Object *object, int object_id); /* Mesh emitter. */
195 LightTreeEmitter(Scene *scene, int prim_id, int object_id, bool with_transformation = false);
196
198 {
199 return root != nullptr;
200 };
201
203 {
204 return !is_mesh() && prim_id >= 0;
205 };
206
208 {
209 return !is_mesh() && light_id < 0;
210 };
211};
212
213/* Light Tree Bucket
214 * Struct used to determine splitting costs in the light BVH. */
218 int count = 0;
219 static const int num_buckets = 12;
220
221 LightTreeBucket() = default;
222
229
230 void add(const LightTreeEmitter &emitter)
231 {
232 measure.add(emitter.measure);
234 count++;
235 }
236};
237
239
240/* Light Tree Node */
246
247 /* A bitmask of `LightTreeNodeType`, as in the building process an instance node can also be a
248 * leaf or an inner node. */
249 int type;
250
251 struct Leaf {
252 /* The number of emitters a leaf node stores. */
253 int num_emitters = -1;
254 /* Index to first emitter. */
256 };
257
258 struct Inner {
259 /* Inner node has two children. */
260 unique_ptr<LightTreeNode> children[2];
261 };
262
263 struct Instance {
264 LightTreeNode *reference = nullptr;
265 };
266
267 std::variant<Leaf, Inner, Instance> variant_type;
268
269 LightTreeNode(const LightTreeMeasure &measure, const uint &bit_trial)
270 : measure(measure), bit_trail(bit_trial), variant_type(Inner())
271 {
272 type = LIGHT_TREE_INNER;
273 }
274
275 ~LightTreeNode() = default;
276
277 __forceinline void add(const LightTreeEmitter &emitter)
278 {
279 measure.add(emitter.measure);
281 }
282
284 {
285 return std::get<Leaf>(variant_type);
286 }
287
289 {
290 return std::get<Leaf>(variant_type);
291 }
292
294 {
295 return std::get<Inner>(variant_type);
296 }
297
299 {
300 return std::get<Inner>(variant_type);
301 }
302
304 {
305 return std::get<Instance>(variant_type);
306 }
307
309 {
310 return std::get<Instance>(variant_type);
311 }
312
313 void make_leaf(const int first_emitter_index, const int num_emitters)
314 {
315 variant_type = Leaf();
316 Leaf &leaf = get_leaf();
317
318 leaf.first_emitter_index = first_emitter_index;
319 leaf.num_emitters = num_emitters;
320 type = LIGHT_TREE_LEAF;
321 }
322
323 void make_distant(const int first_emitter_index, const int num_emitters)
324 {
325 variant_type = Leaf();
326 Leaf &leaf = get_leaf();
327
328 leaf.first_emitter_index = first_emitter_index;
329 leaf.num_emitters = num_emitters;
330 type = LIGHT_TREE_DISTANT;
331 }
332
333 void make_instance(LightTreeNode *reference, const int object_id)
334 {
336 Instance &instance = get_instance();
337
338 instance.reference = reference;
339 this->object_id = object_id;
340 type = LIGHT_TREE_INSTANCE;
341 }
342
344 {
345 assert(is_instance());
346 if (type == LIGHT_TREE_INSTANCE) {
347 return get_instance().reference;
348 }
349 return this;
350 }
351
353 {
354 return type & LIGHT_TREE_INSTANCE;
355 }
356
358 {
359 return type & LIGHT_TREE_LEAF;
360 }
361
363 {
364 return type & LIGHT_TREE_INNER;
365 }
366
368 {
369 return type == LIGHT_TREE_DISTANT;
370 }
371};
372
373/* Light BVH
374 *
375 * BVH-like data structure that keeps track of lights
376 * and considers additional orientation and energy information */
378 unique_ptr<LightTreeNode> root_;
379
380 /* Local lights, distant lights and mesh lights are added to separate vectors for light tree
381 * construction. They are all considered as `emitters_`. */
382 vector<LightTreeEmitter> emitters_;
383 vector<LightTreeEmitter> local_lights_;
384 vector<LightTreeEmitter> distant_lights_;
385 vector<LightTreeEmitter> mesh_lights_;
386
387 std::unordered_map<Mesh *, int> offset_map_;
388
389 Progress &progress_;
390
391 uint max_lights_in_leaf_;
392
393 public:
394 std::atomic<int> num_nodes = 0;
395 size_t num_triangles = 0;
396
397 /* Bitmask of receiver light sets used. Default set is always used. */
399
400 /* An inner node itself or its left and right child. */
401 enum Child {
402 self = -1,
403 left = 0,
404 right = 1,
405 };
406
407 LightTree(Scene *scene, DeviceScene *dscene, Progress &progress, uint max_lights_in_leaf);
408
409 /* Returns a pointer to the root node. */
410 LightTreeNode *build(Scene *scene, DeviceScene *dscene);
411
412 /* NOTE: Always use this function to create a new node so the number of nodes is in sync. */
413 unique_ptr<LightTreeNode> create_node(const LightTreeMeasure &measure, const uint &bit_trial)
414 {
415 num_nodes++;
416 return make_unique<LightTreeNode>(measure, bit_trial);
417 }
418
420 {
421 return emitters_.size();
422 }
423
425 {
426 return emitters_.data();
427 }
428
429 private:
430 /* Thread. */
431 TaskPool task_pool;
432 /* Do not spawn a thread if less than this amount of emitters are to be processed. */
433 enum { MIN_EMITTERS_PER_THREAD = 4096 };
434
435 void recursive_build(Child child,
436 LightTreeNode *inner,
437 int start,
438 int end,
439 LightTreeEmitter *emitters,
440 uint bit_trail,
441 int depth);
442
443 bool should_split(LightTreeEmitter *emitters,
444 const int start,
445 int &middle,
446 const int end,
447 LightTreeMeasure &measure,
448 LightTreeLightLink &light_link,
449 int &split_dim);
450
451 /* Check whether the light tree can use this triangle as light-emissive. */
452 bool triangle_usable_as_light(Mesh *mesh, int prim_id);
453
454 /* Add all the emissive triangles of a mesh to the light tree. */
455 void add_mesh(Scene *scene, Mesh *mesh, int object_id);
456};
457
459
460#endif /* __LIGHT_TREE_H__ */
unsigned int uint
LightTree(Scene *scene, DeviceScene *dscene, Progress &progress, uint max_lights_in_leaf)
std::atomic< int > num_nodes
Definition light_tree.h:394
const LightTreeEmitter * get_emitters() const
Definition light_tree.h:424
unique_ptr< LightTreeNode > create_node(const LightTreeMeasure &measure, const uint &bit_trial)
Definition light_tree.h:413
uint64_t light_link_receiver_used
Definition light_tree.h:398
size_t num_triangles
Definition light_tree.h:395
LightTreeNode * build(Scene *scene, DeviceScene *dscene)
size_t num_emitters()
Definition light_tree.h:419
local_group_size(16, 16) .push_constant(Type b
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define __forceinline
int len
@ 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 bool is_zero(const float2 a)
blender::draw::overlay::Instance Instance
unsigned __int64 uint64_t
Definition stdint.h:90
BoundBox transformed(const Transform *tfm) const
Definition boundbox.h:135
__forceinline float3 size() const
Definition boundbox.h:123
__forceinline void grow(const float3 &pt)
Definition boundbox.h:36
__forceinline float area() const
Definition boundbox.h:102
void add(const LightTreeEmitter &emitter)
Definition light_tree.h:230
LightTreeBucket()=default
LightTreeLightLink light_link
Definition light_tree.h:217
static const int num_buckets
Definition light_tree.h:219
LightTreeMeasure measure
Definition light_tree.h:216
LightTreeBucket(const LightTreeMeasure &measure, const LightTreeLightLink &light_link, const int &count)
Definition light_tree.h:223
__forceinline bool is_mesh() const
Definition light_tree.h:197
LightTreeEmitter(Object *object, int object_id)
__forceinline bool is_triangle() const
Definition light_tree.h:202
unique_ptr< LightTreeNode > root
Definition light_tree.h:181
uint64_t light_set_membership
Definition light_tree.h:190
LightTreeMeasure measure
Definition light_tree.h:192
__forceinline bool is_light() const
Definition light_tree.h:207
__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:118
__forceinline LightTreeMeasure()=default
__forceinline void reset()
Definition light_tree.h:113
__forceinline float calculate()
Definition light_tree.h:102
__forceinline LightTreeMeasure(const LightTreeMeasure &other)
Definition light_tree.h:82
__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:92
__forceinline bool is_zero() const
Definition light_tree.h:87
unique_ptr< LightTreeNode > children[2]
Definition light_tree.h:260
LightTreeNode * reference
Definition light_tree.h:264
LightTreeNode(const LightTreeMeasure &measure, const uint &bit_trial)
Definition light_tree.h:269
void make_instance(LightTreeNode *reference, const int object_id)
Definition light_tree.h:333
__forceinline void add(const LightTreeEmitter &emitter)
Definition light_tree.h:277
__forceinline Inner & get_inner()
Definition light_tree.h:293
__forceinline Instance & get_instance()
Definition light_tree.h:303
__forceinline bool is_leaf() const
Definition light_tree.h:357
void make_leaf(const int first_emitter_index, const int num_emitters)
Definition light_tree.h:313
LightTreeNode * get_reference()
Definition light_tree.h:343
LightTreeMeasure measure
Definition light_tree.h:242
std::variant< Leaf, Inner, Instance > variant_type
Definition light_tree.h:267
void make_distant(const int first_emitter_index, const int num_emitters)
Definition light_tree.h:323
__forceinline bool is_inner() const
Definition light_tree.h:362
LightTreeLightLink light_link
Definition light_tree.h:243
__forceinline bool is_instance() const
Definition light_tree.h:352
__forceinline Leaf & get_leaf()
Definition light_tree.h:283
__forceinline bool is_distant() const
Definition light_tree.h:367
__forceinline const Inner & get_inner() const
Definition light_tree.h:298
~LightTreeNode()=default
__forceinline const Leaf & get_leaf() const
Definition light_tree.h:288
__forceinline const Instance & get_instance() const
Definition light_tree.h:308
__forceinline OrientationBounds()
Definition light_tree.h:29
__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(empty_t)
Definition light_tree.h:41
float calculate_measure() const
ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
Definition transform.h:94
ccl_device_inline bool transform_uniform_scale(const Transform &tfm, float &scale)
Definition transform.h:340
ccl_device_inline float inversesqrtf(float f)
Definition util/math.h:711