From 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 Mon Sep 17 00:00:00 2001 From: git perforce import user Date: Tue, 25 Oct 2016 12:29:14 -0600 Subject: Initial commit: PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167] --- .../src/intersection/GuIntersectionRayBox.cpp | 449 +++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 PhysX_3.4/Source/GeomUtils/src/intersection/GuIntersectionRayBox.cpp (limited to 'PhysX_3.4/Source/GeomUtils/src/intersection/GuIntersectionRayBox.cpp') diff --git a/PhysX_3.4/Source/GeomUtils/src/intersection/GuIntersectionRayBox.cpp b/PhysX_3.4/Source/GeomUtils/src/intersection/GuIntersectionRayBox.cpp new file mode 100644 index 00000000..44d583f3 --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/intersection/GuIntersectionRayBox.cpp @@ -0,0 +1,449 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#include "foundation/PxVec3.h" +#include "foundation/PxIntrinsics.h" +#include "PsFPU.h" +#include "GuIntersectionRayBox.h" +#include "GuIntersectionRayBoxSIMD.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** +* Computes a ray-AABB intersection. +* Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 +* Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) +* Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) +* +* Hence this version is faster as well as more robust than the original one. +* +* Should work provided: +* 1) the integer representation of 0.0f is 0x00000000 +* 2) the sign bit of the float is the most significant one +* +* Report bugs: p.terdiman@codercorner.com +* +* \param aabb [in] the axis-aligned bounding box +* \param origin [in] ray origin +* \param dir [in] ray direction +* \param coord [out] impact coordinates +* \return true if ray intersects AABB +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define RAYAABB_EPSILON 0.00001f +bool Gu::rayAABBIntersect(const PxVec3& minimum, const PxVec3& maximum, const PxVec3& origin, const PxVec3& _dir, PxVec3& coord) +{ + Ps::IntBool Inside = Ps::IntTrue; + PxVec3 MaxT(-1.0f, -1.0f, -1.0f); + const PxReal* dir = &_dir.x; + const PxU32* idir = reinterpret_cast(dir); + // Find candidate planes. + for(PxU32 i=0;i<3;i++) + { + if(origin[i] < minimum[i]) + { + coord[i] = minimum[i]; + Inside = Ps::IntFalse; + + // Calculate T distances to candidate planes + if(idir[i]) +// if(PX_IR(dir[i])) + MaxT[i] = (minimum[i] - origin[i]) / dir[i]; + } + else if(origin[i] > maximum[i]) + { + coord[i] = maximum[i]; + Inside = Ps::IntFalse; + + // Calculate T distances to candidate planes + if(idir[i]) +// if(PX_IR(dir[i])) + MaxT[i] = (maximum[i] - origin[i]) / dir[i]; + } + } + + // Ray origin inside bounding box + if(Inside) + { + coord = origin; + return true; + } + + // Get largest of the maxT's for final choice of intersection + PxU32 WhichPlane = 0; + if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1; + if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box + const PxU32* tmp = reinterpret_cast(&MaxT[WhichPlane]); + if((*tmp)&PX_SIGN_BITMASK) +// if(PX_IR(MaxT[WhichPlane])&PX_SIGN_BITMASK) + return false; + + for(PxU32 i=0;i<3;i++) + { + if(i!=WhichPlane) + { + coord[i] = origin[i] + MaxT[WhichPlane] * dir[i]; +#ifdef RAYAABB_EPSILON + if(coord[i] < minimum[i] - RAYAABB_EPSILON || coord[i] > maximum[i] + RAYAABB_EPSILON) +#else + if(coord[i] < minimum[i] || coord[i] > maximum[i]) +#endif + return false; + } + } + return true; // ray hits box +} + + + +/** +* Computes a ray-AABB intersection. +* Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 +* Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) +* Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) +* Return of intersected face code and parameter by Adam! Also modified behavior for ray starts inside AABB. 2004 :-p +* +* Hence this version is faster as well as more robust than the original one. +* +* Should work provided: +* 1) the integer representation of 0.0f is 0x00000000 +* 2) the sign bit of the float is the most significant one +* +* Report bugs: p.terdiman@codercorner.com +* +* \param minimum [in] the smaller corner of the bounding box +* \param maximum [in] the larger corner of the bounding box +* \param origin [in] ray origin +* \param _dir [in] ray direction +* \param coord [out] impact coordinates +* \param t [out] t such that coord = origin + dir * t +* \return false if ray does not intersect AABB, or ray origin is inside AABB. Else: + 1 + coordinate index of box axis that was hit + + Note: sign bit that determines if the minimum (0) or maximum (1) of the axis was hit is equal to sign(coord[returnVal-1]). +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +PxU32 Gu::rayAABBIntersect2(const PxVec3& minimum, const PxVec3& maximum, const PxVec3& origin, const PxVec3& _dir, PxVec3& coord, PxReal & t) +{ + Ps::IntBool Inside = Ps::IntTrue; + PxVec3 MaxT(-1.0f, -1.0f, -1.0f); + const PxReal* dir = &_dir.x; + const PxU32* idir = reinterpret_cast(dir); + // Find candidate planes. + for(PxU32 i=0;i<3;i++) + { + if(origin[i] < minimum[i]) + { + coord[i] = minimum[i]; + Inside = Ps::IntFalse; + + // Calculate T distances to candidate planes + if(idir[i]) +// if(PX_IR(dir[i])) + MaxT[i] = (minimum[i] - origin[i]) / dir[i]; + } + else if(origin[i] > maximum[i]) + { + coord[i] = maximum[i]; + Inside = Ps::IntFalse; + + // Calculate T distances to candidate planes + if(idir[i]) +// if(PX_IR(dir[i])) + MaxT[i] = (maximum[i] - origin[i]) / dir[i]; + } + } + + // Ray origin inside bounding box + if(Inside) + { + coord = origin; + t = 0; + return 1; + } + + // Get largest of the maxT's for final choice of intersection + PxU32 WhichPlane = 0; + if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1; + if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box + const PxU32* tmp = reinterpret_cast(&MaxT[WhichPlane]); + if((*tmp)&PX_SIGN_BITMASK) +// if(PX_IR(MaxT[WhichPlane])&PX_SIGN_BITMASK) + return 0; + + for(PxU32 i=0;i<3;i++) + { + if(i!=WhichPlane) + { + coord[i] = origin[i] + MaxT[WhichPlane] * dir[i]; +#ifdef RAYAABB_EPSILON + if(coord[i] < minimum[i] - RAYAABB_EPSILON || coord[i] > maximum[i] + RAYAABB_EPSILON) return 0; +#else + if(coord[i] < minimum[i] || coord[i] > maximum[i]) return 0; +#endif + } + } + t = MaxT[WhichPlane]; + return 1 + WhichPlane; // ray hits box +} + +// Collide ray defined by ray origin (ro) and ray direction (rd) +// with the bounding box. Returns -1 on no collision and the face index +// for first intersection if a collision is found together with +// the distance to the collision points (tnear and tfar) + +// ptchernev: +// Should we use an enum, or should we keep the anonymous ints? +// Should we increment the return code by one (return 0 for non intersection)? + +int Gu::intersectRayAABB(const PxVec3& minimum, const PxVec3& maximum, const PxVec3& ro, const PxVec3& rd, float& tnear, float& tfar) +{ + // Refactor + int ret=-1; + + tnear = -PX_MAX_F32; + tfar = PX_MAX_F32; + // PT: why did we change the initial epsilon value? + #define LOCAL_EPSILON PX_EPS_F32 + //#define LOCAL_EPSILON 0.0001f + + for(unsigned int a=0;a<3;a++) + { + if(rd[a]>-LOCAL_EPSILON && rd[a]maximum[a]) + return -1; + } + else + { + const PxReal OneOverDir = 1.0f / rd[a]; + PxReal t1 = (minimum[a]-ro[a]) * OneOverDir; + PxReal t2 = (maximum[a]-ro[a]) * OneOverDir; + + unsigned int b = a; + if(t1>t2) + { + PxReal t=t1; + t1=t2; + t2=t; + b += 3; + } + + if(t1>tnear) + { + tnear = t1; + ret = int(b); + } + if(t2tfar || tfartfar || tfar-LOCAL_EPSILON && rd.xmaximum.x) + return -1; + if(physx::intrinsics::abs(rd.y)-LOCAL_EPSILON && rd.ymaximum.y) + return -1; + if(physx::intrinsics::abs(rd.z)-LOCAL_EPSILON && rd.zmaximum.z) + return -1; + + PxReal t1x = (minimum.x - ro.x) * oneOverDir.x; + PxReal t2x = (maximum.x - ro.x) * oneOverDir.x; + PxReal t1y = (minimum.y - ro.y) * oneOverDir.y; + PxReal t2y = (maximum.y - ro.y) * oneOverDir.y; + PxReal t1z = (minimum.z - ro.z) * oneOverDir.z; + PxReal t2z = (maximum.z - ro.z) * oneOverDir.z; + + int bx; + int by; + int bz; + + if(t1x>t2x) + { + PxReal t=t1x; t1x=t2x; t2x=t; + bx = 3; + } + else + { + bx = 0; + } + + if(t1y>t2y) + { + PxReal t=t1y; t1y=t2y; t2y=t; + by = 4; + } + else + { + by = 1; + } + + if(t1z>t2z) + { + PxReal t=t1z; t1z=t2z; t2z=t; + bz = 5; + } + else + { + bz = 2; + } + + int ret; +// if(t1x>tnear) // PT: no need to test for the first value + { + tnear = t1x; + ret = bx; + } +// tfar = PxMin(tfar, t2x); + tfar = t2x; // PT: no need to test for the first value + + if(t1y>tnear) + { + tnear = t1y; + ret = by; + } + tfar = PxMin(tfar, t2y); + + if(t1z>tnear) + { + tnear = t1z; + ret = bz; + } + tfar = PxMin(tfar, t2z); + + if(tnear>tfar || tfar= GU_MIN_AABB_EXTENT*0.5f); + PX_ASSERT(maximum.y-minimum.y >= GU_MIN_AABB_EXTENT*0.5f); + PX_ASSERT(maximum.z-minimum.z >= GU_MIN_AABB_EXTENT*0.5f); + // not using vector math due to vector to integer pipeline penalties. TODO: verify that it's indeed faster + namespace i = physx::intrinsics; + + // P+tD=a; t=(a-P)/D + // t=(a - p.x)*1/d.x = a/d.x +(- p.x/d.x) + const PxF32 dEpsilon = 1e-9f; + // using recipFast fails height field unit tests case where a ray cast from y=10000 to 0 gets clipped to 0.27 in y + PxF32 invDx = i::recip(i::selectMax(i::abs(rd.x), dEpsilon) * i::sign(rd.x)); +#ifdef RAYAABB_EPSILON + PxF32 tx0 = (minimum.x - RAYAABB_EPSILON - ro.x) * invDx; + PxF32 tx1 = (maximum.x + RAYAABB_EPSILON - ro.x) * invDx; +#else + PxF32 tx0 = (minimum.x - ro.x) * invDx; + PxF32 tx1 = (maximum.x - ro.x) * invDx; +#endif + PxF32 txMin = i::selectMin(tx0, tx1); + PxF32 txMax = i::selectMax(tx0, tx1); + + PxF32 invDy = i::recip(i::selectMax(i::abs(rd.y), dEpsilon) * i::sign(rd.y)); +#ifdef RAYAABB_EPSILON + PxF32 ty0 = (minimum.y - RAYAABB_EPSILON - ro.y) * invDy; + PxF32 ty1 = (maximum.y + RAYAABB_EPSILON - ro.y) * invDy; +#else + PxF32 ty0 = (minimum.y - ro.y) * invDy; + PxF32 ty1 = (maximum.y - ro.y) * invDy; +#endif + PxF32 tyMin = i::selectMin(ty0, ty1); + PxF32 tyMax = i::selectMax(ty0, ty1); + + PxF32 invDz = i::recip(i::selectMax(i::abs(rd.z), dEpsilon) * i::sign(rd.z)); +#ifdef RAYAABB_EPSILON + PxF32 tz0 = (minimum.z - RAYAABB_EPSILON - ro.z) * invDz; + PxF32 tz1 = (maximum.z + RAYAABB_EPSILON - ro.z) * invDz; +#else + PxF32 tz0 = (minimum.z - ro.z) * invDz; + PxF32 tz1 = (maximum.z - ro.z) * invDz; +#endif + PxF32 tzMin = i::selectMin(tz0, tz1); + PxF32 tzMax = i::selectMax(tz0, tz1); + + PxF32 maxOfNears = i::selectMax(i::selectMax(txMin, tyMin), tzMin); + PxF32 minOfFars = i::selectMin(i::selectMin(txMax, tyMax), tzMax); + + tnear = i::selectMax(maxOfNears, 0.0f); + tfar = i::selectMin(minOfFars, maxDist); + + return (tnear