Blender V5.0
embree.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2018-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5/* This class implements a ray accelerator for Cycles using Intel's Embree library.
6 * It supports triangles, curves, object and deformation blur and instancing.
7 *
8 * Since Embree allows object to be either curves or triangles but not both, Cycles object IDs are
9 * mapped to Embree IDs by multiplying by two and adding one for curves.
10 *
11 * This implementation shares RTCDevices between Cycles instances. Eventually each instance should
12 * get a separate RTCDevice to correctly keep track of memory usage.
13 *
14 * Vertex and index buffers are duplicated between Cycles device arrays and Embree. These could be
15 * merged, which would require changes to intersection refinement, shader setup, mesh light
16 * sampling and a few other places in Cycles where direct access to vertex data is required.
17 */
18
19#ifdef WITH_EMBREE
20
21# include <embree4/rtcore_geometry.h>
22
23# include "bvh/embree.h"
24
25# include "scene/hair.h"
26# include "scene/mesh.h"
27# include "scene/object.h"
28# include "scene/pointcloud.h"
29
30# include "util/log.h"
31# include "util/progress.h"
32# include "util/stats.h"
33
35
36static_assert(Object::MAX_MOTION_STEPS <= RTC_MAX_TIME_STEP_COUNT,
37 "Object and Embree max motion steps inconsistent");
39 "Object and Geometry max motion steps inconsistent");
40
41static size_t unaccounted_mem = 0;
42
43static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool /*unused*/)
44{
45 Stats *stats = (Stats *)userPtr;
46 if (stats) {
47 if (bytes > 0) {
48 stats->mem_alloc(bytes);
49 }
50 else {
51 stats->mem_free(-bytes);
52 }
53 }
54 else {
55 /* A stats pointer may not yet be available. Keep track of the memory usage for later. */
56 if (bytes >= 0) {
57 atomic_add_and_fetch_z(&unaccounted_mem, bytes);
58 }
59 else {
60 atomic_sub_and_fetch_z(&unaccounted_mem, -bytes);
61 }
62 }
63 return true;
64}
65
66static void rtc_error_func(void * /*unused*/, enum RTCError /*unused*/, const char *str)
67{
69}
70
71static double progress_start_time = 0.0;
72
73static bool rtc_progress_func(void *user_ptr, const double n)
74{
75 Progress *progress = (Progress *)user_ptr;
76
77 if (time_dt() - progress_start_time < 0.25) {
78 return true;
79 }
80
81 const string msg = string_printf("Building BVH %.0f%%", n * 100.0);
82 progress->set_substatus(msg);
83 progress_start_time = time_dt();
84
85 return !progress->get_cancel();
86}
87
88BVHEmbree::BVHEmbree(const BVHParams &params_,
89 const vector<Geometry *> &geometry_,
90 const vector<Object *> &objects_)
91 : BVH(params_, geometry_, objects_),
92 scene(nullptr),
93 rtc_device(nullptr),
94 build_quality(RTC_BUILD_QUALITY_REFIT)
95{
97}
98
99BVHEmbree::~BVHEmbree()
100{
101 if (scene) {
102 rtcReleaseScene(scene);
103 }
104}
105
106void BVHEmbree::build(Progress &progress,
107 Stats *stats,
108 RTCDevice rtc_device_,
109 const bool rtc_device_is_sycl_)
110{
111 rtc_device = rtc_device_;
112 rtc_device_is_sycl = rtc_device_is_sycl_;
113 assert(rtc_device);
114
115 rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, nullptr);
116 rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
117
118 progress.set_substatus("Building BVH");
119
120 if (scene) {
121 rtcReleaseScene(scene);
122 scene = nullptr;
123 }
124
125 const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
126 const bool compact = params.use_compact_structure;
127
128 scene = rtcNewScene(rtc_device);
129 const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
130 (compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
131 RTC_SCENE_FLAG_ROBUST |
132 RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS;
133 rtcSetSceneFlags(scene, scene_flags);
134 build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
135 (params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
136 RTC_BUILD_QUALITY_MEDIUM);
137 rtcSetSceneBuildQuality(scene, build_quality);
138
139 int i = 0;
140 for (Object *ob : objects) {
141 if (params.top_level) {
142 if (!ob->is_traceable()) {
143 ++i;
144 continue;
145 }
146 if (!ob->get_geometry()->is_instanced()) {
147 add_object(ob, i);
148 }
149 else {
150 add_instance(ob, i);
151 }
152 }
153 else {
154 add_object(ob, i);
155 }
156 ++i;
157 if (progress.get_cancel()) {
158 return;
159 }
160 }
161
162 if (progress.get_cancel()) {
163 return;
164 }
165
166 rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
167 rtcCommitScene(scene);
168}
169
170const char *BVHEmbree::get_error_string(RTCError error_code)
171{
172# if RTC_VERSION >= 40303
173 return rtcGetErrorString(error_code);
174# else
175 switch (error_code) {
176 case RTC_ERROR_NONE:
177 return "no error";
178 case RTC_ERROR_UNKNOWN:
179 return "unknown error";
180 case RTC_ERROR_INVALID_ARGUMENT:
181 return "invalid argument error";
182 case RTC_ERROR_INVALID_OPERATION:
183 return "invalid operation error";
184 case RTC_ERROR_OUT_OF_MEMORY:
185 return "out of memory error";
186 case RTC_ERROR_UNSUPPORTED_CPU:
187 return "unsupported cpu error";
188 case RTC_ERROR_CANCELLED:
189 return "cancelled";
190 default:
191 /* We should never end here unless enum for RTC errors would change. */
192 return "unknown error";
193 }
194# endif
195}
196
197# if defined(WITH_EMBREE_GPU) && RTC_VERSION >= 40302
198/* offload_scenes_to_gpu() uses rtcGetDeviceError() which also resets Embree error status,
199 * we propagate its value so it doesn't get lost. */
200RTCError BVHEmbree::offload_scenes_to_gpu(const vector<RTCScene> &scenes)
201{
202 /* Having BVH on GPU is more performance-critical than texture data.
203 * In order to ensure good performance even when running out of GPU
204 * memory, we force BVH to migrate to GPU before allocating other textures
205 * that may not fit. */
206 for (const RTCScene &embree_scene : scenes) {
207 RTCSceneFlags scene_flags = rtcGetSceneFlags(embree_scene);
208 scene_flags = scene_flags | RTC_SCENE_FLAG_PREFETCH_USM_SHARED_ON_GPU;
209 rtcSetSceneFlags(embree_scene, scene_flags);
210 rtcCommitScene(embree_scene);
211 /* In case of any errors from Embree, we should stop
212 * the execution and propagate the error. */
213 RTCError error_code = rtcGetDeviceError(rtc_device);
214 if (error_code != RTC_ERROR_NONE) {
215 return error_code;
216 }
217 }
218 return RTC_ERROR_NONE;
219}
220# endif
221
222void BVHEmbree::add_object(Object *ob, const int i)
223{
224 Geometry *geom = ob->get_geometry();
225
226 if (geom->is_mesh() || geom->is_volume()) {
227 Mesh *mesh = static_cast<Mesh *>(geom);
228 if (mesh->num_triangles() > 0) {
229 add_triangles(ob, mesh, i);
230 }
231 }
232 else if (geom->is_hair()) {
233 Hair *hair = static_cast<Hair *>(geom);
234 if (hair->is_traceable()) {
235 add_curves(ob, hair, i);
236 }
237 }
238 else if (geom->is_pointcloud()) {
239 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
240 if (pointcloud->num_points() > 0) {
241 add_points(ob, pointcloud, i);
242 }
243 }
244}
245
246void BVHEmbree::add_instance(Object *ob, const int i)
247{
248 BVHEmbree *instance_bvh = static_cast<BVHEmbree *>(ob->get_geometry()->bvh.get());
249 assert(instance_bvh != nullptr);
250
251 const size_t num_object_motion_steps = ob->use_motion() ? ob->get_motion().size() : 1;
252 const size_t num_motion_steps = min(num_object_motion_steps, (size_t)RTC_MAX_TIME_STEP_COUNT);
253 assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
254
255 RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_INSTANCE);
256 rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
257 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
258
259 if (ob->use_motion()) {
260 array<DecomposedTransform> decomp(ob->get_motion().size());
261 transform_motion_decompose(decomp.data(), ob->get_motion().data(), ob->get_motion().size());
262 for (size_t step = 0; step < num_motion_steps; ++step) {
263 RTCQuaternionDecomposition rtc_decomp;
264 rtcInitQuaternionDecomposition(&rtc_decomp);
265 rtcQuaternionDecompositionSetQuaternion(
266 &rtc_decomp, decomp[step].x.w, decomp[step].x.x, decomp[step].x.y, decomp[step].x.z);
267 rtcQuaternionDecompositionSetScale(
268 &rtc_decomp, decomp[step].y.w, decomp[step].z.w, decomp[step].w.w);
269 rtcQuaternionDecompositionSetTranslation(
270 &rtc_decomp, decomp[step].y.x, decomp[step].y.y, decomp[step].y.z);
271 rtcQuaternionDecompositionSetSkew(
272 &rtc_decomp, decomp[step].z.x, decomp[step].z.y, decomp[step].w.x);
273 rtcSetGeometryTransformQuaternion(geom_id, step, &rtc_decomp);
274 }
275 }
276 else {
277 rtcSetGeometryTransform(
278 geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->get_tfm());
279 }
280
281 rtcSetGeometryUserData(geom_id,
282# if RTC_VERSION >= 40400
283 (void *)rtcGetSceneTraversable(instance_bvh->scene)
284# else
285 (void *)instance_bvh->scene
286# endif
287 );
288
289 rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
290 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
291
292 rtcCommitGeometry(geom_id);
293 rtcAttachGeometryByID(scene, geom_id, i * 2);
294 rtcReleaseGeometry(geom_id);
295}
296
297void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, const int i)
298{
299 const size_t prim_offset = mesh->prim_offset;
300
301 const Attribute *attr_mP = nullptr;
302 size_t num_motion_steps = 1;
303 if (mesh->has_motion_blur()) {
305 if (attr_mP) {
306 num_motion_steps = mesh->get_motion_steps();
307 }
308 }
309
310 assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
311 num_motion_steps = min(num_motion_steps, (size_t)RTC_MAX_TIME_STEP_COUNT);
312
313 const size_t num_triangles = mesh->num_triangles();
314
315 RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
316 rtcSetGeometryBuildQuality(geom_id, build_quality);
317 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
318
319 const int *triangles = mesh->get_triangles().data();
320 if (!rtc_device_is_sycl) {
321 rtcSetSharedGeometryBuffer(geom_id,
322 RTC_BUFFER_TYPE_INDEX,
323 0,
324 RTC_FORMAT_UINT3,
325 triangles,
326 0,
327 sizeof(int) * 3,
328 num_triangles);
329 }
330 else {
331 /* NOTE(sirgienko): If the Embree device is a SYCL device, then Embree execution will
332 * happen on GPU, and we cannot use standard host pointers at this point. So instead
333 * of making a shared geometry buffer - a new Embree buffer will be created and data
334 * will be copied. */
335 int *triangles_buffer = nullptr;
336# if RTC_VERSION >= 40400
337 rtcSetNewGeometryBufferHostDevice(
338# else
339 triangles_buffer = (int *)rtcSetNewGeometryBuffer(
340# endif
341 geom_id,
342 RTC_BUFFER_TYPE_INDEX,
343 0,
344 RTC_FORMAT_UINT3,
345 sizeof(int) * 3,
346 num_triangles
347# if RTC_VERSION >= 40400
348 ,
349 (void **)(&triangles_buffer),
350 nullptr
351# endif
352 );
353 assert(triangles_buffer);
354 if (triangles_buffer) {
355 static_assert(sizeof(int) == sizeof(uint));
356 std::memcpy(triangles_buffer, triangles, sizeof(int) * 3 * (num_triangles));
357 }
358 }
359 set_tri_vertex_buffer(geom_id, mesh, false);
360
361 rtcSetGeometryUserData(geom_id, (void *)prim_offset);
362 rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
363 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
364
365 rtcCommitGeometry(geom_id);
366 rtcAttachGeometryByID(scene, geom_id, i * 2);
367 rtcReleaseGeometry(geom_id);
368}
369
370void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update)
371{
372 const Attribute *attr_mP = nullptr;
373 size_t num_motion_steps = 1;
374 int t_mid = 0;
375 if (mesh->has_motion_blur()) {
377 if (attr_mP) {
378 num_motion_steps = mesh->get_motion_steps();
379 t_mid = (num_motion_steps - 1) / 2;
380 if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
381 assert(0);
382 num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
383 }
384 }
385 }
386 const size_t num_verts = mesh->get_verts().size();
387
388 for (int t = 0; t < num_motion_steps; ++t) {
389 const float3 *verts;
390 if (t == t_mid) {
391 verts = mesh->get_verts().data();
392 }
393 else {
394 const int t_ = (t > t_mid) ? (t - 1) : t;
395 verts = &attr_mP->data_float3()[t_ * num_verts];
396 }
397
398 if (update) {
399 rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
400 }
401 else {
402 if (!rtc_device_is_sycl) {
403 static_assert(sizeof(float3) == 16,
404 "Embree requires that each buffer element be readable with 16-byte SSE load "
405 "instructions");
406 rtcSetSharedGeometryBuffer(geom_id,
407 RTC_BUFFER_TYPE_VERTEX,
408 t,
409 RTC_FORMAT_FLOAT3,
410 verts,
411 0,
412 sizeof(float3),
413 num_verts);
414 }
415 else {
416 /* NOTE(sirgienko): If the Embree device is a SYCL device, then Embree execution will
417 * happen on GPU, and we cannot use standard host pointers at this point. So instead
418 * of making a shared geometry buffer - a new Embree buffer will be created and data
419 * will be copied. */
420 /* As float3 is packed on GPU side, we map it to packed_float3. */
421 /* There is no need for additional padding in rtcSetNewGeometryBuffer since Embree 3.6:
422 * "Fixed automatic vertex buffer padding when using rtcSetNewGeometry API function". */
423 packed_float3 *verts_buffer = nullptr;
424# if RTC_VERSION >= 40400
425 rtcSetNewGeometryBufferHostDevice(
426# else
427 verts_buffer = (packed_float3 *)rtcSetNewGeometryBuffer(
428# endif
429 geom_id,
430 RTC_BUFFER_TYPE_VERTEX,
431 t,
432 RTC_FORMAT_FLOAT3,
433 sizeof(packed_float3),
434 num_verts
435# if RTC_VERSION >= 40400
436 ,
437 (void **)(&verts_buffer),
438 nullptr
439# endif
440 );
441 assert(verts_buffer);
442 if (verts_buffer) {
443 for (size_t i = (size_t)0; i < num_verts; ++i) {
444 verts_buffer[i].x = verts[i].x;
445 verts_buffer[i].y = verts[i].y;
446 verts_buffer[i].z = verts[i].z;
447 }
448 }
449 }
450 }
451 }
452}
453
457template<typename T>
458void pack_motion_verts(const size_t num_curves,
459 const Hair *hair,
460 const T *verts,
461 const float *curve_radius,
462 float4 *rtc_verts,
463 CurveShapeType curve_shape)
464{
465 for (size_t j = 0; j < num_curves; ++j) {
466 const Hair::Curve c = hair->get_curve(j);
467 int fk = c.first_key;
468
469 if (curve_shape == CURVE_THICK_LINEAR) {
470 for (int k = 0; k < c.num_keys; ++k, ++fk) {
471 rtc_verts[k].x = verts[fk].x;
472 rtc_verts[k].y = verts[fk].y;
473 rtc_verts[k].z = verts[fk].z;
474 rtc_verts[k].w = curve_radius[fk];
475 }
476 rtc_verts += c.num_keys;
477 }
478 else {
479 for (int k = 1; k < c.num_keys + 1; ++k, ++fk) {
480 rtc_verts[k].x = verts[fk].x;
481 rtc_verts[k].y = verts[fk].y;
482 rtc_verts[k].z = verts[fk].z;
483 rtc_verts[k].w = curve_radius[fk];
484 }
485 /* Duplicate Embree's Catmull-Rom spline CVs at the start and end of each curve. */
486 rtc_verts[0] = rtc_verts[1];
487 rtc_verts[c.num_keys + 1] = rtc_verts[c.num_keys];
488 rtc_verts += c.num_keys + 2;
489 }
490 }
491}
492
493void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update)
494{
495 const Attribute *attr_mP = nullptr;
496 size_t num_motion_steps = 1;
497 if (hair->has_motion_blur()) {
499 if (attr_mP) {
500 num_motion_steps = hair->get_motion_steps();
501 }
502 }
503
504 const size_t num_curves = hair->num_curves();
505 size_t num_keys = 0;
506 for (size_t j = 0; j < num_curves; ++j) {
507 const Hair::Curve c = hair->get_curve(j);
508 num_keys += c.num_keys;
509 }
510
511 /* Catmull-Rom splines need extra CVs at the beginning and end of each curve. */
512 size_t num_keys_embree = num_keys;
513 num_keys_embree += num_curves * 2;
514
515 /* Copy the CV data to Embree */
516 const int t_mid = (num_motion_steps - 1) / 2;
517 const float *curve_radius = hair->get_curve_radius().data();
518 for (int t = 0; t < num_motion_steps; ++t) {
519 // As float4 and float3 are no longer interchangeable the 2 types need to be
520 // handled separately. Attributes are float4s where the radius is stored in w and
521 // the middle motion vector is from the mesh points which are stored float3s with
522 // the radius stored in another array.
523 float4 *rtc_verts = nullptr;
524 if (update) {
525 rtc_verts = (float4 *)rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
526 }
527 else {
528# if RTC_VERSION >= 40400
529 rtcSetNewGeometryBufferHostDevice(
530# else
531 rtc_verts = (float4 *)rtcSetNewGeometryBuffer(
532# endif
533 geom_id,
534 RTC_BUFFER_TYPE_VERTEX,
535 t,
536 RTC_FORMAT_FLOAT4,
537 sizeof(float) * 4,
538 num_keys_embree
539# if RTC_VERSION >= 40400
540 ,
541 (void **)(&rtc_verts),
542 nullptr
543# endif
544 );
545 }
546
547 assert(rtc_verts);
548 if (rtc_verts) {
549 const size_t num_curves = hair->num_curves();
550 if (t == t_mid || attr_mP == nullptr) {
551 const float3 *verts = hair->get_curve_keys().data();
552 pack_motion_verts<float3>(
553 num_curves, hair, verts, curve_radius, rtc_verts, hair->curve_shape);
554 }
555 else {
556 const int t_ = (t > t_mid) ? (t - 1) : t;
557 const float4 *verts = &attr_mP->data_float4()[t_ * num_keys];
558 pack_motion_verts<float4>(
559 num_curves, hair, verts, curve_radius, rtc_verts, hair->curve_shape);
560 }
561 }
562
563 if (update) {
564 rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
565 }
566 }
567}
568
569void BVHEmbree::set_point_vertex_buffer(RTCGeometry geom_id,
570 const PointCloud *pointcloud,
571 const bool update)
572{
573 const Attribute *attr_mP = nullptr;
574 size_t num_motion_steps = 1;
575 if (pointcloud->has_motion_blur()) {
576 attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
577 if (attr_mP) {
578 num_motion_steps = pointcloud->get_motion_steps();
579 }
580 }
581
582 const size_t num_points = pointcloud->num_points();
583
584 /* Copy the point data to Embree */
585 const int t_mid = (num_motion_steps - 1) / 2;
586 const float *radius = pointcloud->get_radius().data();
587 for (int t = 0; t < num_motion_steps; ++t) {
588 // As float4 and float3 are no longer interchangeable the 2 types need to be
589 // handled separately. Attributes are float4s where the radius is stored in w and
590 // the middle motion vector is from the mesh points which are stored float3s with
591 // the radius stored in another array.
592
593 float4 *rtc_verts = nullptr;
594 if (update) {
595 rtc_verts = (float4 *)rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
596 }
597 else {
598# if RTC_VERSION >= 40400
599 rtcSetNewGeometryBufferHostDevice(
600# else
601 rtc_verts = (float4 *)rtcSetNewGeometryBuffer(
602# endif
603 geom_id,
604 RTC_BUFFER_TYPE_VERTEX,
605 t,
606 RTC_FORMAT_FLOAT4,
607 sizeof(float) * 4,
608 num_points
609# if RTC_VERSION >= 40400
610 ,
611 (void **)(&rtc_verts),
612 nullptr
613# endif
614 );
615 }
616
617 assert(rtc_verts);
618 if (rtc_verts) {
619 if (t == t_mid || attr_mP == nullptr) {
620 /* Pack the motion points into a float4 as [x y z radius]. */
621 const float3 *verts = pointcloud->get_points().data();
622 for (size_t j = 0; j < num_points; ++j) {
623 rtc_verts[j].x = verts[j].x;
624 rtc_verts[j].y = verts[j].y;
625 rtc_verts[j].z = verts[j].z;
626 rtc_verts[j].w = radius[j];
627 }
628 }
629 else {
630 /* Motion blur is already packed as [x y z radius]. */
631 const int t_ = (t > t_mid) ? (t - 1) : t;
632 const float4 *verts = &attr_mP->data_float4()[t_ * num_points];
633 std::copy_n(verts, num_points, rtc_verts);
634 }
635 }
636
637 if (update) {
638 rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
639 }
640 }
641}
642
643void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, const int i)
644{
645 const size_t prim_offset = pointcloud->prim_offset;
646
647 const Attribute *attr_mP = nullptr;
648 size_t num_motion_steps = 1;
649 if (pointcloud->has_motion_blur()) {
650 attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
651 if (attr_mP) {
652 num_motion_steps = pointcloud->get_motion_steps();
653 }
654 }
655
656 const enum RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
657
658 RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
659
660 rtcSetGeometryBuildQuality(geom_id, build_quality);
661 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
662
663 set_point_vertex_buffer(geom_id, pointcloud, false);
664
665 rtcSetGeometryUserData(geom_id, (void *)prim_offset);
666 rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
667 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
668
669 rtcCommitGeometry(geom_id);
670 rtcAttachGeometryByID(scene, geom_id, i * 2);
671 rtcReleaseGeometry(geom_id);
672}
673
674void BVHEmbree::add_curves(const Object *ob, const Hair *hair, const int i)
675{
676 const size_t prim_offset = hair->curve_segment_offset;
677
678 const Attribute *attr_mP = nullptr;
679 size_t num_motion_steps = 1;
680 if (hair->has_motion_blur()) {
682 if (attr_mP) {
683 num_motion_steps = hair->get_motion_steps();
684 }
685 }
686
687 assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
688 num_motion_steps = min(num_motion_steps, (size_t)RTC_MAX_TIME_STEP_COUNT);
689
690 const size_t num_curves = hair->num_curves();
691 size_t num_segments = 0;
692 for (size_t j = 0; j < num_curves; ++j) {
693 const Hair::Curve c = hair->get_curve(j);
694 assert(c.num_segments() > 0);
695 num_segments += c.num_segments();
696 }
697
698 const enum RTCGeometryType type = (hair->curve_shape == CURVE_THICK_LINEAR ?
699 RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE :
700 hair->curve_shape == CURVE_RIBBON ?
701 RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
702 RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
703
704 RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
705 rtcSetGeometryTessellationRate(geom_id, params.curve_subdivisions + 1);
706 unsigned *rtc_indices = nullptr;
707# if RTC_VERSION >= 40400
708 rtcSetNewGeometryBufferHostDevice(
709# else
710 rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
711# endif
712 geom_id,
713 RTC_BUFFER_TYPE_INDEX,
714 0,
715 RTC_FORMAT_UINT,
716 sizeof(int),
717 num_segments
718# if RTC_VERSION >= 40400
719 ,
720 (void **)(&rtc_indices),
721 nullptr
722# endif
723 );
724
725 size_t rtc_index = 0;
726 for (size_t j = 0; j < num_curves; ++j) {
727 const Hair::Curve c = hair->get_curve(j);
728 for (size_t k = 0; k < c.num_segments(); ++k) {
729 rtc_indices[rtc_index] = c.first_key + k;
730 if (hair->curve_shape != CURVE_THICK_LINEAR) {
731 /* Room for extra CVs at Catmull-Rom splines. */
732 rtc_indices[rtc_index] += j * 2;
733 }
734
735 ++rtc_index;
736 }
737 }
738
739 rtcSetGeometryBuildQuality(geom_id, build_quality);
740 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
741
742 set_curve_vertex_buffer(geom_id, hair, false);
743
744 rtcSetGeometryUserData(geom_id, (void *)prim_offset);
745 rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
746 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
747
748 rtcCommitGeometry(geom_id);
749 rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
750 rtcReleaseGeometry(geom_id);
751}
752
753void BVHEmbree::refit(Progress &progress)
754{
755 progress.set_substatus("Refitting BVH nodes");
756
757 /* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
758 unsigned geom_id = 0;
759 for (Object *ob : objects) {
760 if (!params.top_level || (ob->is_traceable() && !ob->get_geometry()->is_instanced())) {
761 Geometry *geom = ob->get_geometry();
762
763 if (geom->is_mesh() || geom->is_volume()) {
764 Mesh *mesh = static_cast<Mesh *>(geom);
765 if (mesh->num_triangles() > 0) {
766 RTCGeometry geom = rtcGetGeometry(scene, geom_id);
767 set_tri_vertex_buffer(geom, mesh, true);
768 rtcSetGeometryUserData(geom, (void *)mesh->prim_offset);
769 rtcCommitGeometry(geom);
770 }
771 }
772 else if (geom->is_hair()) {
773 Hair *hair = static_cast<Hair *>(geom);
774 if (hair->is_traceable()) {
775 RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1);
776 set_curve_vertex_buffer(geom, hair, true);
777 rtcSetGeometryUserData(geom, (void *)hair->curve_segment_offset);
778 rtcCommitGeometry(geom);
779 }
780 }
781 else if (geom->is_pointcloud()) {
782 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
783 if (pointcloud->num_points() > 0) {
784 RTCGeometry geom = rtcGetGeometry(scene, geom_id);
785 set_point_vertex_buffer(geom, pointcloud, true);
786 rtcCommitGeometry(geom);
787 }
788 }
789 }
790 geom_id += 2;
791 }
792
793 rtcCommitScene(scene);
794}
795
797
798#endif /* WITH_EMBREE */
unsigned int uint
ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x)
ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
Attribute * find(ustring name) const
Definition bvh/bvh.h:67
static const uint MAX_MOTION_STEPS
bool is_volume() const
bool is_pointcloud() const
bool is_hair() const
size_t prim_offset
virtual bool has_motion_blur() const
AttributeSet attributes
bool is_mesh() const
Definition hair.h:13
bool is_traceable() const
Definition hair.h:136
Curve get_curve(const size_t i) const
Definition hair.h:111
size_t curve_segment_offset
Definition hair.h:90
size_t num_curves() const
Definition hair.h:126
CurveShapeType curve_shape
Definition hair.h:91
void set_substatus(const string &substatus_)
Definition progress.h:259
bool get_cancel() const
Definition progress.h:77
void mem_alloc(const size_t size)
Definition util/stats.h:18
void mem_free(const size_t size)
Definition util/stats.h:24
#define SIMD_SET_FLUSH_TO_ZERO
#define CCL_NAMESPACE_END
#define str(s)
static float verts[][3]
#define assert(assertion)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
@ ATTR_STD_MOTION_VERTEX_POSITION
CurveShapeType
@ CURVE_RIBBON
@ CURVE_THICK_LINEAR
#define LOG_WARNING
Definition log.h:103
#define T
void add_curves(bke::CurvesGeometry &curves, const Span< int > new_sizes)
static void update(bNodeTree *ntree)
@ BVH_TYPE_DYNAMIC
Definition params.h:33
#define min(a, b)
Definition sort.cc:36
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
float3 * data_float3()
float4 * data_float4()
int first_key
Definition hair.h:19
int num_segments() const
Definition hair.h:22
int num_keys
Definition hair.h:20
bool has_motion_blur() const override
size_t num_triangles() const
Definition scene/mesh.h:77
bool use_motion() const
static const uint MAX_MOTION_STEPS
bool is_traceable() const
uint visibility_for_tracing() const
size_t num_points() const
float y
Definition sky_math.h:225
float z
Definition sky_math.h:225
float x
Definition sky_math.h:225
float w
Definition sky_math.h:225
i
Definition text_draw.cc:230
CCL_NAMESPACE_BEGIN double time_dt()
Definition time.cpp:47
void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, const size_t size)