Files
XCEngine/engine/third_party/physx/source/gpunarrowphase/src/CUDA/particleCollision.cuh

225 lines
8.6 KiB
Plaintext

// 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-2025 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 __PARTICLE_COLLISION_CUH__
#define __PARTICLE_COLLISION_CUH__
#include "foundation/PxVec3.h"
#include "foundation/PxTransform.h"
#include "sphereCollision.cuh"
#include "deformableCollision.cuh"
#include "GuConvexSupport.h"
/**
* Retuns distance and normal information for a particle-box contact.
* If maxDist < PX_MAX_F32, then no result is provided if the distance is larger than maxDist.
*/
__device__ __forceinline__ static
bool contactPointBox(PxVec3& normal, PxReal& dist,
const PxVec3& pointPos, const PxTransform& boxToWorld, const PxVec3& halfBoxExtents, const PxReal maxDist)
{
PxVec3 relPointPos = boxToWorld.transformInv(pointPos);
const PxVec3 closestPos(
PxClamp(relPointPos.x, -halfBoxExtents.x, halfBoxExtents.x),
PxClamp(relPointPos.y, -halfBoxExtents.y, halfBoxExtents.y),
PxClamp(relPointPos.z, -halfBoxExtents.z, halfBoxExtents.z)
);
if (maxDist < PX_MAX_F32)
{
PxReal maxDistSq = maxDist*maxDist;
PxReal distSq = (relPointPos - closestPos).magnitudeSquared();
if (distSq > maxDistSq)
{
return false;
}
}
//check whether the point is inside the aabb
const bool bX = halfBoxExtents.x >= PxAbs(relPointPos.x);
const bool bY = halfBoxExtents.y >= PxAbs(relPointPos.y);
const bool bZ = halfBoxExtents.z >= PxAbs(relPointPos.z);
const bool isInside = bX && bY && bZ;
if (isInside)
{
//dist from embedded point to box surface along 3 dimensions.
const PxVec3 distToSurface = halfBoxExtents - closestPos.abs();
//assume z is the smallest element of the distToSurface
normal = closestPos.z >= 0.f ? PxVec3(0.f, 0.f, 1.f) : PxVec3(0.f, 0.f, -1.f);
dist = -distToSurface.z;
//find smallest element of distToSurface
if (distToSurface.x <= distToSurface.y && distToSurface.x <= distToSurface.z)
{
normal = closestPos.x >= 0.f ? PxVec3(1.f, 0.f, 0.f) : PxVec3(-1.0f, 0.f, 0.f);
dist = -distToSurface.x;
}
else if (distToSurface.y <= distToSurface.z)
{
normal = closestPos.y >= 0.f ? PxVec3(0.f, 1.f, 0.f) : PxVec3(0.f, -1.f, 0.f);
dist = -distToSurface.y;
}
}
else
{
normal = relPointPos - closestPos;
dist = normal.normalizeFast();
}
normal = boxToWorld.rotate(normal);
return true;
}
/**
* Retuns distance and normal information for a particle-sphere contact.
* If maxDist < PX_MAX_F32, then no result is provided if the distance is larger than maxDist.
*/
__device__ __forceinline__ static
bool contactPointSphere(PxVec3& normal, PxReal& dist,
const PxVec3& pointPos, const PxVec3& spherePos, const PxReal sphereRadius, const PxReal maxDist)
{
PxVec3 relPointPos = pointPos - spherePos;
const PxReal distCenterSq = relPointPos.magnitudeSquared();
if (maxDist < PX_MAX_F32)
{
const PxReal maxDistCenter = maxDist + sphereRadius;
const PxReal maxDistCenterSq = maxDistCenter*maxDistCenter;
if (distCenterSq > maxDistCenterSq)
{
return false;
}
}
const PxReal distCenter = PxSqrt(distCenterSq);
normal = (distCenter > PX_EPS_REAL) ? relPointPos * (1.0f / distCenter) : PxVec3(1.0f, 0.0f, 0.0f);
dist = distCenter - sphereRadius;
return true;
}
/**
* Retuns distance and normal information for a point-capsule contact.
* If maxDist < PX_MAX_F32, then no result is provided if the distance is larger than maxDist.
*/
__device__ __forceinline__ static
bool contactPointCapsule(PxVec3& normal, PxReal& dist,
const PxVec3& pointPos, const PxVec3& capsulePos, const PxVec3& capsuleDir, const PxReal capsuleRadius, const PxReal capsuleHalfHeight, const PxReal maxDist)
{
const PxVec3 capsuleAxisVec = capsuleDir * capsuleHalfHeight;
const PxVec3 relPointPos = pointPos - capsulePos;
PxReal t;
const PxReal distSegmentSq = distancePointSegmentSquared(-capsuleAxisVec, capsuleAxisVec, relPointPos, t);
if (maxDist < PX_MAX_F32)
{
const PxReal maxDistSegment = maxDist + capsuleRadius;
const PxReal maxDistSegmentSq = maxDistSegment * maxDistSegment;
if (distSegmentSq > maxDistSegmentSq)
{
return false;
}
}
const PxVec3 distSegmentVec = relPointPos - capsuleAxisVec * (2.0f * t - 1.0f);
const PxReal distSegment = PxSqrt(distSegmentSq);
normal = (distSegment > PX_EPS_REAL) ? (distSegmentVec * (1.0f / distSegment)) : PxVec3(1.0f, 0.0f, 0.0f);
dist = distSegment - capsuleRadius;
return true;
}
/**
* Combined speculative particle triangle cd. Returns normal and distance.
* If CCD is enabled two tests are performed. The first one decides if the triangle
* is overlapping with the contact volume (sphere), which is typically located at a
* predicted position of the particle, covering it's whole predicted path. The second
* test then establishes the correct distance and normal with respect to the actual particle
* position.
* If CCD is disabled, particlePos == cVolumePos, and cVolumeRadius is the standard contact
* distance.
*/
__device__ __forceinline__ static
bool particleTriangleTest(PxVec3& normal, PxReal& distance,
const PxVec3& particlePos, const PxVec3& cVolumePos, const PxReal cVolumeRadius,
const PxVec3& triV0, const PxVec3& triV1, const PxVec3& triV2, const bool enableCCD)
{
const PxVec3 triNormal = ((triV1 - triV0).cross(triV2 - triV0)).getNormalized();
const PxReal cVolumeRadiusSq = cVolumeRadius * cVolumeRadius;
//contact volume test
const PxReal cVolumePosPlaneDist = (cVolumePos - triV0).dot(triNormal);
PxVec3 closestPos;
if (cVolumePosPlaneDist < cVolumeRadius)
{
PxReal distSq = distancePointTriangleSquared(cVolumePos, triV0, triV1, triV2, closestPos);
if (distSq <= cVolumeRadiusSq)
{
//intersection test
//back face culling with respect to current particle position
const PxReal particlePosPlaneDist = (particlePos - triV0).dot(triNormal);
if (particlePosPlaneDist > 0.0f)
{
if (enableCCD)
{
//in case of CCD we replace the closest and distance from the contact volume with
//the corresponding from the current particle position
distSq = distancePointTriangleSquared(particlePos, triV0, triV1, triV2, closestPos);
}
//assumes particlePos == cVolumePos if enableCCD == false.
PxVec3 distVec = particlePos - closestPos;
normal = (distSq > 0.0f) ? distVec*PxRecipSqrt(distSq) : triNormal;
distance = PxSqrt(distSq);
return true;
}
}
}
return false;
}
/**
* Retuns distance and normal information for a particle-convexCore contact.
* If maxDist < PX_MAX_F32, then no result is provided if the distance is larger than maxDist.
*/
__device__ __forceinline__ static
bool particleConvexCore(PxVec3& normal, PxReal& dist, const PxVec3& particlePos,
const Gu::ConvexShape& convex, const PxReal maxDist)
{
Gu::ConvexShape particle;
particle.coreType = Gu::ConvexCore::Type::ePOINT;
particle.pose = PxTransform(particlePos);
particle.margin = 0;
PxVec3 point0, point1;
dist = Gu::RefGjkEpa::computeGjkDistance(particle, convex, particle.pose, convex.pose,
convex.margin + particle.margin + maxDist, point0, point1, normal);
if (dist < FLT_EPSILON)
dist = Gu::RefGjkEpa::computeEpaDepth(particle, convex, particle.pose, convex.pose,
point0, point1, normal);
if (dist > maxDist)
return false;
return true;
}
#endif // __PARTICLE_COLLISION_CUH__