RavEngine
Loading...
Searching...
No Matches
GuWindingNumberT.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef GU_WINDING_NUMBER_T_H
30#define GU_WINDING_NUMBER_T_H
31
36#include "GuTriangle.h"
37#include "foundation/PxArray.h"
38#include "foundation/PxHashMap.h"
39#include "foundation/PxVec3.h"
40#include "GuBVH.h"
41#include "GuAABBTreeQuery.h"
42#include "GuAABBTreeNode.h"
43#include "GuWindingNumberCluster.h"
44
45namespace physx
46{
47namespace Gu
48{
49 using Triangle = Gu::IndexedTriangleT<PxI32>;
50
51 template<typename R, typename V3>
53 {
54 PxMat33 WeightedOuterProductSum;
55
57
58 PX_FORCE_INLINE SecondOrderClusterApproximationT(R radius, R areaSum, const V3& weightedCentroid, const V3& weightedNormalSum, const PxMat33& weightedOuterProductSum) :
59 ClusterApproximationT<R, V3>(radius, areaSum, weightedCentroid, weightedNormalSum), WeightedOuterProductSum(weightedOuterProductSum)
60 { }
61 };
62
63 //Evaluates a first order winding number approximation for a given cluster (cluster = bunch of triangles)
64 template<typename R, typename V3>
65 PX_FORCE_INLINE R firstOrderClusterApproximation(const V3& weightedCentroid, const V3& weightedNormalSum,
66 const V3& evaluationPoint)
67 {
68 const V3 dir = weightedCentroid - evaluationPoint;
69 const R l = dir.magnitude();
70 return (R(0.25 / 3.141592653589793238462643383) / (l * l * l)) * weightedNormalSum.dot(dir);
71 }
72 template<typename R, typename V3>
73 PX_FORCE_INLINE R clusterApproximation(const ClusterApproximationT<R, V3>& c, const V3& evaluationPoint)
74 {
75 return firstOrderClusterApproximation(c.WeightedCentroid, c.WeightedNormalSum, evaluationPoint);
76 }
77
78 //Evaluates a second order winding number approximation for a given cluster (cluster = bunch of triangles)
79 template<typename R, typename V3>
80 PX_FORCE_INLINE R secondOrderClusterApproximation(const V3& weightedCentroid, const V3& weightedNormalSum,
81 const PxMat33& weightedOuterProductSum, const V3& evaluationPoint)
82 {
83 const V3 dir = weightedCentroid - evaluationPoint;
84 const R l = dir.magnitude();
85 const R l2 = l * l;
86 const R scaling = R(0.25 / 3.141592653589793238462643383) / (l2 * l);
87 const R firstOrder = scaling * weightedNormalSum.dot(dir);
88
89 const R scaling2 = -R(3.0) * scaling / l2;
90 const R m11 = scaling + scaling2 * dir.x * dir.x, m12 = scaling2 * dir.x * dir.y, m13 = scaling2 * dir.x * dir.z;
91 const R m21 = scaling2 * dir.y * dir.x, m22 = scaling + scaling2 * dir.y * dir.y, m23 = scaling2 * dir.y * dir.z;
92 const R m31 = scaling2 * dir.z * dir.x, m32 = scaling2 * dir.z * dir.y, m33 = scaling + scaling2 * dir.z * dir.z;
93
94 return firstOrder + (weightedOuterProductSum.column0.x * m11 + weightedOuterProductSum.column1.x * m12 + weightedOuterProductSum.column2.x * m13 +
95 weightedOuterProductSum.column0.y * m21 + weightedOuterProductSum.column1.y * m22 + weightedOuterProductSum.column2.y * m23 +
96 weightedOuterProductSum.column0.z * m31 + weightedOuterProductSum.column1.z * m32 + weightedOuterProductSum.column2.z * m33);
97 }
98 template<typename R, typename V3>
99 PX_FORCE_INLINE R clusterApproximation(const SecondOrderClusterApproximationT<R, V3>& c, const V3& evaluationPoint)
100 {
101 return secondOrderClusterApproximation(c.WeightedCentroid, c.WeightedNormalSum, c.WeightedOuterProductSum, evaluationPoint);
102 }
103
104 //Computes parameters to approximately represent a cluster (cluster = bunch of triangles) to be used to compute a winding number approximation
105 template<typename R, typename V3>
106 void approximateCluster(const PxArray<PxI32>& triangleSet, PxU32 start, PxU32 end, const PxU32* triangles, const V3* points,
107 const PxArray<R>& triangleAreas, const PxArray<V3>& triangleNormalsTimesTriangleArea, const PxArray<V3>& triangleCentroids, ClusterApproximationT<R, V3>& cluster)
108 {
109 V3 weightedCentroid(0., 0., 0.);
110 R areaSum = 0;
111 V3 weightedNormalSum(0., 0., 0.);
112
113 for (PxU32 i = start; i < end; ++i)
114 {
115 PxI32 triId = triangleSet[i];
116 areaSum += triangleAreas[triId];
117 weightedCentroid += triangleCentroids[triId] * triangleAreas[triId];
118 weightedNormalSum += triangleNormalsTimesTriangleArea[triId];
119 }
120 weightedCentroid = weightedCentroid / areaSum;
121
122 R radiusSquared = 0;
123 for (PxU32 i = start; i < end; ++i)
124 {
125 PxI32 triId = triangleSet[i];
126 const PxU32* tri = &triangles[3 * triId];
127 R d2 = (weightedCentroid - points[tri[0]]).magnitudeSquared();
128 if (d2 > radiusSquared) radiusSquared = d2;
129 d2 = (weightedCentroid - points[tri[1]]).magnitudeSquared();
130 if (d2 > radiusSquared) radiusSquared = d2;
131 d2 = (weightedCentroid - points[tri[2]]).magnitudeSquared();
132 if (d2 > radiusSquared) radiusSquared = d2;
133 }
134 cluster = ClusterApproximationT<R, V3>(PxSqrt(radiusSquared), areaSum, weightedCentroid, weightedNormalSum/*, weightedOuterProductSum*/);
135 }
136
137 //Computes parameters to approximately represent a cluster (cluster = bunch of triangles) to be used to compute a winding number approximation
138 template<typename R, typename V3>
139 void approximateCluster(const PxArray<PxI32>& triangleSet, PxU32 start, PxU32 end, const PxU32* triangles, const V3* points,
140 const PxArray<R>& triangleAreas, const PxArray<V3>& triangleNormalsTimesTriangleArea, const PxArray<V3>& triangleCentroids, SecondOrderClusterApproximationT<R, V3>& cluster)
141 {
142 V3 weightedCentroid(0., 0., 0.);
143 R areaSum = 0;
144 V3 weightedNormalSum(0., 0., 0.);
145
146 for (PxU32 i = start; i < end; ++i)
147 {
148 PxI32 triId = triangleSet[i];
149 areaSum += triangleAreas[triId];
150 weightedCentroid += triangleCentroids[triId] * triangleAreas[triId];
151 weightedNormalSum += triangleNormalsTimesTriangleArea[triId];
152 }
153 weightedCentroid = weightedCentroid / areaSum;
154
155 R radiusSquared = 0;
156 PxMat33 weightedOuterProductSum(PxZERO::PxZero);
157 for (PxU32 i = start; i < end; ++i)
158 {
159 PxI32 triId = triangleSet[i];
160 const PxU32* tri = &triangles[3 * triId];
161 R d2 = (weightedCentroid - points[tri[0]]).magnitudeSquared();
162 if (d2 > radiusSquared) radiusSquared = d2;
163 d2 = (weightedCentroid - points[tri[1]]).magnitudeSquared();
164 if (d2 > radiusSquared) radiusSquared = d2;
165 d2 = (weightedCentroid - points[tri[2]]).magnitudeSquared();
166 if (d2 > radiusSquared) radiusSquared = d2;
167
168 weightedOuterProductSum = weightedOuterProductSum + PxMat33::outer(triangleCentroids[triId] - weightedCentroid, triangleNormalsTimesTriangleArea[triId]);
169 }
170 cluster = SecondOrderClusterApproximationT<R, V3>(PxSqrt(radiusSquared), areaSum, weightedCentroid, weightedNormalSum, weightedOuterProductSum);
171 }
172
173 //Exact winding number evaluation, needs to be called for every triangle close to the winding number query point
174 template<typename R, typename V3>
175 PX_FORCE_INLINE R evaluateExact(V3 a, V3 b, V3 c, const V3& p)
176 {
177 const R twoOver4PI = R(0.5 / 3.141592653589793238462643383);
178
179 a -= p;
180 b -= p;
181 c -= p;
182
183 const R la = a.magnitude(),
184 lb = b.magnitude(),
185 lc = c.magnitude();
186
187 const R y = a.x * b.y * c.z - a.x * b.z * c.y - a.y * b.x * c.z + a.y * b.z * c.x + a.z * b.x * c.y - a.z * b.y * c.x;
188 const R x = (la * lb * lc + (a.x * b.x + a.y * b.y + a.z * b.z) * lc +
189 (b.x * c.x + b.y * c.y + b.z * c.z) * la + (c.x * a.x + c.y * a.y + c.z * a.z) * lb);
190 return twoOver4PI * PxAtan2(y, x);
191 }
192
193 struct Section
194 {
195 PxI32 start;
196 PxI32 end;
197
198 Section(PxI32 s, PxI32 e) : start(s), end(e)
199 {}
200 };
201
202 //Helper method that recursively traverses the given BVH tree and computes a cluster approximation for every node and links it to the node
203 template<typename R, typename V3>
204 void precomputeClusterInformation(PxI32 nodeId, const BVHNode* tree, const PxU32* triangles, const PxU32 numTriangles,
205 const V3* points, PxHashMap<PxU32, ClusterApproximationT<R, V3>>& infos, const PxArray<R> triangleAreas,
206 const PxArray<V3>& triangleNormalsTimesTriangleArea, const PxArray<V3>& triangleCentroids)
207 {
208 PxArray<PxI32> stack;
209 stack.pushBack(nodeId);
210 PxArray<Section> returnStack;
211
212 PxArray<PxI32> triIndices;
213 triIndices.reserve(numTriangles);
214 infos.reserve(PxU32(1.2f*numTriangles));
215
216 while (stack.size() > 0)
217 {
218 nodeId = stack.popBack();
219
220 if (nodeId >= 0)
221 {
222 const BVHNode& node = tree[nodeId];
223 if (node.isLeaf())
224 {
225 triIndices.pushBack(node.getPrimitiveIndex());
226 returnStack.pushBack(Section(triIndices.size() - 1, triIndices.size()));
227 continue;
228 }
229
230 stack.pushBack(-nodeId - 1); //Marker for return index
231 stack.pushBack(node.getPosIndex());
232 stack.pushBack(node.getPosIndex() + 1);
233 }
234 else
235 {
236 Section trianglesA = returnStack.popBack();
237 Section trianglesB = returnStack.popBack();
238 Section sum(trianglesB.start, trianglesA.end);
239
240 nodeId = -nodeId - 1;
241 ClusterApproximationT<R, V3> c;
242 approximateCluster<R, V3>(triIndices, sum.start, sum.end, triangles, points, triangleAreas, triangleNormalsTimesTriangleArea, triangleCentroids, c);
243 infos.insert(PxU32(nodeId), c);
244
245 returnStack.pushBack(sum);
246 }
247 }
248 }
249
250 //Precomputes a cluster approximation for every node in the BVH tree
251 template<typename R, typename V3>
252 void precomputeClusterInformation(const BVHNode* tree, const PxU32* triangles, const PxU32 numTriangles,
253 const V3* points, PxHashMap<PxU32, ClusterApproximationT<R, V3>>& result, PxI32 rootNodeIndex)
254 {
255 PxArray<R> triangleAreas;
256 triangleAreas.resize(numTriangles);
257 PxArray<V3> triangleNormalsTimesTriangleArea;
258 triangleNormalsTimesTriangleArea.resize(numTriangles);
259 PxArray<V3> triangleCentroids;
260 triangleCentroids.resize(numTriangles);
261
262 for (PxU32 i = 0; i < numTriangles; ++i)
263 {
264 const PxU32* tri = &triangles[3 * i];
265 const V3& a = points[tri[0]];
266 const V3& b = points[tri[1]];
267 const V3& c = points[tri[2]];
268 triangleNormalsTimesTriangleArea[i] = (b - a).cross(c - a) * R(0.5);
269 triangleAreas[i] = triangleNormalsTimesTriangleArea[i].magnitude();
270 triangleCentroids[i] = (a + b + c) * R(1.0 / 3.0);
271 }
272
273 result.clear();
274 precomputeClusterInformation(rootNodeIndex, tree, triangles, numTriangles, points, result, triangleAreas, triangleNormalsTimesTriangleArea, triangleCentroids);
275 }
276
277 template<typename R, typename V3>
279 {
280 public:
281 R mWindingNumber = 0;
282 private:
283 const PxU32* mTriangles;
284 const V3* mPoints;
286 V3 mQueryPoint;
287 R mDistanceThresholdBeta;
288
289 public:
290 PX_FORCE_INLINE WindingNumberTraversalController(const PxU32* triangles, const V3* points,
291 const PxHashMap<PxU32, ClusterApproximationT<R, V3>>& clusters, const V3& queryPoint, R distanceThresholdBeta = 2)
292 : mTriangles(triangles), mPoints(points), mClusters(clusters), mQueryPoint(queryPoint), mDistanceThresholdBeta(distanceThresholdBeta)
293 { }
294
295 PX_FORCE_INLINE Gu::TraversalControl::Enum analyze(const BVHNode& node, PxI32 nodeIndex)
296 {
297 if (node.isLeaf())
298 {
299 PX_ASSERT(node.getNbPrimitives() == 1);
300 const PxU32* tri = &mTriangles[3 * node.getPrimitiveIndex()];
301 mWindingNumber += evaluateExact<R, V3>(mPoints[tri[0]], mPoints[tri[1]], mPoints[tri[2]], mQueryPoint);
302 return Gu::TraversalControl::eDontGoDeeper;
303 }
304 const ClusterApproximationT<R, V3>& cluster = mClusters.find(nodeIndex)->second;
305 const R distSquared = (mQueryPoint - cluster.WeightedCentroid).magnitudeSquared();
306 const R threshold = mDistanceThresholdBeta * cluster.Radius;
307 if (distSquared > threshold * threshold)
308 {
309 //mWindingNumber += secondOrderClusterApproximation(cluster.WeightedCentroid, cluster.WeightedNormalSum, cluster.WeightedOuterProductSum, mQueryPoint);
310 mWindingNumber += firstOrderClusterApproximation<R, V3>(cluster.WeightedCentroid, cluster.WeightedNormalSum, mQueryPoint); // secondOrderClusterApproximation(cluster.WeightedCentroid, cluster.WeightedNormalSum, cluster.WeightedOuterProductSum, mQueryPoint);
311 return Gu::TraversalControl::eDontGoDeeper;
312 }
313 return Gu::TraversalControl::eGoDeeper;
314 }
315
316 private:
318 };
319
320 template<typename R, typename V3>
321 R computeWindingNumber(const BVHNode* tree, const V3& q, R beta, const PxHashMap<PxU32, ClusterApproximationT<R, V3>>& clusters,
322 const PxU32* triangles, const V3* points)
323 {
324 WindingNumberTraversalController<R, V3> c(triangles, points, clusters, q, beta);
325 traverseBVH<WindingNumberTraversalController<R, V3>>(tree, c);
326 return c.mWindingNumber;
327 }
328}
329}
330
332#endif
Definition GuWindingNumberT.h:279
Definition PxArray.h:53
PX_NOINLINE void resize(const uint32_t size, const T &a=T())
Definition PxArray.h:637
PX_FORCE_INLINE uint32_t size() const
Definition PxArray.h:242
PX_FORCE_INLINE T & pushBack(const T &a)
Definition PxArray.h:296
PX_INLINE void reserve(const uint32_t capacity)
Definition PxArray.h:486
PX_INLINE T popBack()
Definition PxArray.h:311
Definition PxHashMap.h:78
PX_CUDA_CALLABLE static PX_INLINE const PxMat33T outer(const PxVec3T< float > &a, const PxVec3T< float > &b)
Computes the outer product of two vectors.
Definition PxMat33.h:194
3x3 matrix class
Definition PxMat33.h:91
GLM_FUNC_QUALIFIER vec< 3, T, Q > cross(vec< 3, T, Q > const &x, vec< 3, T, Q > const &y)
Definition func_geometric.inl:175
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_CUDA_CALLABLE PX_FORCE_INLINE float PxAtan2(float x, float y)
Arctangent of (x/y) with correct sign. Returns angle between -PI and PI in radians Unit: Radians.
Definition PxMath.h:302
PX_CUDA_CALLABLE PX_FORCE_INLINE float PxSqrt(float a)
Square root.
Definition PxMath.h:146
Definition SnippetImmediateMode.cpp:303
Definition GuAABBTreeNode.h:44
Definition GuWindingNumberCluster.h:42
Definition GuWindingNumberT.h:53
Definition GuWindingNumberT.h:194