Blender V5.0
bvh/split.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
2 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Adapted code from NVIDIA Corporation. */
7
8#include "bvh/split.h"
9
10#include "bvh/build.h"
11#include "bvh/sort.h"
12
13#include "scene/hair.h"
14#include "scene/mesh.h"
15#include "scene/object.h"
16#include "scene/pointcloud.h"
17
18#include "util/algorithm.h"
19
21
22/* Object Split */
23
25 BVHSpatialStorage *storage,
26 const BVHRange &range,
27 vector<BVHReference> &references,
28 const float nodeSAH,
29 const BVHUnaligned *unaligned_heuristic,
30 const Transform *aligned_space)
31 : sah(FLT_MAX),
32 dim(0),
33 num_left(0),
34 left_bounds(BoundBox::empty),
35 right_bounds(BoundBox::empty),
36 storage_(storage),
37 references_(&references),
38 unaligned_heuristic_(unaligned_heuristic),
39 aligned_space_(aligned_space)
40{
41 const BVHReference *ref_ptr = &references_->at(range.start());
42 float min_sah = FLT_MAX;
43
44 for (int dim = 0; dim < 3; dim++) {
45 /* Sort references. */
47 range.end(),
48 &references_->at(0),
49 dim,
52
53 // Resize must be called after every bvh_reference_sort, as sorting may use a task pool for
54 // large ranges. This may cause another BVHObjectSplit to use and resize the storage on the
55 // same thread.
56 storage_->right_bounds.resize(range.size());
57
58 /* sweep right to left and determine bounds. */
60 for (int i = range.size() - 1; i > 0; i--) {
61 const BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
62 right_bounds.grow(prim_bounds);
63 storage_->right_bounds[i - 1] = right_bounds;
64 }
65
66 /* sweep left to right and select lowest SAH. */
68
69 for (int i = 1; i < range.size(); i++) {
70 const BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
71 left_bounds.grow(prim_bounds);
72 right_bounds = storage_->right_bounds[i - 1];
73
74 const float sah = nodeSAH + left_bounds.safe_area() * builder->params.primitive_cost(i) +
75 right_bounds.safe_area() *
76 builder->params.primitive_cost(range.size() - i);
77
78 if (sah < min_sah) {
79 min_sah = sah;
80
81 this->sah = sah;
82 this->dim = dim;
83 this->num_left = i;
84 this->left_bounds = left_bounds;
85 this->right_bounds = right_bounds;
86 }
87 }
88 }
89}
90
92{
93 assert(!references_->empty());
94 /* sort references according to split */
96 range.end(),
97 &references_->at(0),
98 this->dim,
101
102 BoundBox effective_left_bounds;
103 BoundBox effective_right_bounds;
104 const int num_right = range.size() - this->num_left;
105 if (aligned_space_ == nullptr) {
106 effective_left_bounds = left_bounds;
107 effective_right_bounds = right_bounds;
108 }
109 else {
110 effective_left_bounds = BoundBox::empty;
111 effective_right_bounds = BoundBox::empty;
112 for (int i = 0; i < this->num_left; ++i) {
113 const BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
114 effective_left_bounds.grow(prim_boundbox);
115 }
116 for (int i = 0; i < num_right; ++i) {
117 const BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
118 effective_right_bounds.grow(prim_boundbox);
119 }
120 }
121
122 /* split node ranges */
123 left = BVHRange(effective_left_bounds, range.start(), this->num_left);
124 right = BVHRange(effective_right_bounds, left.end(), num_right);
125}
126
127/* Spatial Split */
128
130 BVHSpatialStorage *storage,
131 const BVHRange &range,
132 vector<BVHReference> &references,
133 const float nodeSAH,
134 const BVHUnaligned *unaligned_heuristic,
135 const Transform *aligned_space)
136 : sah(FLT_MAX),
137 dim(0),
138 pos(0.0f),
139 storage_(storage),
140 references_(&references),
141 unaligned_heuristic_(unaligned_heuristic),
142 aligned_space_(aligned_space)
143{
144 /* initialize bins. */
145 BoundBox range_bounds;
146 if (aligned_space == nullptr) {
147 range_bounds = range.bounds();
148 }
149 else {
150 range_bounds = unaligned_heuristic->compute_aligned_boundbox(
151 range, &references_->at(0), *aligned_space);
152 }
153
154 float3 origin = range_bounds.min;
155 float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
156 const float3 invBinSize = safe_divide(make_float3(1.0f), binSize);
157
158 for (int dim = 0; dim < 3; dim++) {
159 for (int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
160 BVHSpatialBin &bin = storage_->bins[dim][i];
161
163 bin.enter = 0;
164 bin.exit = 0;
165 }
166 }
167
168 /* chop references into bins. */
169 for (unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
170 const BVHReference &ref = references_->at(refIdx);
171 const BoundBox prim_bounds = get_prim_bounds(ref);
172 const float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
173 const float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
174 int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
175 int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
176
177 firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
178 lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
179
180 for (int dim = 0; dim < 3; dim++) {
181 BVHReference currRef(
182 get_prim_bounds(ref), ref.prim_index(), ref.prim_object(), ref.prim_type());
183
184 for (int i = firstBin[dim]; i < lastBin[dim]; i++) {
185 BVHReference leftRef;
186 BVHReference rightRef;
187
189 builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
190 storage_->bins[dim][i].bounds.grow(leftRef.bounds());
191 currRef = rightRef;
192 }
193
194 storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
195 storage_->bins[dim][firstBin[dim]].enter++;
196 storage_->bins[dim][lastBin[dim]].exit++;
197 }
198 }
199
200 /* select best split plane. */
201 storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
202 for (int dim = 0; dim < 3; dim++) {
203 /* sweep right to left and determine bounds. */
204 BoundBox right_bounds = BoundBox::empty;
205 for (int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
206 right_bounds.grow(storage_->bins[dim][i].bounds);
207 storage_->right_bounds[i - 1] = right_bounds;
208 }
209
210 /* sweep left to right and select lowest SAH. */
211 BoundBox left_bounds = BoundBox::empty;
212 int leftNum = 0;
213 int rightNum = range.size();
214
215 for (int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
216 left_bounds.grow(storage_->bins[dim][i - 1].bounds);
217 leftNum += storage_->bins[dim][i - 1].enter;
218 rightNum -= storage_->bins[dim][i - 1].exit;
219
220 const float sah = nodeSAH +
221 left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
222 storage_->right_bounds[i - 1].safe_area() *
223 builder.params.primitive_cost(rightNum);
224
225 if (sah < this->sah) {
226 this->sah = sah;
227 this->dim = dim;
228 this->pos = origin[dim] + binSize[dim] * (float)i;
229 }
230 }
231 }
232}
233
235 BVHRange &left,
236 BVHRange &right,
237 const BVHRange &range)
238{
239 /* Categorize references and compute bounds.
240 *
241 * Left-hand side: [left_start, left_end[
242 * Uncategorized/split: [left_end, right_start[
243 * Right-hand side: [right_start, refs.size()[ */
244
246 const int left_start = range.start();
247 int left_end = left_start;
248 int right_start = range.end();
249 int right_end = range.end();
250 BoundBox left_bounds = BoundBox::empty;
251 BoundBox right_bounds = BoundBox::empty;
252
253 for (int i = left_end; i < right_start; i++) {
254 BoundBox prim_bounds = get_prim_bounds(refs[i]);
255 if (prim_bounds.max[this->dim] <= this->pos) {
256 /* entirely on the left-hand side */
257 left_bounds.grow(prim_bounds);
258 swap(refs[i], refs[left_end++]);
259 }
260 else if (prim_bounds.min[this->dim] >= this->pos) {
261 /* entirely on the right-hand side */
262 right_bounds.grow(prim_bounds);
263 swap(refs[i--], refs[--right_start]);
264 }
265 }
266
267 /* Duplicate or unsplit references intersecting both sides.
268 *
269 * Duplication happens into a temporary pre-allocated vector in order to
270 * reduce number of `memmove()` calls happening in `vector.insert()`.
271 */
272 vector<BVHReference> &new_refs = storage_->new_references;
273 new_refs.clear();
274 new_refs.reserve(right_start - left_end);
275 while (left_end < right_start) {
276 /* split reference. */
277 const BVHReference curr_ref(get_prim_bounds(refs[left_end]),
278 refs[left_end].prim_index(),
279 refs[left_end].prim_object(),
280 refs[left_end].prim_type());
281 BVHReference lref;
282 BVHReference rref;
283 split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
284
285 /* compute SAH for duplicate/unsplit candidates. */
286 BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
287 BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds.
288 BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
289 BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
290
291 lub.grow(curr_ref.bounds());
292 rub.grow(curr_ref.bounds());
293 ldb.grow(lref.bounds());
294 rdb.grow(rref.bounds());
295
296 const float lac = builder->params.primitive_cost(left_end - left_start);
297 const float rac = builder->params.primitive_cost(right_end - right_start);
298 const float lbc = builder->params.primitive_cost(left_end - left_start + 1);
299 const float rbc = builder->params.primitive_cost(right_end - right_start + 1);
300
301 const float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
302 const float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
303 const float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc;
304 const float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
305
306 if (minSAH == unsplitLeftSAH) {
307 /* unsplit to left */
308 left_bounds = lub;
309 left_end++;
310 }
311 else if (minSAH == unsplitRightSAH) {
312 /* unsplit to right */
313 right_bounds = rub;
314 swap(refs[left_end], refs[--right_start]);
315 }
316 else {
317 /* duplicate */
318 left_bounds = ldb;
319 right_bounds = rdb;
320 refs[left_end++] = lref;
321 new_refs.push_back(rref);
322 right_end++;
323 }
324 }
325 /* Insert duplicated references into actual array in one go. */
326 if (!new_refs.empty()) {
327 refs.insert(refs.begin() + (right_end - new_refs.size()), new_refs.begin(), new_refs.end());
328 }
329 if (aligned_space_ != nullptr) {
330 left_bounds = right_bounds = BoundBox::empty;
331 for (int i = left_start; i < left_end - left_start; ++i) {
332 const BoundBox prim_boundbox = references_->at(i).bounds();
333 left_bounds.grow(prim_boundbox);
334 }
335 for (int i = right_start; i < right_end - right_start; ++i) {
336 const BoundBox prim_boundbox = references_->at(i).bounds();
337 right_bounds.grow(prim_boundbox);
338 }
339 }
340 left = BVHRange(left_bounds, left_start, left_end - left_start);
341 right = BVHRange(right_bounds, right_start, right_end - right_start);
342}
343
345 const Transform *tfm,
346 const int prim_index,
347 const int dim,
348 const float pos,
349 BoundBox &left_bounds,
350 BoundBox &right_bounds)
351{
352 const Mesh::Triangle t = mesh->get_triangle(prim_index);
353 const float3 *verts = mesh->verts.data();
354 float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
355 v1 = get_unaligned_point(v1);
356
357 for (int i = 0; i < 3; i++) {
358 float3 v0 = v1;
359 const int vindex = t.v[i];
360 v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
361 v1 = get_unaligned_point(v1);
362 const float v0p = v0[dim];
363 const float v1p = v1[dim];
364
365 /* insert vertex to the boxes it belongs to. */
366 if (v0p <= pos) {
367 left_bounds.grow(v0);
368 }
369
370 if (v0p >= pos) {
371 right_bounds.grow(v0);
372 }
373
374 /* edge intersects the plane => insert intersection to both boxes. */
375 if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
376 const float3 t = mix(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
377 left_bounds.grow(t);
378 right_bounds.grow(t);
379 }
380 }
381}
382
384 const Transform *tfm,
385 const int prim_index,
386 const int segment_index,
387 const int dim,
388 const float pos,
389 BoundBox &left_bounds,
390 BoundBox &right_bounds)
391{
392 /* curve split: NOTE - Currently ignores curve width and needs to be fixed. */
393 const Hair::Curve curve = hair->get_curve(prim_index);
394 const int k0 = curve.first_key + segment_index;
395 const int k1 = k0 + 1;
396 float3 v0 = hair->get_curve_keys()[k0];
397 float3 v1 = hair->get_curve_keys()[k1];
398
399 if (tfm != nullptr) {
400 v0 = transform_point(tfm, v0);
401 v1 = transform_point(tfm, v1);
402 }
403 v0 = get_unaligned_point(v0);
404 v1 = get_unaligned_point(v1);
405
406 const float v0p = v0[dim];
407 const float v1p = v1[dim];
408
409 /* insert vertex to the boxes it belongs to. */
410 if (v0p <= pos) {
411 left_bounds.grow(v0);
412 }
413
414 if (v0p >= pos) {
415 right_bounds.grow(v0);
416 }
417
418 if (v1p <= pos) {
419 left_bounds.grow(v1);
420 }
421
422 if (v1p >= pos) {
423 right_bounds.grow(v1);
424 }
425
426 /* edge intersects the plane => insert intersection to both boxes. */
427 if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
428 const float3 t = mix(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
429 left_bounds.grow(t);
430 right_bounds.grow(t);
431 }
432}
433
435 const Transform *tfm,
436 const int prim_index,
437 const int dim,
438 const float pos,
439 BoundBox &left_bounds,
440 BoundBox &right_bounds)
441{
442 /* No real splitting support for points, assume they are small enough for it
443 * not to matter. */
444 float3 point = pointcloud->get_points()[prim_index];
445 const float radius = pointcloud->get_radius()[prim_index];
446
447 if (tfm != nullptr) {
448 point = transform_point(tfm, point);
449 }
450 point = get_unaligned_point(point);
451
452 if (point[dim] - radius <= pos) {
453 left_bounds.grow(point, radius);
454 }
455
456 if (point[dim] + radius >= pos) {
457 right_bounds.grow(point, radius);
458 }
459}
460
462 const Mesh *mesh,
463 const int dim,
464 const float pos,
465 BoundBox &left_bounds,
466 BoundBox &right_bounds)
467{
468 split_triangle_primitive(mesh, nullptr, ref.prim_index(), dim, pos, left_bounds, right_bounds);
469}
470
472 const Hair *hair,
473 const int dim,
474 const float pos,
475 BoundBox &left_bounds,
476 BoundBox &right_bounds)
477{
479 nullptr,
480 ref.prim_index(),
482 dim,
483 pos,
484 left_bounds,
485 right_bounds);
486}
487
489 const PointCloud *pointcloud,
490 const int dim,
491 const float pos,
492 BoundBox &left_bounds,
493 BoundBox &right_bounds)
494{
496 pointcloud, nullptr, ref.prim_index(), dim, pos, left_bounds, right_bounds);
497}
498
500 const int dim,
501 const float pos,
502 BoundBox &left_bounds,
503 BoundBox &right_bounds)
504{
505 Geometry *geom = object->get_geometry();
506
507 if (geom->is_mesh() || geom->is_volume()) {
508 Mesh *mesh = static_cast<Mesh *>(geom);
509 for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
511 mesh, &object->get_tfm(), tri_idx, dim, pos, left_bounds, right_bounds);
512 }
513 }
514 else if (geom->is_hair()) {
515 Hair *hair = static_cast<Hair *>(geom);
516 for (int curve_idx = 0; curve_idx < hair->num_curves(); ++curve_idx) {
517 const Hair::Curve curve = hair->get_curve(curve_idx);
518 for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) {
520 hair, &object->get_tfm(), curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
521 }
522 }
523 }
524 else if (geom->is_pointcloud()) {
525 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
526 for (int point_idx = 0; point_idx < pointcloud->num_points(); ++point_idx) {
528 pointcloud, &object->get_tfm(), point_idx, dim, pos, left_bounds, right_bounds);
529 }
530 }
531}
532
535 BVHReference &right,
536 const BVHReference &ref,
537 const int dim,
538 const float pos)
539{
540 /* Initialize bounding-boxes. */
541 BoundBox left_bounds = BoundBox::empty;
542 BoundBox right_bounds = BoundBox::empty;
543
544 /* loop over vertices/edges. */
545 const Object *ob = builder.objects[ref.prim_object()];
546
547 if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
548 Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
549 split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
550 }
551 else if (ref.prim_type() & PRIMITIVE_CURVE) {
552 Hair *hair = static_cast<Hair *>(ob->get_geometry());
553 split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
554 }
555 else if (ref.prim_type() & PRIMITIVE_POINT) {
556 PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry());
557 split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds);
558 }
559 else {
560 split_object_reference(ob, dim, pos, left_bounds, right_bounds);
561 }
562
563 /* intersect with original bounds. */
564 left_bounds.max[dim] = pos;
565 right_bounds.min[dim] = pos;
566
567 left_bounds.intersect(ref.bounds());
568 right_bounds.intersect(ref.bounds());
569
570 /* set references */
571 left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
572 right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
573}
574
MINLINE float safe_divide(float a, float b)
vector< Object * > objects
Definition build.h:109
BVHParams params
Definition build.h:122
BVHSpatialStorage * storage_
Definition bvh/split.h:43
vector< BVHReference > * references_
Definition bvh/split.h:44
BVHObjectSplit()=default
BoundBox left_bounds
Definition bvh/split.h:28
BoundBox right_bounds
Definition bvh/split.h:29
__forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
Definition bvh/split.h:48
void split(BVHRange &left, BVHRange &right, const BVHRange &range)
Definition bvh/split.cpp:91
const Transform * aligned_space_
Definition bvh/split.h:46
const BVHUnaligned * unaligned_heuristic_
Definition bvh/split.h:45
@ NUM_SPATIAL_BINS
Definition params.h:111
__forceinline float primitive_cost(const int n) const
Definition params.h:153
__forceinline int size() const
Definition params.h:281
__forceinline int start() const
Definition params.h:277
__forceinline const BoundBox & bounds() const
Definition params.h:269
__forceinline int end() const
Definition params.h:285
__forceinline int prim_type() const
Definition params.h:216
__forceinline int prim_object() const
Definition params.h:212
__forceinline const BoundBox & bounds() const
Definition params.h:204
__forceinline int prim_index() const
Definition params.h:208
const BVHUnaligned * unaligned_heuristic_
Definition bvh/split.h:86
void split_curve_reference(const BVHReference &ref, const Hair *hair, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
__forceinline float3 get_unaligned_point(const float3 &point) const
Definition bvh/split.h:155
__forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
Definition bvh/split.h:147
void split_reference(const BVHBuild &builder, BVHReference &left, BVHReference &right, const BVHReference &ref, const int dim, float pos)
void split_triangle_reference(const BVHReference &ref, const Mesh *mesh, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
BVHSpatialStorage * storage_
Definition bvh/split.h:84
const Transform * aligned_space_
Definition bvh/split.h:87
vector< BVHReference > * references_
Definition bvh/split.h:85
void split_curve_primitive(const Hair *hair, const Transform *tfm, const int prim_index, const int segment_index, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_point_primitive(const PointCloud *pointcloud, const Transform *tfm, const int prim_index, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_triangle_primitive(const Mesh *mesh, const Transform *tfm, const int prim_index, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_object_reference(const Object *object, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range)
void split_point_reference(const BVHReference &ref, const PointCloud *pointcloud, const int dim, const float pos, BoundBox &left_bounds, BoundBox &right_bounds)
BoundBox compute_aligned_boundbox(const BVHObjectBinning &range, const BVHReference *references, const Transform &aligned_space, BoundBox *cent_bounds=nullptr) const
bool is_volume() const
bool is_pointcloud() const
bool is_hair() const
bool is_mesh() const
Definition hair.h:13
Curve get_curve(const size_t i) const
Definition hair.h:111
size_t num_curves() const
Definition hair.h:126
nullptr float
#define PRIMITIVE_UNPACK_SEGMENT(type)
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline int3 make_int3(const int x, const int y, const int z)
static float verts[][3]
#define assert(assertion)
constexpr T clamp(T, U, U) RET
@ PRIMITIVE_CURVE
@ PRIMITIVE_TRIANGLE
@ PRIMITIVE_POINT
static int left
#define mix
#define swap(a, b)
Definition sort.cc:59
#define min(a, b)
Definition sort.cc:36
void bvh_reference_sort(const int start, const int end, BVHReference *data, const int dim, const BVHUnaligned *unaligned_heuristic, const Transform *aligned_space)
Definition sort.cpp:167
#define FLT_MAX
Definition stdcycles.h:14
BoundBox bounds
Definition params.h:298
float3 max
Definition boundbox.h:20
__forceinline void intersect(const BoundBox &bbox)
Definition boundbox.h:85
__forceinline float safe_area() const
Definition boundbox.h:92
__forceinline void grow(const float3 &pt)
Definition boundbox.h:35
float3 min
Definition boundbox.h:20
int first_key
Definition hair.h:19
int num_keys
Definition hair.h:20
size_t num_triangles() const
Definition scene/mesh.h:77
Triangle get_triangle(const size_t i) const
Definition scene/mesh.h:71
size_t num_points() const
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
i
Definition text_draw.cc:230
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56