Lagrange
embree_closest_point.h
1// Source: https://github.com/embree/embree/blob/master/tutorials/closest_point/closest_point.cpp
2// SPDX-License-Identifier: Apache-2.0
3//
4// This file has been modified by Adobe.
5//
6// All modifications are Copyright 2020 Adobe.
7
8#pragma once
9
10#include <lagrange/raycasting/ClosestPointResult.h>
11
12#include <lagrange/utils/point_triangle_squared_distance.h>
13
14#include <embree3/rtcore.h>
15#include <embree3/rtcore_geometry.h>
16#include <embree3/rtcore_ray.h>
17#include <Eigen/Geometry>
18
19namespace lagrange {
20namespace raycasting {
21
22template <typename Scalar>
23bool embree_closest_point(RTCPointQueryFunctionArguments* args)
24{
25 using Point = typename ClosestPointResult<Scalar>::Point;
26 using MapType = Eigen::Map<Eigen::Matrix4f, Eigen::Aligned16>;
27 using AffineMat = Eigen::Transform<Scalar, 3, Eigen::Affine>;
28
29 assert(args->userPtr);
30 auto result = reinterpret_cast<ClosestPointResult<Scalar>*>(args->userPtr);
31
32 const unsigned int geomID = args->geomID;
33 const unsigned int primID = args->primID;
34
35 RTCPointQueryContext* context = args->context;
36 const unsigned int stack_size = args->context->instStackSize;
37 const unsigned int stack_ptr = stack_size - 1;
38
39 AffineMat inst2world =
40 (stack_size > 0 ? AffineMat(MapType(context->inst2world[stack_ptr]).template cast<Scalar>())
41 : AffineMat::Identity());
42
43 // Query position in world space
44 Point q(args->query->x, args->query->y, args->query->z);
45
46 // Get triangle information in local space
47 Point v0, v1, v2;
48 assert(result->populate_triangle);
49 result->populate_triangle(geomID, primID, v0, v1, v2);
50
51 // Bring query and primitive data in the same space if necessary.
52 if (stack_size > 0 && args->similarityScale > 0) {
53 // Instance transform is a similarity transform, therefore we
54 // can compute distance information in instance space. Therefore,
55 // transform query position into local instance space.
56 AffineMat world2inst(MapType(context->world2inst[stack_ptr]).template cast<Scalar>());
57 q = world2inst * q;
58 } else if (stack_size > 0) {
59 // Instance transform is not a similarity tranform. We have to transform the
60 // primitive data into world space and perform distance computations in
61 // world space to ensure correctness.
62 v0 = inst2world * v0;
63 v1 = inst2world * v1;
64 v2 = inst2world * v2;
65 } else {
66 // Primitive is not instanced, therefore point query and primitive are
67 // already in the same space.
68 }
69
70 // Determine distance to closest point on triangle, and transform in
71 // world space if necessary.
72 Point p;
73 Scalar l1, l2, l3;
74 Scalar d2 = point_triangle_squared_distance(q, v0, v1, v2, p, l1, l2, l3);
75 float d = std::sqrt(static_cast<float>(d2));
76 if (args->similarityScale > 0) {
77 d = d / args->similarityScale;
78 }
79
80 // Store result in userPtr and update the query radius if we found a point
81 // closer to the query position. This is optional but allows for faster
82 // traversal (due to better culling).
83 if (d < args->query->radius) {
84 args->query->radius = d;
85 result->closest_point = (args->similarityScale > 0 ? (inst2world * p).eval() : p);
86 result->mesh_index = geomID;
87 result->facet_index = primID;
88 result->barycentric_coord = Point(l1, l2, l3);
89 return true; // Return true to indicate that the query radius changed.
90 }
91
92 return false;
93}
94
95} // namespace raycasting
96} // namespace lagrange
Main namespace for Lagrange.
Definition: AABBIGL.h:30
auto point_triangle_squared_distance(const Eigen::MatrixBase< PointType > &point, const Eigen::MatrixBase< PointType > &V0, const Eigen::MatrixBase< PointType > &V1, const Eigen::MatrixBase< PointType > &V2, Eigen::PlainObjectBase< PointType > &closest_point, ScalarOf< PointType > &lambda0, ScalarOf< PointType > &lambda1, ScalarOf< PointType > &lambda2) -> ScalarOf< PointType >
Computes the point closest to a given point in a nd triangle.
Definition: point_triangle_squared_distance.h:77