Revision control

- //
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
- // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
+ // Copyright (c) 2008-2026 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
- #ifndef PXFOUNDATION_PXMATHUTILS_H
- #define PXFOUNDATION_PXMATHUTILS_H
+ #ifndef PX_MATH_UTILS_H
+ #define PX_MATH_UTILS_H
- /** \addtogroup common
- @{
- */
- #include "foundation/Px.h"
#include "foundation/PxFoundationConfig.h"
+ #include "foundation/PxSimpleTypes.h"
+ #include "foundation/PxVec4.h"
+ #include "foundation/PxAssert.h"
#include "foundation/PxPlane.h"
- #include "foundation/PxTransform.h"
+ #include "foundation/PxMat33.h"
+
#if !PX_DOXYGEN
namespace physx
{
#endif
/**
\brief finds the shortest rotation between two vectors.
\param[in] from the vector to start from
\param[in] target the vector to rotate to
\return a rotation about an axis normal to the two vectors which takes one to the other via the shortest path
*/
PX_FOUNDATION_API PxQuat PxShortestRotation(const PxVec3& from, const PxVec3& target);
/* \brief diagonalizes a 3x3 symmetric matrix y
The returned matrix satisfies M = R * D * R', where R is the rotation matrix for the output quaternion, R' its
transpose, and D the diagonal matrix
If the matrix is not symmetric, the result is undefined.
\param[in] m the matrix to diagonalize
\param[out] axes a quaternion rotation which diagonalizes the matrix
\return the vector diagonal of the diagonalized matrix.
*/
PX_FOUNDATION_API PxVec3 PxDiagonalize(const PxMat33& m, PxQuat& axes);
/** \brief creates a transform from the endpoints of a segment, suitable for an actor transform for a PxCapsuleGeometry
\param[in] p0 one end of major axis of the capsule
\param[in] p1 the other end of the axis of the capsule
\param[out] halfHeight the halfHeight of the capsule. This parameter is optional.
\return A PxTransform which will transform the vector (1,0,0) to the capsule axis shrunk by the halfHeight
*/
PX_FOUNDATION_API PxTransform PxTransformFromSegment(const PxVec3& p0, const PxVec3& p1, PxReal* halfHeight = NULL);
/** \brief creates a transform from a plane equation, suitable for an actor transform for a PxPlaneGeometry
\param[in] plane the desired plane equation
\return a PxTransform which will transform the plane PxPlane(1,0,0,0) to the specified plane
*/
PX_FOUNDATION_API PxTransform PxTransformFromPlaneEquation(const PxPlane& plane);
/** \brief creates a plane equation from a transform, such as the actor transform for a PxPlaneGeometry
- \param[in] transform the transform
+ \param[in] pose the transform
\return the plane
*/
- PX_INLINE PxPlane PxPlaneEquationFromTransform(const PxTransform& transform)
+ PX_INLINE PxPlane PxPlaneEquationFromTransform(const PxTransform& pose)
{
- return transform.transform(PxPlane(1.f,0.f,0.f,0.f));
+ return PxPlane(1.0f, 0.0f, 0.0f, 0.0f).transform(pose);
}
+ /**
+ \brief Spherical linear interpolation of two quaternions.
+ \param[in] t is the interpolation parameter in range (0, 1)
+ \param[in] left is the start of the interpolation
+ \param[in] right is the end of the interpolation
+ \return Returns left when t=0, right when t=1 and a linear interpolation of left and right when 0 < t < 1.
+ Returns angle between -PI and PI in radians
+ */
+ PX_CUDA_CALLABLE PX_INLINE PxQuat PxSlerp(const PxReal t, const PxQuat& left, const PxQuat& right)
+ {
+ const PxReal quatEpsilon = (PxReal(1.0e-8f));
+
+ PxReal cosine = left.dot(right);
+ PxReal sign = PxReal(1);
+ if (cosine < 0)
+ {
+ cosine = -cosine;
+ sign = PxReal(-1);
+ }
+
+ PxReal sine = PxReal(1) - cosine * cosine;
+
+ if (sine >= quatEpsilon * quatEpsilon)
+ {
+ sine = PxSqrt(sine);
+ const PxReal angle = PxAtan2(sine, cosine);
+ const PxReal i_sin_angle = PxReal(1) / sine;
+
+ const PxReal leftw = PxSin(angle * (PxReal(1) - t)) * i_sin_angle;
+ const PxReal rightw = PxSin(angle * t) * i_sin_angle * sign;
+
+ return left * leftw + right * rightw;
+ }
+
+ return left;
+ }
+
+ /**
+ \brief integrate transform.
+ \param[in] curTrans The current transform
+ \param[in] linvel Linear velocity
+ \param[in] angvel Angular velocity
+ \param[in] timeStep The time-step for integration
+ \param[out] result The integrated transform
+ */
+ PX_FOUNDATION_API void PxIntegrateTransform(const PxTransform& curTrans, const PxVec3& linvel, const PxVec3& angvel,
+ PxReal timeStep, PxTransform& result);
+
+ //! \brief Compute the exponent of a PxVec3
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat PxExp(const PxVec3& v)
+ {
+ const PxReal m = v.magnitudeSquared();
+ return m < 1e-24f ? PxQuat(PxIdentity) : PxQuat(PxSqrt(m), v * PxRecipSqrt(m));
+ }
+
+ /**
+ \brief computes a oriented bounding box around the scaled basis.
+ \param basis Input = skewed basis, Output = (normalized) orthogonal basis.
+ \return Bounding box extent.
+ */
+ PX_FOUNDATION_API PxVec3 PxOptimizeBoundingBox(PxMat33& basis);
+
+ /**
+ \brief return Returns the log of a PxQuat
+ */
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxLog(const PxQuat& q)
+ {
+ const PxReal s = q.getImaginaryPart().magnitude();
+ if (s < 1e-12f)
+ return PxVec3(0.0f);
+ // force the half-angle to have magnitude <= pi/2
+ PxReal halfAngle = q.w < 0 ? PxAtan2(-s, -q.w) : PxAtan2(s, q.w);
+ PX_ASSERT(halfAngle >= -PxPi / 2 && halfAngle <= PxPi / 2);
+
+ return q.getImaginaryPart().getNormalized() * 2.f * halfAngle;
+ }
+
+ /**
+ \brief return Returns 0 if v.x is largest element of v, 1 if v.y is largest element, 2 if v.z is largest element.
+ */
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 PxLargestAxis(const PxVec3& v)
+ {
+ PxU32 m = PxU32(v.y > v.x ? 1 : 0);
+ return v.z > v[m] ? 2 : m;
+ }
+
+ /**
+ \brief Compute tan(theta/2) given sin(theta) and cos(theta) as inputs.
+ \param[in] sin has value sin(theta)
+ \param[in] cos has value cos(theta)
+ \return Returns tan(theta/2)
+ */
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal PxTanHalf(PxReal sin, PxReal cos)
+ {
+ // PT: avoids divide by zero for singularity. We return sqrt(FLT_MAX) instead of FLT_MAX
+ // to make sure the calling code doesn't generate INF values when manipulating the returned value
+ // (some joints multiply it by 4, etc).
+ if (cos == -1.0f)
+ return sin < 0.0f ? -sqrtf(FLT_MAX) : sqrtf(FLT_MAX);
+
+ // PT: half-angle formula: tan(a/2) = sin(a)/(1+cos(a))
+ return sin / (1.0f + cos);
+ }
+
+ /**
+ \brief Compute the closest point on an 2d ellipse to a given 2d point.
+ \param[in] point is a 2d point in the y-z plane represented by (point.y, point.z)
+ \param[in] radii are the radii of the ellipse (radii.y and radii.z) in the y-z plane.
+ \return Returns the 2d position on the surface of the ellipse that is closest to point.
+ */
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxEllipseClamp(const PxVec3& point, const PxVec3& radii)
+ {
+ // lagrange multiplier method with Newton/Halley hybrid root-finder.
+ // for proof of Newton step robustness and initial estimate.
+ // Halley converges much faster but sometimes overshoots - when that happens we take
+ // a newton step instead
+
+ // converges in 1-2 iterations where D&C works well, and it's good with 4 iterations
+ // with any ellipse that isn't completely crazy
+
+ const PxU32 MAX_ITERATIONS = 20;
+ const PxReal convergenceThreshold = 1e-4f;
+
+ // iteration requires first quadrant but we recover generality later
+
+ PxVec3 q(0, PxAbs(point.y), PxAbs(point.z));
+ const PxReal tinyEps = 1e-6f; // very close to minor axis is numerically problematic but trivial
+ if (radii.y >= radii.z)
+ {
+ if (q.z < tinyEps)
+ return PxVec3(0, point.y > 0 ? radii.y : -radii.y, 0);
+ }
+ else
+ {
+ if (q.y < tinyEps)
+ return PxVec3(0, 0, point.z > 0 ? radii.z : -radii.z);
+ }
+
+ PxVec3 denom, e2 = radii.multiply(radii), eq = radii.multiply(q);
+
+ // we can use any initial guess which is > maximum(-e.y^2,-e.z^2) and for which f(t) is > 0.
+ // this guess works well near the axes, but is weak along the diagonals.
+
+ PxReal t = PxMax(eq.y - e2.y, eq.z - e2.z);
+
+ for (PxU32 i = 0; i < MAX_ITERATIONS; i++)
+ {
+ denom = PxVec3(0, 1 / (t + e2.y), 1 / (t + e2.z));
+ PxVec3 denom2 = eq.multiply(denom);
+
+ PxVec3 fv = denom2.multiply(denom2);
+ PxReal f = fv.y + fv.z - 1;
+
+ // although in exact arithmetic we are guaranteed f>0, we can get here
+ // on the first iteration via catastrophic cancellation if the point is
+ // very close to the origin. In that case we just behave as if f=0
+
+ if (f < convergenceThreshold)
+ return e2.multiply(point).multiply(denom);
+
+ PxReal df = fv.dot(denom) * -2.0f;
+ t = t - f / df;
+ }
+
+ // we didn't converge, so clamp what we have
+ PxVec3 r = e2.multiply(point).multiply(denom);
+ return r * PxRecipSqrt(PxSqr(r.y / radii.y) + PxSqr(r.z / radii.z));
+ }
+
+ /**
+ \brief Compute from an input quaternion q a pair of quaternions (swing, twist) such that
+ q = swing * twist
+ with the caveats that swing.x = twist.y = twist.z = 0.
+ \param[in] q is the quaternion to be decomposed into swing and twist quaternions.
+ \param[out] swing is the swing component of the quaternion decomposition.
+ \param[out] twist is the twist component of the quaternion decomposition.
+ */
+ PX_CUDA_CALLABLE PX_FORCE_INLINE void PxSeparateSwingTwist(const PxQuat& q, PxQuat& swing, PxQuat& twist)
+ {
+ twist = q.x != 0.0f ? PxQuat(q.x, 0, 0, q.w).getNormalized() : PxQuat(PxIdentity);
+ swing = q * twist.getConjugate();
+ }
+
+ /**
+ \brief Compute the angle between two non-unit vectors
+ \param[in] v0 is one of the non-unit vectors
+ \param[in] v1 is the other of the two non-unit vectors
+ \return Returns the angle (in radians) between the two vector v0 and v1.
+ */
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxF32 PxComputeAngle(const PxVec3& v0, const PxVec3& v1)
+ {
+ const PxF32 cos = v0.dot(v1); // |v0|*|v1|*Cos(Angle)
+ const PxF32 sin = (v0.cross(v1)).magnitude(); // |v0|*|v1|*Sin(Angle)
+ return PxAtan2(sin, cos);
+ }
+
+ /**
+ \brief Compute two normalized vectors (right and up) that are perpendicular to an input normalized vector (dir).
+ \param[in] dir is a normalized vector that is used to compute the perpendicular vectors.
+ \param[out] right is the first of the two vectors perpendicular to dir
+ \param[out] up is the second of the two vectors perpendicular to dir
+ */
+ PX_CUDA_CALLABLE PX_INLINE void PxComputeBasisVectors(const PxVec3& dir, PxVec3& right, PxVec3& up)
+ {
+ // Derive two remaining vectors
+ if (PxAbs(dir.y) <= 0.9999f)
+ {
+ right = PxVec3(dir.z, 0.0f, -dir.x);
+ right.normalize();
+
+ // PT: normalize not needed for 'up' because dir & right are unit vectors,
+ // and by construction the angle between them is 90 degrees (i.e. sin(angle)=1)
+ up = PxVec3(dir.y * right.z, dir.z * right.x - dir.x * right.z, -dir.y * right.x);
+ }
+ else
+ {
+ right = PxVec3(1.0f, 0.0f, 0.0f);
+
+ up = PxVec3(0.0f, dir.z, -dir.y);
+ up.normalize();
+ }
+ }
+
+ /**
+ \brief Compute three normalized vectors (dir, right and up) that are parallel to (dir) and perpendicular to (right, up) the
+ normalized direction vector (p1 - p0)/||p1 - p0||.
+ \param[in] p0 is used to compute the normalized vector dir = (p1 - p0)/||p1 - p0||.
+ \param[in] p1 is used to compute the normalized vector dir = (p1 - p0)/||p1 - p0||.
+ \param[out] dir is the normalized vector (p1 - p0)/||p1 - p0||.
+ \param[out] right is the first of the two normalized vectors perpendicular to dir
+ \param[out] up is the second of the two normalized vectors perpendicular to dir
+ */
+ PX_INLINE void PxComputeBasisVectors(const PxVec3& p0, const PxVec3& p1, PxVec3& dir, PxVec3& right, PxVec3& up)
+ {
+ // Compute the new direction vector
+ dir = p1 - p0;
+ dir.normalize();
+
+ // Derive two remaining vectors
+ PxComputeBasisVectors(dir, right, up);
+ }
+
+
+ /**
+ \brief Compute (i+1)%3
+ */
+ PX_INLINE PxU32 PxGetNextIndex3(PxU32 i)
+ {
+ return (i + 1 + (i >> 1)) & 3;
+ }
+
+ /**
+ \brief Computes the barycentric coordinates for a point inside a tetrahedron.
+
+ This function calculates the barycentric coordinates of a point p with respect to a tetrahedron defined by vertices a, b, c, and d.
+
+ \param[in] a Vertex A of the tetrahedron
+ \param[in] b Vertex B of the tetrahedron
+ \param[in] c Vertex C of the tetrahedron
+ \param[in] d Vertex D of the tetrahedron
+ \param[in] p The point for which to compute the barycentric coordinates
+ \param[out] bary The resulting barycentric coordinates as a PxVec4
+ */
+ PX_INLINE PX_CUDA_CALLABLE void PxComputeBarycentric(const PxVec3& a, const PxVec3& b, const PxVec3& c, const PxVec3& d, const PxVec3& p, PxVec4& bary)
+ {
+ const PxVec3 ba = b - a;
+ const PxVec3 ca = c - a;
+ const PxVec3 da = d - a;
+ const PxVec3 pa = p - a;
+
+ const PxReal detBcd = ba.dot(ca.cross(da));
+ const PxReal detPcd = pa.dot(ca.cross(da));
+
+ bary.y = detPcd / detBcd;
+
+ const PxReal detBpd = ba.dot(pa.cross(da));
+ bary.z = detBpd / detBcd;
+
+ const PxReal detBcp = ba.dot(ca.cross(pa));
+
+ bary.w = detBcp / detBcd;
+ bary.x = 1 - bary.y - bary.z - bary.w;
+ }
+
+ /**
+ \brief Computes the barycentric coordinates for a point inside a triangle.
+
+ This function calculates the barycentric coordinates of a point p with respect to a triangle defined by vertices a, b, and c.
+
+ \param[in] a Vertex A of the triangle
+ \param[in] b Vertex B of the triangle
+ \param[in] c Vertex C of the triangle
+ \param[in] p The point for which to compute the barycentric coordinates
+ \param[out] bary The resulting barycentric coordinates as a PxVec4
+ */
+ PX_INLINE PX_CUDA_CALLABLE void PxComputeBarycentric(const PxVec3& a, const PxVec3& b, const PxVec3& c, const PxVec3& p, PxVec4& bary)
+ {
+ const PxVec3 v0 = b - a;
+ const PxVec3 v1 = c - a;
+ const PxVec3 v2 = p - a;
+
+ const float d00 = v0.dot(v0);
+ const float d01 = v0.dot(v1);
+ const float d11 = v1.dot(v1);
+ const float d20 = v2.dot(v0);
+ const float d21 = v2.dot(v1);
+
+ const float denom = d00 * d11 - d01 * d01;
+ const float v = (d11 * d20 - d01 * d21) / denom;
+ const float w = (d00 * d21 - d01 * d20) / denom;
+ const float u = 1.f - v - w;
+
+ bary.x = u; bary.y = v; bary.z = w;
+ bary.w = 0.f;
+ }
+
+ /**
+ \brief Computes the barycentric coordinates for a point inside a triangle (deprecated).
+
+ This function is deprecated. Use PxComputeBarycentric instead.
+
+ \param[in] a Vertex A of the triangle
+ \param[in] b Vertex B of the triangle
+ \param[in] c Vertex C of the triangle
+ \param[in] p The point for which to compute the barycentric coordinates
+ \param[out] bary The resulting barycentric coordinates as a PxVec4
+
+ \see PxComputeBarycentric
+ */
+ PX_INLINE PX_CUDA_CALLABLE PX_DEPRECATED void computeBarycentric(const PxVec3& a, const PxVec3& b, const PxVec3& c, const PxVec3& p, PxVec4& bary)
+ {
+ PxComputeBarycentric(a, b, c, p, bary);
+ }
+
+ /**
+ \brief Computes the barycentric coordinates for a point inside a tetrahedron (deprecated).
+
+ This function is deprecated. Use PxComputeBarycentric instead.
+
+ \param[in] a Vertex A of the tetrahedron
+ \param[in] b Vertex B of the tetrahedron
+ \param[in] c Vertex C of the tetrahedron
+ \param[in] d Vertex D of the tetrahedron
+ \param[in] p The point for which to compute the barycentric coordinates
+ \param[out] bary The resulting barycentric coordinates as a PxVec4
+
+ \see PxComputeBarycentric
+ */
+ PX_INLINE PX_CUDA_CALLABLE PX_DEPRECATED void computeBarycentric(const PxVec3& a, const PxVec3& b, const PxVec3& c, const PxVec3& d, const PxVec3& p, PxVec4& bary)
+ {
+ PxComputeBarycentric(a, b, c, d, p, bary);
+ }
+
+
+ /**
+ \brief Performs linear interpolation between two values.
+
+ \param[in] a The start value
+ \param[in] b The end value
+ \param[in] t The interpolation parameter in the range [0, 1]
+ \return The interpolated value
+ */
+ PX_INLINE PX_CUDA_CALLABLE static float PxLerp(float a, float b, float t)
+ {
+ return a + t * (b - a);
+ }
+
+ /**
+ \brief Performs bilinear interpolation.
+
+ \param[in] f00 The value at (0, 0)
+ \param[in] f10 The value at (1, 0)
+ \param[in] f01 The value at (0, 1)
+ \param[in] f11 The value at (1, 1)
+ \param[in] tx The interpolation parameter along the x-axis
+ \param[in] ty The interpolation parameter along the y-axis
+ \return The interpolated value
+
+ \see PxLerp
+ */
+ PX_INLINE PX_CUDA_CALLABLE static PxReal PxBiLerp(
+ const PxReal f00,
+ const PxReal f10,
+ const PxReal f01,
+ const PxReal f11,
+ const PxReal tx, const PxReal ty)
+ {
+ return PxLerp(
+ PxLerp(f00, f10, tx),
+ PxLerp(f01, f11, tx),
+ ty);
+ }
+
+ /**
+ \brief Performs trilinear interpolation.
+
+ \param[in] f000 The value at (0, 0, 0)
+ \param[in] f100 The value at (1, 0, 0)
+ \param[in] f010 The value at (0, 1, 0)
+ \param[in] f110 The value at (1, 1, 0)
+ \param[in] f001 The value at (0, 0, 1)
+ \param[in] f101 The value at (1, 0, 1)
+ \param[in] f011 The value at (0, 1, 1)
+ \param[in] f111 The value at (1, 1, 1)
+ \param[in] tx The interpolation parameter along the x-axis
+ \param[in] ty The interpolation parameter along the y-axis
+ \param[in] tz The interpolation parameter along the z-axis
+ \return The interpolated value
+
+ \see PxLerp PxBiLerp
+ */
+ PX_INLINE PX_CUDA_CALLABLE static PxReal PxTriLerp(
+ const PxReal f000,
+ const PxReal f100,
+ const PxReal f010,
+ const PxReal f110,
+ const PxReal f001,
+ const PxReal f101,
+ const PxReal f011,
+ const PxReal f111,
+ const PxReal tx,
+ const PxReal ty,
+ const PxReal tz)
+ {
+ return PxLerp(
+ PxBiLerp(f000, f100, f010, f110, tx, ty),
+ PxBiLerp(f001, f101, f011, f111, tx, ty),
+ tz);
+ }
+
+ /**
+ \brief Computes the 1D index for a 3D grid point.
+
+ \param[in] i The x-coordinate index
+ \param[in] j The y-coordinate index
+ \param[in] k The z-coordinate index
+ \param[in] nbX The number of grid points along the x-axis
+ \param[in] nbY The number of grid points along the y-axis
+ \return The 1D index corresponding to the 3D grid point
+ */
+ PX_INLINE PX_CUDA_CALLABLE static PxU32 PxSDFIdx(PxU32 i, PxU32 j, PxU32 k, PxU32 nbX, PxU32 nbY)
+ {
+ return i + j * nbX + k * nbX*nbY;
+ }
+
+ /**
+ \brief Samples the signed distance field (SDF) at a given local position.
+
+ This function samples the SDF at a given local position within the defined box bounds and calculates the interpolated distance value. It handles grid clamping and ensures that the sampled value is within the tolerance limit.
+
+ \param[in] sdf A pointer to the SDF data
+ \param[in] localPos The local position to sample the SDF
+ \param[in] sdfBoxLower The lower bound of the SDF box
+ \param[in] sdfBoxHigher The upper bound of the SDF box
+ \param[in] sdfDx The spacing between grid points in the SDF
+ \param[in] invSdfDx The inverse of the grid spacing
+ \param[in] dimX The number of grid points along the x-axis
+ \param[in] dimY The number of grid points along the y-axis
+ \param[in] dimZ The number of grid points along the z-axis
+ \param[in] tolerance The tolerance for clamping the grid points
+ \return The sampled SDF value
+
+ \see PxTriLerp PxSDFIdx
+ */
+ PX_INLINE PX_CUDA_CALLABLE static PxReal PxSDFSample(const PxReal* PX_RESTRICT sdf, const PxVec3& localPos, const PxVec3& sdfBoxLower,
+ const PxVec3& sdfBoxHigher, const PxReal sdfDx, const PxReal invSdfDx, const PxU32 dimX, const PxU32 dimY, const PxU32 dimZ, PxReal tolerance)
+ {
+ PxVec3 clampedGridPt = localPos.maximum(sdfBoxLower).minimum(sdfBoxHigher);
+
+ const PxVec3 diff = (localPos - clampedGridPt);
+
+ if (diff.magnitudeSquared() > tolerance*tolerance)
+ return PX_MAX_F32;
+
+ PxVec3 f = (clampedGridPt - sdfBoxLower) * invSdfDx;
+
+ PxU32 i = PxU32(f.x);
+ PxU32 j = PxU32(f.y);
+ PxU32 k = PxU32(f.z);
+
+ f -= PxVec3(PxReal(i), PxReal(j), PxReal(k));
+
+ if (i >= (dimX - 1))
+ {
+ i = dimX - 2;
+ clampedGridPt.x -= f.x * sdfDx;
+ f.x = 1.f;
+ }
+ if (j >= (dimY - 1))
+ {
+ j = dimY - 2;
+ clampedGridPt.y -= f.y * sdfDx;
+ f.y = 1.f;
+ }
+ if (k >= (dimZ - 1))
+ {
+ k = dimZ - 2;
+ clampedGridPt.z -= f.z * sdfDx;
+ f.z = 1.f;
+ }
+
+ const PxReal s000 = sdf[PxSDFIdx(i, j, k, dimX, dimY)];
+ const PxReal s100 = sdf[PxSDFIdx(i + 1, j, k, dimX, dimY)];
+ const PxReal s010 = sdf[PxSDFIdx(i, j + 1, k, dimX, dimY)];
+ const PxReal s110 = sdf[PxSDFIdx(i + 1, j + 1, k, dimX, dimY)];
+ const PxReal s001 = sdf[PxSDFIdx(i, j, k + 1, dimX, dimY)];
+ const PxReal s101 = sdf[PxSDFIdx(i + 1, j, k + 1, dimX, dimY)];
+ const PxReal s011 = sdf[PxSDFIdx(i, j + 1, k + 1, dimX, dimY)];
+ const PxReal s111 = sdf[PxSDFIdx(i + 1, j + 1, k + 1, dimX, dimY)];
+
+ PxReal dist = PxTriLerp(
+ s000,
+ s100,
+ s010,
+ s110,
+ s001,
+ s101,
+ s011,
+ s111,
+ f.x, f.y, f.z);
+
+ dist += diff.magnitude();
+
+ return dist;
+ }
+
+ #if !PX_DOXYGEN // remove due to failing references
+
+ PX_DEPRECATED struct Interpolation
+ {
+ /**
+ \brief Performs linear interpolation between two values.
+
+ \param[in] a The start value
+ \param[in] b The end value
+ \param[in] t The interpolation parameter in the range [0, 1]
+ \return The interpolated value
+
+ \deprecated Please use corresponding freestanding function outside of Interpolation scope.
+ */
+ PX_DEPRECATED PX_INLINE PX_CUDA_CALLABLE static float PxLerp(float a, float b, float t)
+ {
+ return ::physx::PxLerp(a, b, t);
+ }
+
+ /**
+ \brief Performs bilinear interpolation.
+
+ \param[in] f00 The value at (0, 0)
+ \param[in] f10 The value at (1, 0)
+ \param[in] f01 The value at (0, 1)
+ \param[in] f11 The value at (1, 1)
+ \param[in] tx The interpolation parameter along the x-axis
+ \param[in] ty The interpolation parameter along the y-axis
+ \return The interpolated value
+
+ \deprecated Please use corresponding freestanding function outside of Interpolation scope.
+ */
+ PX_DEPRECATED PX_INLINE PX_CUDA_CALLABLE static PxReal PxBiLerp(
+ const PxReal f00,
+ const PxReal f10,
+ const PxReal f01,
+ const PxReal f11,
+ const PxReal tx, const PxReal ty)
+ {
+ return ::physx::PxBiLerp(f00, f10, f01, f11, tx, ty);
+ }
+
+ /**
+ \brief Performs trilinear interpolation.
+
+ \param[in] f000 The value at (0, 0, 0)
+ \param[in] f100 The value at (1, 0, 0)
+ \param[in] f010 The value at (0, 1, 0)
+ \param[in] f110 The value at (1, 1, 0)
+ \param[in] f001 The value at (0, 0, 1)
+ \param[in] f101 The value at (1, 0, 1)
+ \param[in] f011 The value at (0, 1, 1)
+ \param[in] f111 The value at (1, 1, 1)
+ \param[in] tx The interpolation parameter along the x-axis
+ \param[in] ty The interpolation parameter along the y-axis
+ \param[in] tz The interpolation parameter along the z-axis
+ \return The interpolated value
+
+ \deprecated Please use corresponding freestanding function outside of Interpolation scope.
+ */
+ PX_DEPRECATED PX_INLINE PX_CUDA_CALLABLE static PxReal PxTriLerp(
+ const PxReal f000,
+ const PxReal f100,
+ const PxReal f010,
+ const PxReal f110,
+ const PxReal f001,
+ const PxReal f101,
+ const PxReal f011,
+ const PxReal f111,
+ const PxReal tx,
+ const PxReal ty,
+ const PxReal tz)
+ {
+ return ::physx::PxTriLerp(f000, f100, f010, f110, f001, f101, f011, f111, tx, ty, tz);
+ }
+
+ /**
+ \brief Computes the 1D index for a 3D grid point.
+
+ \param[in] i The x-coordinate index
+ \param[in] j The y-coordinate index
+ \param[in] k The z-coordinate index
+ \param[in] nbX The number of grid points along the x-axis
+ \param[in] nbY The number of grid points along the y-axis
+ \return The 1D index corresponding to the 3D grid point
+
+ \deprecated Please use corresponding freestanding function outside of Interpolation scope.
+ */
+ PX_DEPRECATED PX_INLINE PX_CUDA_CALLABLE static PxU32 PxSDFIdx(PxU32 i, PxU32 j, PxU32 k, PxU32 nbX, PxU32 nbY)
+ {
+ return ::physx::PxSDFIdx(i, j, k, nbX, nbY);
+ }
+
+ /**
+ \brief Samples the signed distance field (SDF) at a given local position.
+
+ This function samples the SDF at a given local position within the defined box bounds and calculates the interpolated distance value. It handles grid clamping and ensures that the sampled value is within the tolerance limit.
+
+ \param[in] sdf A pointer to the SDF data
+ \param[in] localPos The local position to sample the SDF
+ \param[in] sdfBoxLower The lower bound of the SDF box
+ \param[in] sdfBoxHigher The upper bound of the SDF box
+ \param[in] sdfDx The spacing between grid points in the SDF
+ \param[in] invSdfDx The inverse of the grid spacing
+ \param[in] dimX The number of grid points along the x-axis
+ \param[in] dimY The number of grid points along the y-axis
+ \param[in] dimZ The number of grid points along the z-axis
+ \param[in] tolerance The tolerance for clamping the grid points
+ \return The sampled SDF value
+
+ \deprecated Please use corresponding freestanding function outside of Interpolation scope.
+ */
+ PX_DEPRECATED PX_INLINE PX_CUDA_CALLABLE static PxReal PxSDFSampleImpl(const PxReal* PX_RESTRICT sdf, const PxVec3& localPos, const PxVec3& sdfBoxLower,
+ const PxVec3& sdfBoxHigher, const PxReal sdfDx, const PxReal invSdfDx, const PxU32 dimX, const PxU32 dimY, const PxU32 dimZ, PxReal tolerance)
+ {
+ return ::physx::PxSDFSample(sdf, localPos, sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance);
+ }
+ };
+ #endif // !PX_DOXYGEN // remove due to failing references
+
+ /**
+ \brief Samples the signed distance field (SDF) at a given local position with gradient computation (deprecated).
+
+ \param[in] sdf A pointer to the SDF data
+ \param[in] localPos The local position to sample the SDF
+ \param[in] sdfBoxLower The lower bound of the SDF box
+ \param[in] sdfBoxHigher The upper bound of the SDF box
+ \param[in] sdfDx The spacing between grid points in the SDF
+ \param[in] invSdfDx The inverse of the grid spacing
+ \param[in] dimX The number of grid points along the x-axis
+ \param[in] dimY The number of grid points along the y-axis
+ \param[in] dimZ The number of grid points along the z-axis
+ \param[out] gradient The resulting gradient vector
+ \param[in] tolerance The tolerance for clamping the grid points (default is PX_MAX_F32)
+ \return The sampled SDF value
+ \deprecated Please use PxSDFSample.
+ */
+ PX_DEPRECATED PX_INLINE PX_CUDA_CALLABLE PxReal PxSdfSample(const PxReal* PX_RESTRICT sdf, const PxVec3& localPos, const PxVec3& sdfBoxLower,
+ const PxVec3& sdfBoxHigher, const PxReal sdfDx, const PxReal invSdfDx, const PxU32 dimX, const PxU32 dimY, const PxU32 dimZ, PxVec3& gradient, PxReal tolerance = PX_MAX_F32)
+ {
+ PxReal dist = PxSDFSample(sdf, localPos, sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance);
+
+ if (dist < tolerance)
+ {
+
+ PxVec3 grad;
+ grad.x = PxSDFSample(sdf, localPos + PxVec3(sdfDx, 0.f, 0.f), sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance) -
+ PxSDFSample(sdf, localPos - PxVec3(sdfDx, 0.f, 0.f), sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance);
+ grad.y = PxSDFSample(sdf, localPos + PxVec3(0.f, sdfDx, 0.f), sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance) -
+ PxSDFSample(sdf, localPos - PxVec3(0.f, sdfDx, 0.f), sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance);
+ grad.z = PxSDFSample(sdf, localPos + PxVec3(0.f, 0.f, sdfDx), sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance) -
+ PxSDFSample(sdf, localPos - PxVec3(0.f, 0.f, sdfDx), sdfBoxLower, sdfBoxHigher, sdfDx, invSdfDx, dimX, dimY, dimZ, tolerance);
+
+ gradient = grad;
+
+ }
+
+ return dist;
+ }
#if !PX_DOXYGEN
} // namespace physx
#endif
- /** @} */
#endif