Lagrange
Loading...
Searching...
No Matches
EmbreeRayCaster.h
1/*
2 * Copyright 2017 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#ifdef LAGRANGE_WITH_EMBREE_3
15 #include <embree3/rtcore.h>
16 #include <embree3/rtcore_geometry.h>
17 #include <embree3/rtcore_ray.h>
18#else
19 #include <embree4/rtcore.h>
20 #include <embree4/rtcore_geometry.h>
21 #include <embree4/rtcore_ray.h>
22#endif
23
24#include <lagrange/common.h>
25#include <lagrange/legacy/inline.h>
26#include <lagrange/raycasting/ClosestPointResult.h>
27#include <lagrange/raycasting/EmbreeHelper.h>
28#include <lagrange/raycasting/RayCasterMesh.h>
29#include <lagrange/raycasting/embree_closest_point.h>
30#include <lagrange/utils/safe_cast.h>
31
32#include <cassert>
33#include <cmath>
34#include <exception>
35#include <functional>
36#include <iostream>
37#include <limits>
38#include <list>
39#include <memory>
40#include <sstream>
41#include <string>
42#include <vector>
43
44RTC_NAMESPACE_USE
45
46namespace lagrange {
47namespace raycasting {
48LAGRANGE_LEGACY_INLINE
49namespace legacy {
50
57template <typename ScalarType>
59{
60public:
61 using Scalar = ScalarType;
62 using Transform = Eigen::Matrix<Scalar, 4, 4>;
63 using Point = Eigen::Matrix<Scalar, 3, 1>;
64 using Direction = Eigen::Matrix<Scalar, 3, 1>;
65 using Index = size_t;
66 using ClosestPoint = ClosestPointResult<Scalar>;
67 using TransformVector = std::vector<Transform>;
68
69 using Point4 = Eigen::Matrix<Scalar, 4, 3>;
70 using Direction4 = Eigen::Matrix<Scalar, 4, 3>;
71 using Index4 = Eigen::Matrix<size_t, 4, 1>;
72 using Scalar4 = Eigen::Matrix<Scalar, 4, 1>;
73 using Mask4 = Eigen::Matrix<std::int32_t, 4, 1>;
74
75 using FloatData = std::vector<float>;
76 using IntData = std::vector<unsigned>;
77
92 using FilterFunction = std::function<void(
93 const EmbreeRayCaster* obj,
94 const Index* mesh_index,
95 const Index* instance_index,
96 const RTCFilterFunctionNArguments* args)>;
97
98private:
100 enum { FILTER_INTERSECT = 0, FILTER_OCCLUDED = 1 };
101
102public:
105 RTCSceneFlags scene_flags = RTC_SCENE_FLAG_DYNAMIC,
106 RTCBuildQuality build_quality = RTC_BUILD_QUALITY_LOW)
107 {
108// Embree strongly recommend to have the Flush to Zero and
109// Denormals are Zero mode of the MXCSR control and status
110// register enabled for each thread before calling the
111// rtcIntersect and rtcOccluded functions.
112#ifdef _MM_SET_FLUSH_ZERO_MODE
113 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
114#endif
115#ifdef _MM_SET_DENORMALS_ZERO_MODE
116 _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
117#endif
118
119 m_scene_flags = scene_flags;
120 m_build_quality = build_quality;
121 m_device = rtcNewDevice(NULL);
122 ensure_no_errors_internal();
123 m_embree_world_scene = rtcNewScene(m_device);
124 ensure_no_errors_internal();
125 m_instance_index_ranges.push_back(safe_cast<Index>(0));
126
127 m_need_rebuild = true;
128 m_need_commit = false;
129 }
130
133 {
135 rtcReleaseDevice(m_device);
136 }
137
138 EmbreeRayCaster(const EmbreeRayCaster&) = delete;
139 void operator=(const EmbreeRayCaster&) = delete;
140
141public:
143 Index get_num_meshes() const { return safe_cast<Index>(m_meshes.size()); }
144
146 Index get_num_instances() const { return m_instance_index_ranges.back(); }
147
149 Index get_num_instances(Index mesh_index) const
150 {
151 la_debug_assert(mesh_index + 1 < safe_cast<Index>(m_instance_index_ranges.size()));
152 return safe_cast<Index>(
153 m_instance_index_ranges[mesh_index + 1] - m_instance_index_ranges[mesh_index]);
154 }
155
160 template <typename MeshType>
161 std::shared_ptr<MeshType> get_mesh(Index index) const
162 {
163 la_runtime_assert(index < safe_cast<Index>(m_meshes.size()));
164 la_runtime_assert(m_meshes[index] != nullptr);
165 return dynamic_cast<RaycasterMeshDerived<MeshType>&>(*m_meshes[index]).get_mesh_ptr();
166 }
167
176 Index get_mesh_for_instance(Index cumulative_instance_index) const
177 {
178 la_runtime_assert(cumulative_instance_index < get_num_instances());
179 return m_instance_to_user_mesh[cumulative_instance_index];
180 }
181
188 template <typename MeshType>
189 Index add_mesh(
190 std::shared_ptr<MeshType> mesh,
191 const Transform& trans = Transform::Identity(),
192 RTCBuildQuality build_quality = RTC_BUILD_QUALITY_MEDIUM)
193 {
194 return add_raycasting_mesh(
195 std::make_unique<RaycasterMeshDerived<MeshType>>(mesh),
196 trans,
197 build_quality);
198 }
199
206 template <typename MeshType>
208 std::shared_ptr<MeshType> mesh,
209 const TransformVector& trans_vector,
210 RTCBuildQuality build_quality = RTC_BUILD_QUALITY_MEDIUM)
211 {
212 m_meshes.push_back(std::move(std::make_unique<RaycasterMeshDerived<MeshType>>(mesh)));
213 m_transforms.insert(m_transforms.end(), trans_vector.begin(), trans_vector.end());
214 m_mesh_build_qualities.push_back(build_quality);
215 m_visibility.resize(m_visibility.size() + trans_vector.size(), true);
216 for (auto& f : m_filters) { // per-mesh, not per-instance
217 f.push_back(nullptr);
218 }
219 Index mesh_index = safe_cast<Index>(m_meshes.size() - 1);
220 la_runtime_assert(m_instance_index_ranges.size() > 0);
221 Index instance_index = m_instance_index_ranges.back();
222 la_runtime_assert(instance_index == safe_cast<Index>(m_instance_to_user_mesh.size()));
223 Index new_instance_size = instance_index + trans_vector.size();
224 m_instance_index_ranges.push_back(new_instance_size);
225 m_instance_to_user_mesh.resize(new_instance_size, mesh_index);
226 m_need_rebuild = true;
227 return mesh_index;
228 }
229
236 template <typename MeshType>
238 Index index,
239 std::shared_ptr<MeshType> mesh,
240 RTCBuildQuality build_quality = RTC_BUILD_QUALITY_MEDIUM)
241 {
242 update_raycasting_mesh(
243 index,
244 std::make_unique<RaycasterMeshDerived<MeshType>>(mesh),
245 build_quality);
246 }
247
253 void update_mesh_vertices(Index index)
254 {
255 la_runtime_assert(index < safe_cast<Index>(m_meshes.size()));
256 if (m_need_rebuild) return;
257
258 la_runtime_assert(index < safe_cast<Index>(m_embree_mesh_scenes.size()));
259 auto geom = rtcGetGeometry(m_embree_mesh_scenes[index], 0);
260
261 // Update the vertex buffer in Embree
262 auto const& mesh = m_meshes[index];
264 safe_cast<Index>(mesh->get_num_vertices()) == m_mesh_vertex_counts[index]);
265
266 auto vbuf =
267 reinterpret_cast<float*>(rtcGetGeometryBufferData(geom, RTC_BUFFER_TYPE_VERTEX, 0));
268 la_runtime_assert(vbuf);
269 mesh->vertices_to_float(vbuf);
270 rtcUpdateGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0);
271
272 // Re-commit the mesh geometry and scene
273 rtcCommitGeometry(geom);
274 rtcCommitScene(m_embree_mesh_scenes[index]);
275
276 // Re-commit every instance of the mesh
277 for (Index instance_index = m_instance_index_ranges[index];
278 instance_index < m_instance_index_ranges[index + 1];
279 ++instance_index) {
280 Index rtc_inst_id = m_instance_index_ranges[index] + instance_index;
281 auto geom_inst =
282 rtcGetGeometry(m_embree_world_scene, static_cast<unsigned>(rtc_inst_id));
283 rtcCommitGeometry(geom_inst);
284 }
285
286 // Mark the world scene as needing a re-commit (will be called lazily)
287 m_need_commit = true;
288 }
289
291 Transform get_transform(Index mesh_index, Index instance_index) const
292 {
293 la_runtime_assert(mesh_index + 1 < safe_cast<Index>(m_instance_index_ranges.size()));
294 Index index = m_instance_index_ranges[mesh_index] + instance_index;
295 la_runtime_assert(index < m_instance_index_ranges[mesh_index + 1]);
296 la_runtime_assert(index < safe_cast<Index>(m_transforms.size()));
297 return m_transforms[index];
298 }
299
301 void update_transformation(Index mesh_index, Index instance_index, const Transform& trans)
302 {
303 la_runtime_assert(mesh_index + 1 < safe_cast<Index>(m_instance_index_ranges.size()));
304 Index index = m_instance_index_ranges[mesh_index] + instance_index;
305 la_runtime_assert(index < m_instance_index_ranges[mesh_index + 1]);
306 la_runtime_assert(index < safe_cast<Index>(m_transforms.size()));
307 m_transforms[index] = trans;
308 if (!m_need_rebuild) {
309 auto geom = rtcGetGeometry(m_embree_world_scene, static_cast<unsigned>(index));
310 Eigen::Matrix<float, 4, 4> T = trans.template cast<float>();
311 rtcSetGeometryTransform(geom, 0, RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR, T.eval().data());
312 rtcCommitGeometry(geom);
313 m_need_commit = true;
314 }
315 }
316
318 bool get_visibility(Index mesh_index, Index instance_index) const
319 {
320 la_runtime_assert(mesh_index + 1 < safe_cast<Index>(m_instance_index_ranges.size()));
321 Index index = m_instance_index_ranges[mesh_index] + instance_index;
322 la_runtime_assert(index < m_instance_index_ranges[mesh_index + 1]);
323 la_runtime_assert(index < safe_cast<Index>(m_visibility.size()));
324 return m_visibility[index];
325 }
326
328 void update_visibility(Index mesh_index, Index instance_index, bool visible)
329 {
330 la_runtime_assert(mesh_index + 1 < safe_cast<Index>(m_instance_index_ranges.size()));
331 Index index = m_instance_index_ranges[mesh_index] + instance_index;
332 la_runtime_assert(index < m_instance_index_ranges[mesh_index + 1]);
333 la_runtime_assert(index < safe_cast<Index>(m_visibility.size()));
334 m_visibility[index] = visible;
335 if (!m_need_rebuild &&
336 rtcGetDeviceProperty(m_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED)) {
337 // ^^^ else, visibility will be checked by the already bound filter
338
339 auto geom = rtcGetGeometry(m_embree_world_scene, static_cast<unsigned>(index));
340 rtcSetGeometryMask(geom, visible ? 0xFFFFFFFF : 0x00000000);
341 rtcCommitGeometry(geom);
342 m_need_commit = true;
343 }
344 }
345
362 void set_intersection_filter(Index mesh_index, FilterFunction filter)
363 {
364 la_runtime_assert(mesh_index < m_filters[FILTER_INTERSECT].size());
365 m_filters[FILTER_INTERSECT][mesh_index] = filter;
366 m_need_rebuild = true;
367 }
368
376 {
377 la_runtime_assert(mesh_index < m_filters[FILTER_INTERSECT].size());
378 return m_filters[FILTER_INTERSECT][mesh_index];
379 }
380
397 void set_occlusion_filter(Index mesh_index, FilterFunction filter)
398 {
399 la_runtime_assert(mesh_index < m_filters[FILTER_OCCLUDED].size());
400 m_filters[FILTER_OCCLUDED][mesh_index] = filter;
401 m_need_rebuild = true;
402 }
403
410 FilterFunction get_occlusion_filter(Index mesh_index) const
411 {
412 la_runtime_assert(mesh_index < m_filters[FILTER_OCCLUDED].size());
413 return m_filters[FILTER_OCCLUDED][mesh_index];
414 }
415
424 {
425 if (!m_need_commit) return;
426
427 rtcCommitScene(m_embree_world_scene);
428 m_need_commit = false;
429 }
430
432 void ensure_no_errors() const { EmbreeHelper::ensure_no_errors(m_device); }
433
438 uint32_t cast4(
439 uint32_t batch_size,
440 const Point4& origin,
441 const Direction4& direction,
442 const Mask4& mask,
443 Index4& mesh_index,
444 Index4& instance_index,
445 Index4& facet_index,
446 Scalar4& ray_depth,
447 Point4& barycentric_coord,
448 Point4& normal,
449 const Scalar4& tmin = Scalar4::Zero(),
450 const Scalar4& tmax = Scalar4::Constant(std::numeric_limits<Scalar>::infinity()))
451 {
452 la_debug_assert(batch_size <= 4);
453
455
456 RTCRayHit4 embree_raypacket;
457 for (int i = 0; i < static_cast<int>(batch_size); ++i) {
458 // Set ray origins
459 embree_raypacket.ray.org_x[i] = static_cast<float>(origin(i, 0));
460 embree_raypacket.ray.org_y[i] = static_cast<float>(origin(i, 1));
461 embree_raypacket.ray.org_z[i] = static_cast<float>(origin(i, 2));
462
463 // Set ray directions
464 embree_raypacket.ray.dir_x[i] = static_cast<float>(direction(i, 0));
465 embree_raypacket.ray.dir_y[i] = static_cast<float>(direction(i, 1));
466 embree_raypacket.ray.dir_z[i] = static_cast<float>(direction(i, 2));
467
468 // Misc
469 embree_raypacket.ray.tnear[i] = static_cast<float>(tmin[i]);
470 embree_raypacket.ray.tfar[i] = std::isinf(tmax[i]) ? std::numeric_limits<float>::max()
471 : static_cast<float>(tmax[i]);
472 embree_raypacket.ray.mask[i] = 0xFFFFFFFF;
473 embree_raypacket.ray.id[i] = static_cast<unsigned>(i);
474 embree_raypacket.ray.flags[i] = 0;
475
476 // Required initialization of the hit substructure
477 embree_raypacket.hit.geomID[i] = RTC_INVALID_GEOMETRY_ID;
478 embree_raypacket.hit.primID[i] = RTC_INVALID_GEOMETRY_ID;
479 embree_raypacket.hit.instID[0][i] = RTC_INVALID_GEOMETRY_ID;
480 }
481
482 // Modify the mask to make 100% sure extra rays in the packet will be ignored
483 auto packet_mask = mask;
484 for (int i = static_cast<int>(batch_size); i < 4; ++i) packet_mask[i] = 0;
485
486 ensure_no_errors_internal();
487#ifdef LAGRANGE_WITH_EMBREE_3
488 RTCIntersectContext context;
489 rtcInitIntersectContext(&context);
490 rtcIntersect4(packet_mask.data(), m_embree_world_scene, &context, &embree_raypacket);
491#else
492 rtcIntersect4(packet_mask.data(), m_embree_world_scene, &embree_raypacket);
493#endif
494 ensure_no_errors_internal();
495
496 uint32_t is_hits = 0;
497 for (int i = 0; i < static_cast<int>(batch_size); ++i) {
498 if (embree_raypacket.hit.geomID[i] != RTC_INVALID_GEOMETRY_ID) {
499 Index rtc_inst_id = embree_raypacket.hit.instID[0][i];
500 Index rtc_mesh_id = (rtc_inst_id == RTC_INVALID_GEOMETRY_ID)
501 ? embree_raypacket.hit.geomID[i]
502 : rtc_inst_id;
503 assert(rtc_mesh_id < m_instance_to_user_mesh.size());
504 assert(m_visibility[rtc_mesh_id]);
505 mesh_index[i] = m_instance_to_user_mesh[rtc_mesh_id];
506 assert(mesh_index[i] + 1 < m_instance_index_ranges.size());
507 assert(mesh_index[i] < safe_cast<Index>(m_meshes.size()));
508 instance_index[i] = rtc_mesh_id - m_instance_index_ranges[mesh_index[i]];
509 facet_index[i] = embree_raypacket.hit.primID[i];
510 ray_depth[i] = embree_raypacket.ray.tfar[i];
511 barycentric_coord(i, 0) =
512 1.0f - embree_raypacket.hit.u[i] - embree_raypacket.hit.v[i];
513 barycentric_coord(i, 1) = embree_raypacket.hit.u[i];
514 barycentric_coord(i, 2) = embree_raypacket.hit.v[i];
515 normal(i, 0) = embree_raypacket.hit.Ng_x[i];
516 normal(i, 1) = embree_raypacket.hit.Ng_y[i];
517 normal(i, 2) = embree_raypacket.hit.Ng_z[i];
518 is_hits = is_hits | (1 << i);
519 }
520 }
521
522 return is_hits;
523 }
524
529 uint32_t cast4(
530 uint32_t batch_size,
531 const Point4& origin,
532 const Direction4& direction,
533 const Mask4& mask,
534 Index4& mesh_index,
535 Index4& facet_index,
536 Scalar4& ray_depth,
537 Point4& barycentric_coord,
538 const Scalar4& tmin = Scalar4::Zero(),
539 const Scalar4& tmax = Scalar4::Constant(std::numeric_limits<Scalar>::infinity()))
540 {
541 Index4 instance_index;
542 Point4 normal;
543 return cast4(
544 batch_size,
545 origin,
546 direction,
547 mask,
548 mesh_index,
549 instance_index,
550 facet_index,
551 ray_depth,
552 barycentric_coord,
553 normal,
554 tmin,
555 tmax);
556 }
557
561 uint32_t cast4(
562 uint32_t batch_size,
563 const Point4& origin,
564 const Direction4& direction,
565 const Mask4& mask,
566 const Scalar4& tmin = Scalar4::Zero(),
567 const Scalar4& tmax = Scalar4::Constant(std::numeric_limits<Scalar>::infinity()))
568 {
569 la_debug_assert(batch_size <= 4);
570
572
573 RTCRay4 embree_raypacket;
574 for (int i = 0; i < static_cast<int>(batch_size); ++i) {
575 // Set ray origins
576 embree_raypacket.org_x[i] = static_cast<float>(origin(i, 0));
577 embree_raypacket.org_y[i] = static_cast<float>(origin(i, 1));
578 embree_raypacket.org_z[i] = static_cast<float>(origin(i, 2));
579
580 // Set ray directions
581 embree_raypacket.dir_x[i] = static_cast<float>(direction(i, 0));
582 embree_raypacket.dir_y[i] = static_cast<float>(direction(i, 1));
583 embree_raypacket.dir_z[i] = static_cast<float>(direction(i, 2));
584
585 // Misc
586 embree_raypacket.tnear[i] = static_cast<float>(tmin[i]);
587 embree_raypacket.tfar[i] = std::isinf(tmax[i]) ? std::numeric_limits<float>::max()
588 : static_cast<float>(tmax[i]);
589 embree_raypacket.mask[i] = 0xFFFFFFFF;
590 embree_raypacket.id[i] = static_cast<unsigned>(i);
591 embree_raypacket.flags[i] = 0;
592 }
593
594 // Modify the mask to make 100% sure extra rays in the packet will be ignored
595 auto packet_mask = mask;
596 for (int i = static_cast<int>(batch_size); i < 4; ++i) packet_mask[i] = 0;
597
598 ensure_no_errors_internal();
599#ifdef LAGRANGE_WITH_EMBREE_3
600 RTCIntersectContext context;
601 rtcInitIntersectContext(&context);
602 rtcOccluded4(packet_mask.data(), m_embree_world_scene, &context, &embree_raypacket);
603#else
604 rtcOccluded4(packet_mask.data(), m_embree_world_scene, &embree_raypacket);
605#endif
606 ensure_no_errors_internal();
607
608 // If hit, the tfar field will be set to -inf.
609 uint32_t is_hits = 0;
610 for (uint32_t i = 0; i < batch_size; ++i)
611 if (!std::isfinite(embree_raypacket.tfar[i])) is_hits = is_hits | (1 << i);
612
613 return is_hits;
614 }
615
620 bool cast(
621 const Point& origin,
622 const Direction& direction,
623 Index& mesh_index,
624 Index& instance_index,
625 Index& facet_index,
626 Scalar& ray_depth,
627 Point& barycentric_coord,
628 Point& normal,
629 Scalar tmin = 0,
630 Scalar tmax = std::numeric_limits<Scalar>::infinity())
631 {
632 // Overloaded when specializing tnear and tfar
633
635
636 RTCRayHit embree_rayhit;
637 embree_rayhit.ray.org_x = static_cast<float>(origin.x());
638 embree_rayhit.ray.org_y = static_cast<float>(origin.y());
639 embree_rayhit.ray.org_z = static_cast<float>(origin.z());
640 embree_rayhit.ray.dir_x = static_cast<float>(direction.x());
641 embree_rayhit.ray.dir_y = static_cast<float>(direction.y());
642 embree_rayhit.ray.dir_z = static_cast<float>(direction.z());
643 embree_rayhit.ray.tnear = static_cast<float>(tmin);
644 embree_rayhit.ray.tfar =
645 std::isinf(tmax) ? std::numeric_limits<float>::max() : static_cast<float>(tmax);
646 embree_rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
647 embree_rayhit.hit.primID = RTC_INVALID_GEOMETRY_ID;
648 embree_rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
649 embree_rayhit.ray.mask = 0xFFFFFFFF;
650 embree_rayhit.ray.id = 0;
651 embree_rayhit.ray.flags = 0;
652 ensure_no_errors_internal();
653#ifdef LAGRANGE_WITH_EMBREE_3
654 RTCIntersectContext context;
655 rtcInitIntersectContext(&context);
656 rtcIntersect1(m_embree_world_scene, &context, &embree_rayhit);
657#else
658 rtcIntersect1(m_embree_world_scene, &embree_rayhit);
659#endif
660 ensure_no_errors_internal();
661
662 if (embree_rayhit.hit.geomID != RTC_INVALID_GEOMETRY_ID) {
663 Index rtc_inst_id = embree_rayhit.hit.instID[0];
664 Index rtc_mesh_id =
665 (rtc_inst_id == RTC_INVALID_GEOMETRY_ID) ? embree_rayhit.hit.geomID : rtc_inst_id;
666 assert(rtc_mesh_id < m_instance_to_user_mesh.size());
667 assert(m_visibility[rtc_mesh_id]);
668 mesh_index = m_instance_to_user_mesh[rtc_mesh_id];
669 assert(mesh_index + 1 < m_instance_index_ranges.size());
670 assert(mesh_index < safe_cast<Index>(m_meshes.size()));
671 instance_index = rtc_mesh_id - m_instance_index_ranges[mesh_index];
672 facet_index = embree_rayhit.hit.primID;
673 ray_depth = embree_rayhit.ray.tfar;
674 barycentric_coord[0] = 1.0f - embree_rayhit.hit.u - embree_rayhit.hit.v;
675 barycentric_coord[1] = embree_rayhit.hit.u;
676 barycentric_coord[2] = embree_rayhit.hit.v;
677 normal[0] = embree_rayhit.hit.Ng_x;
678 normal[1] = embree_rayhit.hit.Ng_y;
679 normal[2] = embree_rayhit.hit.Ng_z;
680 return true;
681 } else {
682 // Ray missed.
683 mesh_index = invalid<Index>();
684 instance_index = invalid<Index>();
685 facet_index = invalid<Index>();
686 return false;
687 }
688 }
689
694 bool cast(
695 const Point& origin,
696 const Direction& direction,
697 Index& mesh_index,
698 Index& facet_index,
699 Scalar& ray_depth,
700 Point& barycentric_coord,
701 Scalar tmin = 0,
702 Scalar tmax = std::numeric_limits<Scalar>::infinity())
703 {
704 Index instance_index;
705 Point normal;
706 return cast(
707 origin,
708 direction,
709 mesh_index,
710 instance_index,
711 facet_index,
712 ray_depth,
713 barycentric_coord,
714 normal,
715 tmin,
716 tmax);
717 }
718
720 bool cast(
721 const Point& origin,
722 const Direction& direction,
723 Scalar tmin = 0,
724 Scalar tmax = std::numeric_limits<Scalar>::infinity())
725 {
727
728 RTCRay embree_ray;
729 embree_ray.org_x = static_cast<float>(origin.x());
730 embree_ray.org_y = static_cast<float>(origin.y());
731 embree_ray.org_z = static_cast<float>(origin.z());
732 embree_ray.dir_x = static_cast<float>(direction.x());
733 embree_ray.dir_y = static_cast<float>(direction.y());
734 embree_ray.dir_z = static_cast<float>(direction.z());
735 embree_ray.tnear = static_cast<float>(tmin);
736 embree_ray.tfar =
737 std::isinf(tmax) ? std::numeric_limits<float>::max() : static_cast<float>(tmax);
738 embree_ray.mask = 0xFFFFFFFF;
739 embree_ray.id = 0;
740 embree_ray.flags = 0;
741
742 ensure_no_errors_internal();
743#ifdef LAGRANGE_WITH_EMBREE_3
744 RTCIntersectContext context;
745 rtcInitIntersectContext(&context);
746 rtcOccluded1(m_embree_world_scene, &context, &embree_ray);
747#else
748 rtcOccluded1(m_embree_world_scene, &embree_ray);
749#endif
750 ensure_no_errors_internal();
751
752 // If hit, the tfar field will be set to -inf.
753 return !std::isfinite(embree_ray.tfar);
754 }
755
757 ClosestPoint query_closest_point(const Point& p) const;
758
761 std::unique_ptr<RaycasterMesh> mesh,
762 const Transform& trans = Transform::Identity(),
763 RTCBuildQuality build_quality = RTC_BUILD_QUALITY_MEDIUM)
764 {
765 m_meshes.push_back(std::move(mesh));
766 m_transforms.push_back(trans);
767 m_mesh_build_qualities.push_back(build_quality);
768 m_visibility.push_back(true);
769 for (auto& f : m_filters) { // per-mesh, not per-instance
770 f.push_back(nullptr);
771 }
772 Index mesh_index = safe_cast<Index>(m_meshes.size() - 1);
773 la_runtime_assert(m_instance_index_ranges.size() > 0);
774 Index instance_index = m_instance_index_ranges.back();
775 la_runtime_assert(instance_index == safe_cast<Index>(m_instance_to_user_mesh.size()));
776 m_instance_index_ranges.push_back(instance_index + 1);
777 m_instance_to_user_mesh.resize(instance_index + 1, mesh_index);
778 m_need_rebuild = true;
779 return mesh_index;
780 }
781
782 void update_raycasting_mesh(
783 Index index,
784 std::unique_ptr<RaycasterMesh> mesh,
785 RTCBuildQuality build_quality = RTC_BUILD_QUALITY_MEDIUM)
786 {
787 la_runtime_assert(mesh->get_dim() == 3);
788 la_runtime_assert(mesh->get_vertex_per_facet() == 3);
789 la_runtime_assert(index < safe_cast<Index>(m_meshes.size()));
790 m_meshes[index] = std::move(mesh);
791 m_mesh_build_qualities[index] = build_quality;
792 m_need_rebuild = true; // TODO: Make this more fine-grained so only the affected part of
793 // the Embree scene is updated
794 }
795
796protected:
799 {
800 for (auto& s : m_embree_mesh_scenes) {
801 rtcReleaseScene(s);
802 }
803 rtcReleaseScene(m_embree_world_scene);
804 }
805
807 virtual RTCSceneFlags get_scene_flags() const { return m_scene_flags; }
808
810 virtual RTCBuildQuality get_scene_build_quality() const { return m_build_quality; }
811
814 {
815 if (m_need_rebuild)
816 generate_scene(); // full rebuild
817 else if (m_need_commit)
818 commit_scene_changes(); // just call rtcCommitScene()
819 }
820
828 {
829 if (!m_need_rebuild) return;
830
831 // Scene needs to be updated
833 m_embree_world_scene = rtcNewScene(m_device);
834 auto scene_flags = get_scene_flags(); // FIXME: or just m_scene_flags?
835 auto scene_build_quality = get_scene_build_quality(); // FIXME: or just m_build_quality?
836 rtcSetSceneFlags(
837 m_embree_world_scene,
838 scene_flags); // TODO: maybe also set RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION
839 rtcSetSceneBuildQuality(m_embree_world_scene, scene_build_quality);
840 m_float_data.clear();
841 m_int_data.clear();
842 const auto num_meshes = m_meshes.size();
843 la_runtime_assert(num_meshes + 1 == m_instance_index_ranges.size());
844 m_embree_mesh_scenes.resize(num_meshes);
845 m_mesh_vertex_counts.resize(num_meshes);
846 ensure_no_errors_internal();
847
848 bool is_mask_supported =
849 rtcGetDeviceProperty(m_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
850 for (size_t i = 0; i < num_meshes; i++) {
851 // Initialize RTC meshes
852 const auto& mesh = m_meshes[i];
853 // const auto& vertices = mesh->get_vertices();
854 // const auto& facets = mesh->get_facets();
855 const Index num_vertices = m_mesh_vertex_counts[i] =
856 safe_cast<Index>(mesh->get_num_vertices());
857 const Index num_facets = safe_cast<Index>(mesh->get_num_facets());
858
859 auto& embree_mesh_scene = m_embree_mesh_scenes[i];
860 embree_mesh_scene = rtcNewScene(m_device);
861
862 rtcSetSceneFlags(embree_mesh_scene, scene_flags);
863 rtcSetSceneBuildQuality(embree_mesh_scene, scene_build_quality);
864 ensure_no_errors_internal();
865
866 RTCGeometry geom = rtcNewGeometry(
867 m_device,
868 RTC_GEOMETRY_TYPE_TRIANGLE); // EMBREE_FIXME: check if geometry gets properly
869 // committed
870 rtcSetGeometryBuildQuality(geom, m_mesh_build_qualities[i]);
871 // rtcSetGeometryTimeStepCount(geom, 1);
872
873 const float* vertex_data = extract_float_data(*mesh);
874 const unsigned* facet_data = extract_int_data(*mesh);
875
876 rtcSetSharedGeometryBuffer(
877 geom,
878 RTC_BUFFER_TYPE_VERTEX,
879 0,
880 RTC_FORMAT_FLOAT3,
881 vertex_data,
882 0,
883 sizeof(float) * 3,
884 num_vertices);
885 rtcSetSharedGeometryBuffer(
886 geom,
887 RTC_BUFFER_TYPE_INDEX,
888 0,
889 RTC_FORMAT_UINT3,
890 facet_data,
891 0,
892 sizeof(int) * 3,
893 num_facets);
894
895 set_intersection_filter(geom, m_filters[FILTER_INTERSECT][i], is_mask_supported);
896 set_occlusion_filter(geom, m_filters[FILTER_OCCLUDED][i], is_mask_supported);
897
898 rtcCommitGeometry(geom);
899 rtcAttachGeometry(embree_mesh_scene, geom);
900 rtcReleaseGeometry(geom);
901 ensure_no_errors_internal();
902
903 // Initialize RTC instances
904 for (Index instance_index = m_instance_index_ranges[i];
905 instance_index < m_instance_index_ranges[i + 1];
906 ++instance_index) {
907 const auto& trans = m_transforms[instance_index];
908
909 RTCGeometry geom_inst = rtcNewGeometry(
910 m_device,
911 RTC_GEOMETRY_TYPE_INSTANCE); // EMBREE_FIXME: check if geometry gets properly
912 // committed
913 rtcSetGeometryInstancedScene(geom_inst, embree_mesh_scene);
914 rtcSetGeometryTimeStepCount(geom_inst, 1);
915
916 Eigen::Matrix<float, 4, 4> T = trans.template cast<float>();
917 rtcSetGeometryTransform(geom_inst, 0, RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR, T.data());
918 ensure_no_errors_internal();
919
920 if (is_mask_supported) {
921 rtcSetGeometryMask(
922 geom_inst,
923 m_visibility[instance_index] ? 0xFFFFFFFF : 0x00000000);
924 }
925 ensure_no_errors_internal();
926
927 rtcCommitGeometry(geom_inst);
928 unsigned rtc_instance_id = rtcAttachGeometry(m_embree_world_scene, geom_inst);
929 rtcReleaseGeometry(geom_inst);
930 la_runtime_assert(safe_cast<Index>(rtc_instance_id) == instance_index);
931 ensure_no_errors_internal();
932 }
933
934 rtcCommitScene(embree_mesh_scene);
935 ensure_no_errors_internal();
936 }
937 rtcCommitScene(m_embree_world_scene);
938 ensure_no_errors_internal();
939
940 m_need_rebuild = m_need_commit = false;
941 }
942
944 const float* extract_float_data(const RaycasterMesh& mesh)
945 {
946 auto float_data = mesh.vertices_to_float();
947 // Due to Embree bug, we have to have at least one more entry
948 // after the bound. Sigh...
949 // See https://github.com/embree/embree/issues/124
950 float_data.push_back(0.0);
951 m_float_data.emplace_back(std::move(float_data));
952 return m_float_data.back().data();
953 }
954
956 const unsigned* extract_int_data(const RaycasterMesh& mesh)
957 {
958 auto int_data = mesh.indices_to_int();
959 // Due to Embree bug, we have to have at least one more entry
960 // after the bound. Sigh...
961 // See https://github.com/embree/embree/issues/124
962 int_data.push_back(0);
963 m_int_data.emplace_back(std::move(int_data));
964 return m_int_data.back().data();
965 }
966
967private:
972 void set_intersection_filter(RTCGeometry geom, FilterFunction filter, bool is_mask_supported)
973 {
974 if (is_mask_supported) {
975 if (filter) {
976 rtcSetGeometryUserData(geom, this);
977 rtcSetGeometryIntersectFilterFunction(geom, &wrap_filter<FILTER_INTERSECT>);
978 } else {
979 rtcSetGeometryIntersectFilterFunction(geom, nullptr);
980 }
981 } else {
982 rtcSetGeometryUserData(geom, this);
983 rtcSetGeometryIntersectFilterFunction(geom, &wrap_filter_and_mask<FILTER_INTERSECT>);
984 }
985 }
986
991 void set_occlusion_filter(RTCGeometry geom, FilterFunction filter, bool is_mask_supported)
992 {
993 if (is_mask_supported) {
994 if (filter) {
995 rtcSetGeometryUserData(geom, this);
996 rtcSetGeometryOccludedFilterFunction(geom, &wrap_filter<FILTER_OCCLUDED>);
997 } else {
998 rtcSetGeometryOccludedFilterFunction(geom, nullptr);
999 }
1000 } else {
1001 rtcSetGeometryUserData(geom, this);
1002 rtcSetGeometryOccludedFilterFunction(geom, &wrap_filter_and_mask<FILTER_OCCLUDED>);
1003 }
1004 }
1005
1010 template <int IntersectionOrOcclusion> // 0: intersection, 1: occlusion
1011 static void wrap_filter(const RTCFilterFunctionNArguments* args)
1012 {
1013 // Embree never actually calls a filter callback with different geometry or instance IDs
1014 // So we can assume they are the same for all the hits in this batch. Also, every single
1015 // mesh in this class is instanced (never used raw), so we can ignore geomID.
1016 const auto* obj = reinterpret_cast<EmbreeRayCaster*>(args->geometryUserPtr);
1017 auto rtc_inst_id = RTCHitN_instID(args->hit, args->N, 0, 0);
1018 assert(rtc_inst_id < obj->m_instance_to_user_mesh.size());
1019
1020 auto filter = obj->m_filters[IntersectionOrOcclusion][rtc_inst_id];
1021 if (!filter) {
1022 return;
1023 }
1024
1025 Index mesh_index = obj->m_instance_to_user_mesh[rtc_inst_id];
1026 assert(mesh_index + 1 < obj->m_instance_index_ranges.size());
1027 assert(mesh_index < safe_cast<Index>(obj->m_meshes.size()));
1028 Index instance_index = rtc_inst_id - obj->m_instance_index_ranges[mesh_index];
1029
1030 // In case Embree's implementation changes in the future, the callback should be written
1031 // generally, without assuming the single geometry/instance condition above.
1032 Index4 mesh_index4;
1033 mesh_index4.fill(mesh_index);
1034 Index4 instance_index4;
1035 instance_index4.fill(instance_index);
1036
1037 // Call the wrapped filter with the indices specific to this object
1038 filter(obj, mesh_index4.data(), instance_index4.data(), args);
1039 }
1040
1046 template <int IntersectionOrOcclusion> // 0: intersection, 1: occlusion
1047 static void wrap_filter_and_mask(const RTCFilterFunctionNArguments* args)
1048 {
1049 // Embree never actually calls a filter callback with different geometry or instance IDs
1050 // So we can assume they are the same for all the hits in this batch. Also, every single
1051 // mesh in this class is instanced (never used raw), so we can ignore geomID.
1052 const auto* obj = reinterpret_cast<EmbreeRayCaster*>(args->geometryUserPtr);
1053 auto rtc_inst_id = RTCHitN_instID(args->hit, args->N, 0, 0);
1054 if (!obj->m_visibility[rtc_inst_id]) {
1055 // Object is invisible. Make the hits of all the rays with this object invalid.
1056 std::fill(args->valid, args->valid + args->N, 0);
1057 return;
1058 }
1059
1060 // Delegate to the regular filtering after having checked visibility
1061 wrap_filter<IntersectionOrOcclusion>(args);
1062 }
1063
1064protected:
1065 RTCSceneFlags m_scene_flags;
1066 RTCBuildQuality m_build_quality;
1067 RTCDevice m_device;
1068 RTCScene m_embree_world_scene;
1069 bool m_need_rebuild; // full rebuild of the scene?
1070 bool m_need_commit; // just call rtcCommitScene() on the scene?
1071
1072 // Data reservoirs for holding temporary/casted/per-geometry data.
1073 // Length = Number of polygonal meshes
1074 std::vector<FloatData> m_float_data;
1075 std::vector<IntData> m_int_data;
1076 std::vector<std::unique_ptr<RaycasterMesh>> m_meshes;
1077 std::vector<RTCBuildQuality> m_mesh_build_qualities;
1078 std::vector<RTCScene> m_embree_mesh_scenes;
1079 std::vector<Index> m_mesh_vertex_counts; // for bounds-checking of buffer updates
1080 std::vector<FilterFunction> m_filters[2]; // 0: intersection filters, 1: occlusion filters
1081
1082 // Ranges of instance indices corresponding to a specific
1083 // Mesh. For example, in a scenario with 3 meshes each of
1084 // which has 1, 2, 5 instances, this array would be
1085 // [0, 1, 3, 8].
1086 // Length = Number of user meshes + 1
1087 std::vector<Index> m_instance_index_ranges;
1088
1089 // Mapping from (RTC-)instanced mesh to user mesh. For
1090 // example, in a scenario with 3 meshes each of
1091 // which has 1, 2, 5 instances, this array would be
1092 // [0, 1, 1, 2, 2, 2, 2, 2]
1093 // Length = Number of instanced meshes
1094 // Note: This array is only used internally. We shouldn't
1095 // allow the users to access anything with the indices
1096 // used in those RTC functions.
1097 std::vector<Index> m_instance_to_user_mesh;
1098
1099 // Data reservoirs for holding instanced mesh data
1100 // Length = Number of (world-space) instanced meshes
1101 std::vector<Transform> m_transforms;
1102 std::vector<bool> m_visibility;
1103
1104 // error checking function used internally
1105 void ensure_no_errors_internal() const
1106 {
1107#ifdef LAGRANGE_EMBREE_DEBUG
1108 EmbreeHelper::ensure_no_errors(m_device);
1109#endif
1110 }
1111};
1112
1114// IMPLEMENTATION
1116
1117template <typename Scalar>
1118auto EmbreeRayCaster<Scalar>::query_closest_point(const Point& p) const -> ClosestPoint
1119{
1120 RTCPointQuery query;
1121 query.x = (float)(p.x());
1122 query.y = (float)(p.y());
1123 query.z = (float)(p.z());
1124 query.radius = std::numeric_limits<float>::max();
1125 query.time = 0.f;
1126 ensure_no_errors_internal();
1127
1128 ClosestPoint result;
1129
1130 // Callback to retrieve triangle corner positions
1131 result.populate_triangle =
1132 [&](unsigned mesh_index, unsigned facet_index, Point& v0, Point& v1, Point& v2) {
1133 // TODO: There's no way to call this->get_mesh<> since we need to template the function
1134 // by the (derived) type, which we don't know here... This means our only choice is so
1135 // use the float data instead of the (maybe) double point coordinate if available. Note
1136 // that we could also call rtcSetGeometryPointQueryFunction() when we register our mesh,
1137 // since we know the derived type at this point.
1138 const unsigned* face = m_int_data[mesh_index].data() + 3 * facet_index;
1139 const float* vertices = m_float_data[mesh_index].data();
1140 v0 = Point(vertices[3 * face[0]], vertices[3 * face[0] + 1], vertices[3 * face[0] + 2]);
1141 v1 = Point(vertices[3 * face[1]], vertices[3 * face[1] + 1], vertices[3 * face[1] + 2]);
1142 v2 = Point(vertices[3 * face[2]], vertices[3 * face[2] + 1], vertices[3 * face[2] + 2]);
1143 };
1144
1145 {
1146 RTCPointQueryContext context;
1147 rtcInitPointQueryContext(&context);
1148 rtcPointQuery(
1149 m_embree_world_scene,
1150 &query,
1151 &context,
1152 &embree_closest_point<Scalar>,
1153 reinterpret_cast<void*>(&result));
1154 assert(
1155 result.mesh_index != RTC_INVALID_GEOMETRY_ID ||
1156 result.facet_index != RTC_INVALID_GEOMETRY_ID);
1157 assert(
1158 result.mesh_index != invalid<unsigned>() || result.facet_index != invalid<unsigned>());
1159 }
1160 ensure_no_errors_internal();
1161
1162 return result;
1163}
1164
1165} // namespace legacy
1166} // namespace raycasting
1167} // namespace lagrange
A wrapper for Embree's raycasting API to compute ray intersections with (instances of) meshes.
Definition EmbreeRayCaster.h:59
Index add_meshes(std::shared_ptr< MeshType > mesh, const TransformVector &trans_vector, RTCBuildQuality build_quality=RTC_BUILD_QUALITY_MEDIUM)
Add multiple instances of a single mesh to the scene, with given transformations.
Definition EmbreeRayCaster.h:207
Index add_raycasting_mesh(std::unique_ptr< RaycasterMesh > mesh, const Transform &trans=Transform::Identity(), RTCBuildQuality build_quality=RTC_BUILD_QUALITY_MEDIUM)
Add raycasting utilities.
Definition EmbreeRayCaster.h:760
Index add_mesh(std::shared_ptr< MeshType > mesh, const Transform &trans=Transform::Identity(), RTCBuildQuality build_quality=RTC_BUILD_QUALITY_MEDIUM)
Add an instance of a mesh to the scene, with a given transformation.
Definition EmbreeRayCaster.h:189
uint32_t cast4(uint32_t batch_size, const Point4 &origin, const Direction4 &direction, const Mask4 &mask, const Scalar4 &tmin=Scalar4::Zero(), const Scalar4 &tmax=Scalar4::Constant(std::numeric_limits< Scalar >::infinity()))
Cast a packet of up to 4 rays through the scene and check whether they hit anything or not.
Definition EmbreeRayCaster.h:561
FilterFunction get_intersection_filter(Index mesh_index) const
Get the intersection filter function currently bound to a given mesh.
Definition EmbreeRayCaster.h:375
Index get_num_instances(Index mesh_index) const
Get the number of instances of a particular mesh.
Definition EmbreeRayCaster.h:149
void update_mesh(Index index, std::shared_ptr< MeshType > mesh, RTCBuildQuality build_quality=RTC_BUILD_QUALITY_MEDIUM)
Update a particular mesh with a new mesh object.
Definition EmbreeRayCaster.h:237
void set_intersection_filter(Index mesh_index, FilterFunction filter)
Set an intersection filter that is called for every hit on (every instance of) a mesh during an inter...
Definition EmbreeRayCaster.h:362
bool cast(const Point &origin, const Direction &direction, Index &mesh_index, Index &instance_index, Index &facet_index, Scalar &ray_depth, Point &barycentric_coord, Point &normal, Scalar tmin=0, Scalar tmax=std::numeric_limits< Scalar >::infinity())
Cast a single ray through the scene, returning full data of the closest intersection including the no...
Definition EmbreeRayCaster.h:620
virtual ~EmbreeRayCaster()
Destructor.
Definition EmbreeRayCaster.h:132
void generate_scene()
Build the whole Embree scene from the specified meshes, instances, etc.
Definition EmbreeRayCaster.h:827
bool get_visibility(Index mesh_index, Index instance_index) const
Get the visibility flag of a given mesh instance.
Definition EmbreeRayCaster.h:318
virtual RTCSceneFlags get_scene_flags() const
Get the Embree scene flags.
Definition EmbreeRayCaster.h:807
const float * extract_float_data(const RaycasterMesh &mesh)
Get the vertex data of a mesh as an array of floats.
Definition EmbreeRayCaster.h:944
void update_transformation(Index mesh_index, Index instance_index, const Transform &trans)
Update the transform applied to a given mesh instance.
Definition EmbreeRayCaster.h:301
void update_mesh_vertices(Index index)
Update the object to reflect external changes to the vertices of a particular mesh which is already i...
Definition EmbreeRayCaster.h:253
uint32_t cast4(uint32_t batch_size, const Point4 &origin, const Direction4 &direction, const Mask4 &mask, Index4 &mesh_index, Index4 &instance_index, Index4 &facet_index, Scalar4 &ray_depth, Point4 &barycentric_coord, Point4 &normal, const Scalar4 &tmin=Scalar4::Zero(), const Scalar4 &tmax=Scalar4::Constant(std::numeric_limits< Scalar >::infinity()))
Cast a packet of up to 4 rays through the scene, returning full data of the closest intersections inc...
Definition EmbreeRayCaster.h:438
bool cast(const Point &origin, const Direction &direction, Index &mesh_index, Index &facet_index, Scalar &ray_depth, Point &barycentric_coord, Scalar tmin=0, Scalar tmax=std::numeric_limits< Scalar >::infinity())
Cast a single ray through the scene, returning data of the closest intersection excluding the normal ...
Definition EmbreeRayCaster.h:694
uint32_t cast4(uint32_t batch_size, const Point4 &origin, const Direction4 &direction, const Mask4 &mask, Index4 &mesh_index, Index4 &facet_index, Scalar4 &ray_depth, Point4 &barycentric_coord, const Scalar4 &tmin=Scalar4::Zero(), const Scalar4 &tmax=Scalar4::Constant(std::numeric_limits< Scalar >::infinity()))
Cast a packet of up to 4 rays through the scene, returning data of the closest intersections excludin...
Definition EmbreeRayCaster.h:529
Index get_num_instances() const
Get the total number of mesh instances.
Definition EmbreeRayCaster.h:146
void update_internal()
Update all internal structures based on the current dirty flags.
Definition EmbreeRayCaster.h:813
FilterFunction get_occlusion_filter(Index mesh_index) const
Get the occlusion filter function currently bound to a given mesh.
Definition EmbreeRayCaster.h:410
virtual RTCBuildQuality get_scene_build_quality() const
Get the Embree geometry build quality.
Definition EmbreeRayCaster.h:810
std::function< void( const EmbreeRayCaster *obj, const Index *mesh_index, const Index *instance_index, const RTCFilterFunctionNArguments *args)> FilterFunction
Interface for a hit filter function.
Definition EmbreeRayCaster.h:92
void ensure_no_errors() const
Throw an exception if an Embree error has occurred.
Definition EmbreeRayCaster.h:432
std::shared_ptr< MeshType > get_mesh(Index index) const
Get the mesh with a given index.
Definition EmbreeRayCaster.h:161
EmbreeRayCaster(RTCSceneFlags scene_flags=RTC_SCENE_FLAG_DYNAMIC, RTCBuildQuality build_quality=RTC_BUILD_QUALITY_LOW)
Constructor.
Definition EmbreeRayCaster.h:104
void commit_scene_changes()
Call rtcCommitScene() on the overall scene, if it has been marked as modified.
Definition EmbreeRayCaster.h:423
bool cast(const Point &origin, const Direction &direction, Scalar tmin=0, Scalar tmax=std::numeric_limits< Scalar >::infinity())
Cast a single ray through the scene and check whether it hits anything or not.
Definition EmbreeRayCaster.h:720
ClosestPoint query_closest_point(const Point &p) const
Use the underlying BVH to find the point closest to a query point.
Definition EmbreeRayCaster.h:1118
void update_visibility(Index mesh_index, Index instance_index, bool visible)
Update the visibility of a given mesh index (true for visible, false for invisible).
Definition EmbreeRayCaster.h:328
void set_occlusion_filter(Index mesh_index, FilterFunction filter)
Set an occlusion filter that is called for every hit on (every instance of) a mesh during an occlusio...
Definition EmbreeRayCaster.h:397
Index get_num_meshes() const
Get the total number of meshes (not instances).
Definition EmbreeRayCaster.h:143
void release_scenes()
Release internal Embree scenes.
Definition EmbreeRayCaster.h:798
Transform get_transform(Index mesh_index, Index instance_index) const
Get the transform applied to a given mesh instance.
Definition EmbreeRayCaster.h:291
const unsigned * extract_int_data(const RaycasterMesh &mesh)
Get the index data of a mesh as an array of integers.
Definition EmbreeRayCaster.h:956
Index get_mesh_for_instance(Index cumulative_instance_index) const
Get the index of the mesh corresponding to a given instance, where the instances are indexed sequenti...
Definition EmbreeRayCaster.h:176
Definition RayCasterMesh.h:25
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
#define la_debug_assert(...)
Debug assertion check.
Definition assert.h:194
constexpr T invalid()
You can use invalid<T>() to get a value that can represent "invalid" values, such as invalid indices ...
Definition invalid.h:40
constexpr auto safe_cast(SourceType value) -> std::enable_if_t<!std::is_same< SourceType, TargetType >::value, TargetType >
Perform safe cast from SourceType to TargetType, where "safe" means:
Definition safe_cast.h:50
Raycasting operations.
Definition ClosestPointResult.h:22
@ ClosestPoint
Interpolate attribute from the closest point on the source mesh.
Definition Options.h:35
Main namespace for Lagrange.
Definition ClosestPointResult.h:28