Blender V4.3
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 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 storage_->right_bounds.resize(range.size());
45
46 for (int dim = 0; dim < 3; dim++) {
47 /* Sort references. */
49 range.end(),
50 &references_->at(0),
51 dim,
54
55 /* sweep right to left and determine bounds. */
57 for (int i = range.size() - 1; i > 0; i--) {
58 BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
59 right_bounds.grow(prim_bounds);
60 storage_->right_bounds[i - 1] = right_bounds;
61 }
62
63 /* sweep left to right and select lowest SAH. */
65
66 for (int i = 1; i < range.size(); i++) {
67 BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
68 left_bounds.grow(prim_bounds);
69 right_bounds = storage_->right_bounds[i - 1];
70
71 float sah = nodeSAH + left_bounds.safe_area() * builder->params.primitive_cost(i) +
72 right_bounds.safe_area() * builder->params.primitive_cost(range.size() - i);
73
74 if (sah < min_sah) {
75 min_sah = sah;
76
77 this->sah = sah;
78 this->dim = dim;
79 this->num_left = i;
80 this->left_bounds = left_bounds;
81 this->right_bounds = right_bounds;
82 }
83 }
84 }
85}
86
88{
89 assert(references_->size() > 0);
90 /* sort references according to split */
92 range.end(),
93 &references_->at(0),
94 this->dim,
97
98 BoundBox effective_left_bounds, effective_right_bounds;
99 const int num_right = range.size() - this->num_left;
100 if (aligned_space_ == NULL) {
101 effective_left_bounds = left_bounds;
102 effective_right_bounds = right_bounds;
103 }
104 else {
105 effective_left_bounds = BoundBox::empty;
106 effective_right_bounds = BoundBox::empty;
107 for (int i = 0; i < this->num_left; ++i) {
108 BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
109 effective_left_bounds.grow(prim_boundbox);
110 }
111 for (int i = 0; i < num_right; ++i) {
112 BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
113 effective_right_bounds.grow(prim_boundbox);
114 }
115 }
116
117 /* split node ranges */
118 left = BVHRange(effective_left_bounds, range.start(), this->num_left);
119 right = BVHRange(effective_right_bounds, left.end(), num_right);
120}
121
122/* Spatial Split */
123
125 BVHSpatialStorage *storage,
126 const BVHRange &range,
127 vector<BVHReference> &references,
128 float nodeSAH,
129 const BVHUnaligned *unaligned_heuristic,
130 const Transform *aligned_space)
131 : sah(FLT_MAX),
132 dim(0),
133 pos(0.0f),
134 storage_(storage),
135 references_(&references),
136 unaligned_heuristic_(unaligned_heuristic),
137 aligned_space_(aligned_space)
138{
139 /* initialize bins. */
140 BoundBox range_bounds;
141 if (aligned_space == NULL) {
142 range_bounds = range.bounds();
143 }
144 else {
145 range_bounds = unaligned_heuristic->compute_aligned_boundbox(
146 range, &references_->at(0), *aligned_space);
147 }
148
149 float3 origin = range_bounds.min;
150 float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
151 float3 invBinSize = 1.0f / binSize;
152
153 for (int dim = 0; dim < 3; dim++) {
154 for (int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
155 BVHSpatialBin &bin = storage_->bins[dim][i];
156
158 bin.enter = 0;
159 bin.exit = 0;
160 }
161 }
162
163 /* chop references into bins. */
164 for (unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
165 const BVHReference &ref = references_->at(refIdx);
166 BoundBox prim_bounds = get_prim_bounds(ref);
167 float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
168 float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
169 int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
170 int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
171
172 firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
173 lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
174
175 for (int dim = 0; dim < 3; dim++) {
176 BVHReference currRef(
177 get_prim_bounds(ref), ref.prim_index(), ref.prim_object(), ref.prim_type());
178
179 for (int i = firstBin[dim]; i < lastBin[dim]; i++) {
180 BVHReference leftRef, rightRef;
181
182 split_reference(
183 builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
184 storage_->bins[dim][i].bounds.grow(leftRef.bounds());
185 currRef = rightRef;
186 }
187
188 storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
189 storage_->bins[dim][firstBin[dim]].enter++;
190 storage_->bins[dim][lastBin[dim]].exit++;
191 }
192 }
193
194 /* select best split plane. */
195 storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
196 for (int dim = 0; dim < 3; dim++) {
197 /* sweep right to left and determine bounds. */
198 BoundBox right_bounds = BoundBox::empty;
199 for (int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
200 right_bounds.grow(storage_->bins[dim][i].bounds);
201 storage_->right_bounds[i - 1] = right_bounds;
202 }
203
204 /* sweep left to right and select lowest SAH. */
205 BoundBox left_bounds = BoundBox::empty;
206 int leftNum = 0;
207 int rightNum = range.size();
208
209 for (int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
210 left_bounds.grow(storage_->bins[dim][i - 1].bounds);
211 leftNum += storage_->bins[dim][i - 1].enter;
212 rightNum -= storage_->bins[dim][i - 1].exit;
213
214 float sah = nodeSAH + left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
215 storage_->right_bounds[i - 1].safe_area() *
216 builder.params.primitive_cost(rightNum);
217
218 if (sah < this->sah) {
219 this->sah = sah;
220 this->dim = dim;
221 this->pos = origin[dim] + binSize[dim] * (float)i;
222 }
223 }
224 }
225}
226
228 BVHRange &left,
229 BVHRange &right,
230 const BVHRange &range)
231{
232 /* Categorize references and compute bounds.
233 *
234 * Left-hand side: [left_start, left_end[
235 * Uncategorized/split: [left_end, right_start[
236 * Right-hand side: [right_start, refs.size()[ */
237
239 int left_start = range.start();
240 int left_end = left_start;
241 int right_start = range.end();
242 int right_end = range.end();
243 BoundBox left_bounds = BoundBox::empty;
244 BoundBox right_bounds = BoundBox::empty;
245
246 for (int i = left_end; i < right_start; i++) {
247 BoundBox prim_bounds = get_prim_bounds(refs[i]);
248 if (prim_bounds.max[this->dim] <= this->pos) {
249 /* entirely on the left-hand side */
250 left_bounds.grow(prim_bounds);
251 swap(refs[i], refs[left_end++]);
252 }
253 else if (prim_bounds.min[this->dim] >= this->pos) {
254 /* entirely on the right-hand side */
255 right_bounds.grow(prim_bounds);
256 swap(refs[i--], refs[--right_start]);
257 }
258 }
259
260 /* Duplicate or unsplit references intersecting both sides.
261 *
262 * Duplication happens into a temporary pre-allocated vector in order to
263 * reduce number of memmove() calls happening in vector.insert().
264 */
265 vector<BVHReference> &new_refs = storage_->new_references;
266 new_refs.clear();
267 new_refs.reserve(right_start - left_end);
268 while (left_end < right_start) {
269 /* split reference. */
270 BVHReference curr_ref(get_prim_bounds(refs[left_end]),
271 refs[left_end].prim_index(),
272 refs[left_end].prim_object(),
273 refs[left_end].prim_type());
274 BVHReference lref, rref;
275 split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
276
277 /* compute SAH for duplicate/unsplit candidates. */
278 BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
279 BoundBox rub = right_bounds; // Unsplit to right: new right-hand bounds.
280 BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
281 BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
282
283 lub.grow(curr_ref.bounds());
284 rub.grow(curr_ref.bounds());
285 ldb.grow(lref.bounds());
286 rdb.grow(rref.bounds());
287
288 float lac = builder->params.primitive_cost(left_end - left_start);
289 float rac = builder->params.primitive_cost(right_end - right_start);
290 float lbc = builder->params.primitive_cost(left_end - left_start + 1);
291 float rbc = builder->params.primitive_cost(right_end - right_start + 1);
292
293 float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
294 float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
295 float duplicateSAH = ldb.safe_area() * lbc + rdb.safe_area() * rbc;
296 float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
297
298 if (minSAH == unsplitLeftSAH) {
299 /* unsplit to left */
300 left_bounds = lub;
301 left_end++;
302 }
303 else if (minSAH == unsplitRightSAH) {
304 /* unsplit to right */
305 right_bounds = rub;
306 swap(refs[left_end], refs[--right_start]);
307 }
308 else {
309 /* duplicate */
310 left_bounds = ldb;
311 right_bounds = rdb;
312 refs[left_end++] = lref;
313 new_refs.push_back(rref);
314 right_end++;
315 }
316 }
317 /* Insert duplicated references into actual array in one go. */
318 if (new_refs.size() != 0) {
319 refs.insert(refs.begin() + (right_end - new_refs.size()), new_refs.begin(), new_refs.end());
320 }
321 if (aligned_space_ != NULL) {
322 left_bounds = right_bounds = BoundBox::empty;
323 for (int i = left_start; i < left_end - left_start; ++i) {
324 BoundBox prim_boundbox = references_->at(i).bounds();
325 left_bounds.grow(prim_boundbox);
326 }
327 for (int i = right_start; i < right_end - right_start; ++i) {
328 BoundBox prim_boundbox = references_->at(i).bounds();
329 right_bounds.grow(prim_boundbox);
330 }
331 }
332 left = BVHRange(left_bounds, left_start, left_end - left_start);
333 right = BVHRange(right_bounds, right_start, right_end - right_start);
334}
335
337 const Transform *tfm,
338 int prim_index,
339 int dim,
340 float pos,
341 BoundBox &left_bounds,
342 BoundBox &right_bounds)
343{
344 Mesh::Triangle t = mesh->get_triangle(prim_index);
345 const float3 *verts = &mesh->verts[0];
346 float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
347 v1 = get_unaligned_point(v1);
348
349 for (int i = 0; i < 3; i++) {
350 float3 v0 = v1;
351 int vindex = t.v[i];
352 v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
353 v1 = get_unaligned_point(v1);
354 float v0p = v0[dim];
355 float v1p = v1[dim];
356
357 /* insert vertex to the boxes it belongs to. */
358 if (v0p <= pos) {
359 left_bounds.grow(v0);
360 }
361
362 if (v0p >= pos) {
363 right_bounds.grow(v0);
364 }
365
366 /* edge intersects the plane => insert intersection to both boxes. */
367 if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
368 float3 t = mix(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
369 left_bounds.grow(t);
370 right_bounds.grow(t);
371 }
372 }
373}
374
376 const Transform *tfm,
377 int prim_index,
378 int segment_index,
379 int dim,
380 float pos,
381 BoundBox &left_bounds,
382 BoundBox &right_bounds)
383{
384 /* curve split: NOTE - Currently ignores curve width and needs to be fixed. */
385 Hair::Curve curve = hair->get_curve(prim_index);
386 const int k0 = curve.first_key + segment_index;
387 const int k1 = k0 + 1;
388 float3 v0 = hair->get_curve_keys()[k0];
389 float3 v1 = hair->get_curve_keys()[k1];
390
391 if (tfm != NULL) {
392 v0 = transform_point(tfm, v0);
393 v1 = transform_point(tfm, v1);
394 }
395 v0 = get_unaligned_point(v0);
396 v1 = get_unaligned_point(v1);
397
398 float v0p = v0[dim];
399 float v1p = v1[dim];
400
401 /* insert vertex to the boxes it belongs to. */
402 if (v0p <= pos) {
403 left_bounds.grow(v0);
404 }
405
406 if (v0p >= pos) {
407 right_bounds.grow(v0);
408 }
409
410 if (v1p <= pos) {
411 left_bounds.grow(v1);
412 }
413
414 if (v1p >= pos) {
415 right_bounds.grow(v1);
416 }
417
418 /* edge intersects the plane => insert intersection to both boxes. */
419 if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
420 float3 t = mix(v0, v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
421 left_bounds.grow(t);
422 right_bounds.grow(t);
423 }
424}
425
427 const Transform *tfm,
428 int prim_index,
429 int dim,
430 float pos,
431 BoundBox &left_bounds,
432 BoundBox &right_bounds)
433{
434 /* No real splitting support for points, assume they are small enough for it
435 * not to matter. */
436 float3 point = pointcloud->get_points()[prim_index];
437 float radius = pointcloud->get_radius()[prim_index];
438
439 if (tfm != NULL) {
441 }
443
444 if (point[dim] <= pos) {
445 left_bounds.grow(point, radius);
446 }
447
448 if (point[dim] >= pos) {
449 right_bounds.grow(point, radius);
450 }
451}
452
454 const Mesh *mesh,
455 int dim,
456 float pos,
457 BoundBox &left_bounds,
458 BoundBox &right_bounds)
459{
460 split_triangle_primitive(mesh, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
461}
462
464 const Hair *hair,
465 int dim,
466 float pos,
467 BoundBox &left_bounds,
468 BoundBox &right_bounds)
469{
471 NULL,
472 ref.prim_index(),
474 dim,
475 pos,
476 left_bounds,
477 right_bounds);
478}
479
481 const PointCloud *pointcloud,
482 int dim,
483 float pos,
484 BoundBox &left_bounds,
485 BoundBox &right_bounds)
486{
487 split_point_primitive(pointcloud, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds);
488}
489
491 const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
492{
493 Geometry *geom = object->get_geometry();
494
496 Mesh *mesh = static_cast<Mesh *>(geom);
497 for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
499 mesh, &object->get_tfm(), tri_idx, dim, pos, left_bounds, right_bounds);
500 }
501 }
502 else if (geom->geometry_type == Geometry::HAIR) {
503 Hair *hair = static_cast<Hair *>(geom);
504 for (int curve_idx = 0; curve_idx < hair->num_curves(); ++curve_idx) {
505 Hair::Curve curve = hair->get_curve(curve_idx);
506 for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) {
508 hair, &object->get_tfm(), curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
509 }
510 }
511 }
512 else if (geom->geometry_type == Geometry::POINTCLOUD) {
513 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
514 for (int point_idx = 0; point_idx < pointcloud->num_points(); ++point_idx) {
516 pointcloud, &object->get_tfm(), point_idx, dim, pos, left_bounds, right_bounds);
517 }
518 }
519}
520
523 BVHReference &right,
524 const BVHReference &ref,
525 int dim,
526 float pos)
527{
528 /* Initialize bounding-boxes. */
529 BoundBox left_bounds = BoundBox::empty;
530 BoundBox right_bounds = BoundBox::empty;
531
532 /* loop over vertices/edges. */
533 const Object *ob = builder.objects[ref.prim_object()];
534
535 if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
536 Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
537 split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
538 }
539 else if (ref.prim_type() & PRIMITIVE_CURVE) {
540 Hair *hair = static_cast<Hair *>(ob->get_geometry());
541 split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
542 }
543 else if (ref.prim_type() & PRIMITIVE_POINT) {
544 PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry());
545 split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds);
546 }
547 else {
548 split_object_reference(ob, dim, pos, left_bounds, right_bounds);
549 }
550
551 /* intersect with original bounds. */
552 left_bounds.max[dim] = pos;
553 right_bounds.min[dim] = pos;
554
555 left_bounds.intersect(ref.bounds());
556 right_bounds.intersect(ref.bounds());
557
558 /* set references */
559 left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
560 right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
561}
562
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
vector< Object * > objects
Definition build.h:97
BVHParams params
Definition build.h:110
BVHSpatialStorage * storage_
Definition bvh/split.h:44
vector< BVHReference > * references_
Definition bvh/split.h:45
BoundBox left_bounds
Definition bvh/split.h:29
BoundBox right_bounds
Definition bvh/split.h:30
__forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
Definition bvh/split.h:49
void split(BVHRange &left, BVHRange &right, const BVHRange &range)
Definition bvh/split.cpp:87
const Transform * aligned_space_
Definition bvh/split.h:47
const BVHUnaligned * unaligned_heuristic_
Definition bvh/split.h:46
@ NUM_SPATIAL_BINS
Definition params.h:112
__forceinline float primitive_cost(int n) const
Definition params.h:154
__forceinline int size() const
Definition params.h:291
__forceinline int start() const
Definition params.h:287
__forceinline const BoundBox & bounds() const
Definition params.h:279
__forceinline int end() const
Definition params.h:295
__forceinline int prim_type() const
Definition params.h:217
__forceinline int prim_object() const
Definition params.h:213
__forceinline const BoundBox & bounds() const
Definition params.h:205
__forceinline int prim_index() const
Definition params.h:209
void split_point_primitive(const PointCloud *pointcloud, const Transform *tfm, int prim_index, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_curve_primitive(const Hair *hair, const Transform *tfm, int prim_index, int segment_index, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
const BVHUnaligned * unaligned_heuristic_
Definition bvh/split.h:89
void split_curve_reference(const BVHReference &ref, const Hair *hair, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_triangle_primitive(const Mesh *mesh, const Transform *tfm, int prim_index, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
__forceinline float3 get_unaligned_point(const float3 &point) const
Definition bvh/split.h:157
__forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
Definition bvh/split.h:147
BVHSpatialStorage * storage_
Definition bvh/split.h:87
void split_object_reference(const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
const Transform * aligned_space_
Definition bvh/split.h:90
vector< BVHReference > * references_
Definition bvh/split.h:88
void split_triangle_reference(const BVHReference &ref, const Mesh *mesh, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_point_reference(const BVHReference &ref, const PointCloud *pointcloud, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
void split_reference(const BVHBuild &builder, BVHReference &left, BVHReference &right, const BVHReference &ref, int dim, float pos)
void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range)
BoundBox compute_aligned_boundbox(const BVHObjectBinning &range, const BVHReference *references, const Transform &aligned_space, BoundBox *cent_bounds=NULL) const
Definition unaligned.cpp:98
Type geometry_type
Definition hair.h:14
Curve get_curve(size_t i) const
Definition hair.h:112
size_t num_curves() const
Definition hair.h:126
#define CCL_NAMESPACE_END
#define NULL
draw_view in_light_buf[] float
static float verts[][3]
#define mix(a, b, c)
Definition hash.h:36
@ PRIMITIVE_CURVE
@ PRIMITIVE_TRIANGLE
@ PRIMITIVE_POINT
#define PRIMITIVE_UNPACK_SEGMENT(type)
static int left
#define swap(a, b)
Definition sort.c:55
#define min(a, b)
Definition sort.c:32
void bvh_reference_sort(int start, int end, BVHReference *data, int dim, const BVHUnaligned *unaligned_heuristic, const Transform *aligned_space)
Definition sort.cpp:162
#define FLT_MAX
Definition stdcycles.h:14
BoundBox bounds
Definition params.h:308
float3 max
Definition boundbox.h:21
__forceinline void intersect(const BoundBox &bbox)
Definition boundbox.h:86
__forceinline float safe_area() const
Definition boundbox.h:93
__forceinline void grow(const float3 &pt)
Definition boundbox.h:36
float3 min
Definition boundbox.h:21
int first_key
Definition hair.h:20
int num_keys
Definition hair.h:21
Triangle get_triangle(size_t i) const
Definition scene/mesh.h:74
size_t num_triangles() const
Definition scene/mesh.h:80
size_t num_points() const
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379