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