Files
XCEngine/engine/third_party/physx/source/geomutils/src/contact/GuContactBoxBox.cpp

696 lines
23 KiB
C++

// 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.
#include "geomutils/PxContactBuffer.h"
#include "GuContactMethodImpl.h"
#include "CmMatrix34.h"
#include "foundation/PxUtilities.h"
using namespace physx;
using namespace Gu;
using namespace Cm;
#define MAX_NB_CTCS 8 + 12*5 + 6*4
#define ABS_GREATER(x, y) (PxAbs(x) > (y))
#define ABS_SMALLER_EQUAL(x, y) (PxAbs(x) <= (y))
//#define AIR(x) ((PxU32&)(x)&SIGN_BITMASK)
//#define ABS_GREATER(x, y) (AIR(x) > IR(y))
//#define ABS_SMALLER_EQUAL(x, y) (AIR(x) <= IR(y))
#if PX_X86 && !PX_OSX
// Some float optimizations ported over from novodex.
//returns non zero if the value is negative.
#define PXC_IS_NEGATIVE(x) (((PxU32&)(x)) & 0x80000000)
#else
//On most platforms using the integer rep is worse(produces LHSs) since the CPU has more registers.
//returns non zero if the value is negative.
#define PXC_IS_NEGATIVE(x) ((x) < 0.0f)
#endif
enum
{
AXIS_A0, AXIS_A1, AXIS_A2,
AXIS_B0, AXIS_B1, AXIS_B2
};
struct VertexInfo
{
PxVec3 pos;
bool penetrate;
bool area;
};
/*static PxI32 doBoxBoxContactGeneration(PxVec3 ctcPts[MAX_NB_CTCS], PxReal depths[MAX_NB_CTCS], PxVec3* ctcNrm,
const PxVec3& extents0, const PxVec3& extents1,
PxU32& collisionData,
const PxMat34& transform0, const PxMat34& transform1, PxReal contactDistance);*/
static PxI32 doBoxBoxContactGeneration(PxContactBuffer& contactBuffer,
const PxVec3& extents0, const PxVec3& extents1,
PxU32& collisionData,
const PxMat34& transform0, const PxMat34& transform1, PxReal contactDistance);
bool Gu::contactBoxBox(GU_CONTACT_METHOD_ARGS)
{
PX_UNUSED(renderOutput);
// Get actual shape data
const PxBoxGeometry& shapeBox0 = checkedCast<PxBoxGeometry>(shape0);
const PxBoxGeometry& shapeBox1 = checkedCast<PxBoxGeometry>(shape1);
PxU32 pd = PxU32(cache.mPairData);
PxI32 Nb = doBoxBoxContactGeneration(contactBuffer,
shapeBox0.halfExtents, shapeBox1.halfExtents,
pd,
Matrix34FromTransform(transform0), Matrix34FromTransform(transform1),
params.mContactDistance);
cache.mPairData = PxTo8(pd);
if(!Nb)
{
cache.mPairData = 0; // Mark as separated for temporal coherence
return false; // WARNING: the contact stream code below used to output stuff even for 0 contacts (!). Now we just return here.
}
return true;
}
// face => 4 vertices of a face of the cube (i.e. a quad)
static PX_FORCE_INLINE PxReal IsInYZ(const PxReal y, const PxReal z, const VertexInfo** PX_RESTRICT face)
{
// Warning, indices have been remapped. We're now actually like this:
//
// 3+------+2
// | | |
// | *--|
// | (y,z)|
// 0+------+1
PxReal PreviousY = face[3]->pos.y;
PxReal PreviousZ = face[3]->pos.z;
// Loop through quad vertices
for(PxI32 i=0; i<4; i++)
{
const PxReal CurrentY = face[i]->pos.y;
const PxReal CurrentZ = face[i]->pos.z;
// |CurrentY - PreviousY y - PreviousY|
// |CurrentZ - PreviousZ z - PreviousZ|
// => similar to backface culling, check each one of the 4 triangles are consistent, in which case
// the point is within the parallelogram.
if((CurrentY - PreviousY)*(z - PreviousZ) - (CurrentZ - PreviousZ)*(y - PreviousY) >= 0.0f) return -1.0f;
PreviousY = CurrentY;
PreviousZ = CurrentZ;
}
PxReal x = face[0]->pos.x;
{
const PxReal ay = y - face[0]->pos.y;
const PxReal az = z - face[0]->pos.z;
PxVec3 b = face[1]->pos - face[0]->pos; // ### could be precomputed ?
x += b.x * (ay*b.y + az*b.z) / b.magnitudeSquared(); // ### could be precomputed ?
b = face[3]->pos - face[0]->pos; // ### could be precomputed ?
x += b.x * (ay*b.y + az*b.z) / b.magnitudeSquared(); // ### could be precomputed ?
}
return x;
}
// Test with respect to the quad defined by (0,-y1,-z1) and (0,y1,z1)
// +------+ y1 y
// | | |
// | * | |
// | | |
// +------+ -y1 *-----z
static PxI32 generateContacts(//PxVec3 ctcPts[], PxReal depths[],
PxContactBuffer& contactBuffer, const PxVec3& contactNormal,
PxReal y1, PxReal z1, const PxVec3& box2,
const PxMat34& transform0, const PxMat34& transform1, PxReal contactDistance)
{
// PxI32 NbContacts=0;
contactBuffer.reset();
y1 += contactDistance;
z1 += contactDistance;
const PxMat34 trans1to0 = transform0.getInverseRT() * transform1;
VertexInfo vtx[8]; // The 8 cube vertices
// PxI32 i;
// 6+------+7
// /| /|
// / | / |
// / 4+---/--+5
// 2+------+3 / y z
// | / | / | /
// |/ |/ |/
// 0+------+1 *---x
{
const PxVec3 ex = trans1to0.m.column0 * box2.x;
const PxVec3 ey = trans1to0.m.column1 * box2.y;
const PxVec3 ez = trans1to0.m.column2 * box2.z;
/*
vtx[0].pos = mat.pos - ex - ey - ez;
vtx[1].pos = mat.pos + ex - ey - ez;
vtx[2].pos = mat.pos - ex + ey - ez;
vtx[3].pos = mat.pos + ex + ey - ez;
vtx[4].pos = mat.pos - ex - ey + ez;
vtx[5].pos = mat.pos + ex - ey + ez;
vtx[6].pos = mat.pos - ex + ey + ez;
vtx[7].pos = mat.pos + ex + ey + ez;
*/
// 12 vector ops = 12*3 = 36 FPU ops
vtx[0].pos = vtx[2].pos = vtx[4].pos = vtx[6].pos = trans1to0.p - ex;
vtx[1].pos = vtx[3].pos = vtx[5].pos = vtx[7].pos = trans1to0.p + ex;
PxVec3 e = ey+ez;
vtx[0].pos -= e;
vtx[1].pos -= e;
vtx[6].pos += e;
vtx[7].pos += e;
e = ey-ez;
vtx[2].pos += e;
vtx[3].pos += e;
vtx[4].pos -= e;
vtx[5].pos -= e;
}
// Create vertex info for 8 vertices
for(PxU32 i=0; i<8; i++)
{
// Vertex suivant
VertexInfo& p = vtx[i];
// test the point with respect to the x = 0 plane
// if(p.pos.x < 0)
if(p.pos.x < -contactDistance) //if(PXC_IS_NEGATIVE(p.pos.x))
{
p.area = false;
p.penetrate = false;
continue;
}
{
// we penetrated the quad plane
p.penetrate = true;
// test to see if we are in the quad
// PxAbs => thus we test Y with respect to -Y1 and +Y1 (same for Z)
// if(PxAbs(p->pos.y) <= y1 && PxAbs(p->pos.z) <= z1)
if(ABS_SMALLER_EQUAL(p.pos.y, y1) && ABS_SMALLER_EQUAL(p.pos.z, z1))
{
// the point is inside the quad
p.area=true;
// Since we are testing with respect to x = 0, the penetration is directly the x coordinate.
// depths[NbContacts] = p.pos.x;
// We take the vertex as the impact point
// ctcPts[NbContacts++] = p.pos;
contactBuffer.contact(p.pos, contactNormal, -p.pos.x);
}
else
{
p.area=false;
}
}
}
// Teste 12 edges on the quad
static const PxI32 indices[]={ 0,1, 1,3, 3,2, 2,0, 4,5, 5,7, 7,6, 6,4, 0,4, 1,5, 2,6, 3,7, };
const PxI32* runningLine = indices;
const PxI32* endLine = runningLine+24;
while(runningLine!=endLine)
{
// The two vertices of the current edge
const VertexInfo* p1 = &vtx[*runningLine++];
const VertexInfo* p2 = &vtx[*runningLine++];
// Penetrate|Area|Penetrate|Area => 16 cases
// We only take the edges that at least penetrated the quad's plane into account.
if(p1->penetrate || p2->penetrate)
// if(p1->penetrate + p2->penetrate) // One branch only
{
// If at least one of the two vertices is not in the quad...
if(!p1->area || !p2->area)
// if(!p1->area + !p2->area) // One branch only
{
// Test y
if(p1->pos.y > p2->pos.y) { const VertexInfo* tmp=p1; p1=p2; p2=tmp; }
// Impact on the +Y1 edge of the quad
if(p1->pos.y < +y1 && p2->pos.y >= +y1)
// => a point under Y1, the other above
{
// Case 1
PxReal a = (+y1 - p1->pos.y)/(p2->pos.y - p1->pos.y);
PxReal z = p1->pos.z + (p2->pos.z - p1->pos.z)*a;
if(PxAbs(z) <= z1)
{
PxReal x = p1->pos.x + (p2->pos.x - p1->pos.x)*a;
if(x+contactDistance>=0.0f)
{
// depths[NbContacts] = x;
// ctcPts[NbContacts++] = PxVec3(x, y1, z);
contactBuffer.contact(PxVec3(x, y1, z), contactNormal, -x);
}
}
}
// Impact on the edge -Y1 of the quad
if(p1->pos.y < -y1 && p2->pos.y >= -y1)
{
// Case 2
PxReal a = (-y1 - p1->pos.y)/(p2->pos.y - p1->pos.y);
PxReal z = p1->pos.z + (p2->pos.z - p1->pos.z)*a;
if(PxAbs(z) <= z1)
{
PxReal x = p1->pos.x + (p2->pos.x - p1->pos.x)*a;
if(x+contactDistance>=0.0f)
{
// depths[NbContacts] = x;
// ctcPts[NbContacts++] = PxVec3(x, -y1, z);
contactBuffer.contact(PxVec3(x, -y1, z), contactNormal, -x);
}
}
}
// Test z
if(p1->pos.z > p2->pos.z) { const VertexInfo* tmp=p1; p1=p2; p2=tmp; }
// Impact on the edge +Z1 of the quad
if(p1->pos.z < +z1 && p2->pos.z >= +z1)
{
// Case 3
PxReal a = (+z1 - p1->pos.z)/(p2->pos.z - p1->pos.z);
PxReal y = p1->pos.y + (p2->pos.y - p1->pos.y)*a;
if(PxAbs(y) <= y1)
{
PxReal x = p1->pos.x + (p2->pos.x - p1->pos.x)*a;
if(x+contactDistance>=0.0f)
{
// depths[NbContacts] = x;
// ctcPts[NbContacts++] = PxVec3(x, y, z1);
contactBuffer.contact(PxVec3(x, y, z1), contactNormal, -x);
}
}
}
// Impact on the edge -Z1 of the quad
if(p1->pos.z < -z1 && p2->pos.z >= -z1)
{
// Case 4
PxReal a = (-z1 - p1->pos.z)/(p2->pos.z - p1->pos.z);
PxReal y = p1->pos.y + (p2->pos.y - p1->pos.y)*a;
if(PxAbs(y) <= y1)
{
PxReal x = p1->pos.x + (p2->pos.x - p1->pos.x)*a;
if(x+contactDistance>=0.0f)
{
// depths[NbContacts] = x;
// ctcPts[NbContacts++] = PxVec3(x, y, -z1);
contactBuffer.contact(PxVec3(x, y, -z1), contactNormal, -x);
}
}
}
}
// The case where one point penetrates the plane, and the other is not in the quad.
if((!p1->penetrate && !p2->area) || (!p2->penetrate && !p1->area))
{
// Case 5
PxReal a = (-p1->pos.x)/(p2->pos.x - p1->pos.x);
PxReal y = p1->pos.y + (p2->pos.y - p1->pos.y)*a;
if(PxAbs(y) <= y1)
{
PxReal z = p1->pos.z + (p2->pos.z - p1->pos.z)*a;
if(PxAbs(z) <= z1)
{
// depths[NbContacts] = 0;
// ctcPts[NbContacts++] = PxVec3(0, y, z);
contactBuffer.contact(PxVec3(0, y, z), contactNormal, 0);
}
}
}
}
}
{
// 6 quads => 6 faces of the cube
static const PxI32 face[][4]={ {0,1,3,2}, {1,5,7,3}, {5,4,6,7}, {4,0,2,6}, {2,3,7,6}, {0,4,5,1} };
PxI32 addflg=0;
for(PxU32 i=0; i<6 && addflg!=0x0f; i++)
{
const PxI32* p = face[i];
const VertexInfo* q[4];
if((q[0]=&vtx[p[0]])->penetrate && (q[1]=&vtx[p[1]])->penetrate && (q[2]=&vtx[p[2]])->penetrate && (q[3]=&vtx[p[3]])->penetrate)
{
if(!q[0]->area || !q[1]->area || !q[2]->area || !q[3]->area)
{
if(!(addflg&1)) { PxReal x = IsInYZ(-y1, -z1, q); if(x>=0.0f) { addflg|=1; contactBuffer.contact(PxVec3(x, -y1, -z1), contactNormal, -x); /*depths[NbContacts]=x; ctcPts[NbContacts++] = PxVec3(x, -y1, -z1);*/ } }
if(!(addflg&2)) { PxReal x = IsInYZ(+y1, -z1, q); if(x>=0.0f) { addflg|=2; contactBuffer.contact(PxVec3(x, +y1, -z1), contactNormal, -x); /*depths[NbContacts]=x; ctcPts[NbContacts++] = PxVec3(x, +y1, -z1);*/ } }
if(!(addflg&4)) { PxReal x = IsInYZ(-y1, +z1, q); if(x>=0.0f) { addflg|=4; contactBuffer.contact(PxVec3(x, -y1, +z1), contactNormal, -x); /*depths[NbContacts]=x; ctcPts[NbContacts++] = PxVec3(x, -y1, +z1);*/ } }
if(!(addflg&8)) { PxReal x = IsInYZ(+y1, +z1, q); if(x>=0.0f) { addflg|=8; contactBuffer.contact(PxVec3(x, +y1, +z1), contactNormal, -x); /*depths[NbContacts]=x; ctcPts[NbContacts++] = PxVec3(x, +y1, +z1);*/ } }
}
}
}
}
// for(i=0; i<NbContacts; i++)
for(PxU32 i=0; i<contactBuffer.count; i++)
// ctcPts[i] = transform0.transform(ctcPts[i]); // local to world
contactBuffer.contacts[i].point = transform0.transform(contactBuffer.contacts[i].point); // local to world
//PX_ASSERT(NbContacts); //if this did not make contacts then something went wrong in theory, but even the old code without distances had this flaw!
// return NbContacts;
return PxI32(contactBuffer.count);
}
//static PxI32 doBoxBoxContactGeneration(PxVec3 ctcPts[MAX_NB_CTCS], PxReal depths[MAX_NB_CTCS], PxVec3* ctcNrm,
static PxI32 doBoxBoxContactGeneration(PxContactBuffer& contactBuffer,
const PxVec3& extents0, const PxVec3& extents1,
PxU32& collisionData,
const PxMat34& transform0, const PxMat34& transform1, PxReal contactDistance)
{
PxReal aafC[3][3]; // matrix C = A^T B, c_{ij} = Dot(A_i,B_j)
PxReal aafAbsC[3][3]; // |c_{ij}|
PxReal afAD[3]; // Dot(A_i,D)
PxReal d1[6];
PxReal overlap[6];
PxVec3 kD = transform1.p - transform0.p;
const PxVec3& axis00 = transform0.m.column0;
const PxVec3& axis01 = transform0.m.column1;
const PxVec3& axis02 = transform0.m.column2;
const PxVec3& axis10 = transform1.m.column0;
const PxVec3& axis11 = transform1.m.column1;
const PxVec3& axis12 = transform1.m.column2;
// Perform Class I tests
aafC[0][0] = axis00.dot(axis10);
aafC[0][1] = axis00.dot(axis11);
aafC[0][2] = axis00.dot(axis12);
afAD[0] = axis00.dot(kD);
aafAbsC[0][0] = 1e-6f + PxAbs(aafC[0][0]);
aafAbsC[0][1] = 1e-6f + PxAbs(aafC[0][1]);
aafAbsC[0][2] = 1e-6f + PxAbs(aafC[0][2]);
d1[AXIS_A0] = afAD[0];
PxReal d0 = extents0.x + extents1.x*aafAbsC[0][0] + extents1.y*aafAbsC[0][1] + extents1.z*aafAbsC[0][2];
overlap[AXIS_A0] = d0 - PxAbs(d1[AXIS_A0]) + contactDistance;
if(PXC_IS_NEGATIVE(overlap[AXIS_A0])) return 0;
aafC[1][0] = axis01.dot(axis10);
aafC[1][1] = axis01.dot(axis11);
aafC[1][2] = axis01.dot(axis12);
afAD[1] = axis01.dot(kD);
aafAbsC[1][0] = 1e-6f + PxAbs(aafC[1][0]);
aafAbsC[1][1] = 1e-6f + PxAbs(aafC[1][1]);
aafAbsC[1][2] = 1e-6f + PxAbs(aafC[1][2]);
d1[AXIS_A1] = afAD[1];
d0 = extents0.y + extents1.x*aafAbsC[1][0] + extents1.y*aafAbsC[1][1] + extents1.z*aafAbsC[1][2];
overlap[AXIS_A1] = d0 - PxAbs(d1[AXIS_A1]) + contactDistance;
if(PXC_IS_NEGATIVE(overlap[AXIS_A1])) return 0;
aafC[2][0] = axis02.dot(axis10);
aafC[2][1] = axis02.dot(axis11);
aafC[2][2] = axis02.dot(axis12);
afAD[2] = axis02.dot(kD);
aafAbsC[2][0] = 1e-6f + PxAbs(aafC[2][0]);
aafAbsC[2][1] = 1e-6f + PxAbs(aafC[2][1]);
aafAbsC[2][2] = 1e-6f + PxAbs(aafC[2][2]);
d1[AXIS_A2] = afAD[2];
d0 = extents0.z + extents1.x*aafAbsC[2][0] + extents1.y*aafAbsC[2][1] + extents1.z*aafAbsC[2][2];
overlap[AXIS_A2] = d0 - PxAbs(d1[AXIS_A2]) + contactDistance;
if(PXC_IS_NEGATIVE(overlap[AXIS_A2])) return 0;
// Perform Class II tests
d1[AXIS_B0] = axis10.dot(kD);
d0 = extents1.x + extents0.x*aafAbsC[0][0] + extents0.y*aafAbsC[1][0] + extents0.z*aafAbsC[2][0];
overlap[AXIS_B0] = d0 - PxAbs(d1[AXIS_B0]) + contactDistance;
if(PXC_IS_NEGATIVE(overlap[AXIS_B0])) return 0;
d1[AXIS_B1] = axis11.dot(kD);
d0 = extents1.y + extents0.x*aafAbsC[0][1] + extents0.y*aafAbsC[1][1] + extents0.z*aafAbsC[2][1];
overlap[AXIS_B1] = d0 - PxAbs(d1[AXIS_B1]) + contactDistance;
if(PXC_IS_NEGATIVE(overlap[AXIS_B1])) return 0;
d1[AXIS_B2] = axis12.dot(kD);
d0 = extents1.z + extents0.x*aafAbsC[0][2] + extents0.y*aafAbsC[1][2] + extents0.z*aafAbsC[2][2];
overlap[AXIS_B2] = d0 - PxAbs(d1[AXIS_B2]) + contactDistance;
if(PXC_IS_NEGATIVE(overlap[AXIS_B2])) return 0;
// Perform Class III tests - we don't need to store distances for those ones.
// We only test those axes when objects are likely to be separated, i.e. when they where previously non-colliding. For stacks, we'll have
// to do full contact generation anyway, and those tests are useless - so we skip them. This is similar to what I did in Opcode.
if(!collisionData) // separated or first run
{
PxReal d = afAD[2]*aafC[1][0] - afAD[1]*aafC[2][0];
d0 = contactDistance + extents0.y*aafAbsC[2][0] + extents0.z*aafAbsC[1][0] + extents1.y*aafAbsC[0][2] + extents1.z*aafAbsC[0][1];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[2]*aafC[1][1] - afAD[1]*aafC[2][1];
d0 = contactDistance + extents0.y*aafAbsC[2][1] + extents0.z*aafAbsC[1][1] + extents1.x*aafAbsC[0][2] + extents1.z*aafAbsC[0][0];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[2]*aafC[1][2] - afAD[1]*aafC[2][2];
d0 = contactDistance + extents0.y*aafAbsC[2][2] + extents0.z*aafAbsC[1][2] + extents1.x*aafAbsC[0][1] + extents1.y*aafAbsC[0][0];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[0]*aafC[2][0] - afAD[2]*aafC[0][0];
d0 = contactDistance + extents0.x*aafAbsC[2][0] + extents0.z*aafAbsC[0][0] + extents1.y*aafAbsC[1][2] + extents1.z*aafAbsC[1][1];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[0]*aafC[2][1] - afAD[2]*aafC[0][1];
d0 = contactDistance + extents0.x*aafAbsC[2][1] + extents0.z*aafAbsC[0][1] + extents1.x*aafAbsC[1][2] + extents1.z*aafAbsC[1][0];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[0]*aafC[2][2] - afAD[2]*aafC[0][2];
d0 = contactDistance + extents0.x*aafAbsC[2][2] + extents0.z*aafAbsC[0][2] + extents1.x*aafAbsC[1][1] + extents1.y*aafAbsC[1][0];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[1]*aafC[0][0] - afAD[0]*aafC[1][0];
d0 = contactDistance + extents0.x*aafAbsC[1][0] + extents0.y*aafAbsC[0][0] + extents1.y*aafAbsC[2][2] + extents1.z*aafAbsC[2][1];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[1]*aafC[0][1] - afAD[0]*aafC[1][1];
d0 = contactDistance + extents0.x*aafAbsC[1][1] + extents0.y*aafAbsC[0][1] + extents1.x*aafAbsC[2][2] + extents1.z*aafAbsC[2][0];
if(ABS_GREATER(d, d0)) return 0;
d = afAD[1]*aafC[0][2] - afAD[0]*aafC[1][2];
d0 = contactDistance + extents0.x*aafAbsC[1][2] + extents0.y*aafAbsC[0][2] + extents1.x*aafAbsC[2][1] + extents1.y*aafAbsC[2][0];
if(ABS_GREATER(d, d0)) return 0;
}
/* djs - tempUserData can be zero when it gets here
- maybe if there was no previous axis?
- which causes stack corruption, and thence a crash, in .NET
PT: right! At first tempUserData wasn't ever supposed to be zero, but then I used that
value to mark separation of boxes, and forgot to update the code below. Now I think
the test is redundant with the one performed above, and the line could eventually
be merged in the previous block. I'll do that later when removing all the #defines.
*/
// NB: the "16" here has nothing to do with MAX_NB_CTCS. Don't touch.
if(collisionData) // if initialized & not previously separated
overlap[collisionData-1] *= 0.999f; // Favorise previous axis .999 is too little.
PxReal minimum = PX_MAX_REAL;
PxI32 minIndex = 0;
for(PxU32 i=AXIS_A0; i<6; i++)
{
PxReal d = overlap[i];
if(d>=0.0f && d<minimum) { minimum=d; minIndex=PxI32(i); } // >=0 !! otherwise bug at sep = 0
}
collisionData = PxU32(minIndex + 1); // Leave "0" for separation
#if PX_X86
const PxU32 sign = PXC_IS_NEGATIVE(d1[minIndex]);
#else
const PxU32 sign = PxU32(PXC_IS_NEGATIVE(d1[minIndex]));
#endif
PxMat34 trs;
PxVec3 ctcNrm;
switch(minIndex)
{
default:
return 0;
case AXIS_A0:
// *ctcNrm = axis00;
if(sign)
{
ctcNrm = axis00;
trs.m = transform0.m;
trs.p = transform0.p - extents0.x*axis00;
}
else
{
// *ctcNrm = -*ctcNrm;
ctcNrm = -axis00;
trs.m.column0 = -axis00;
trs.m.column1 = -axis01;
trs.m.column2 = axis02;
trs.p = transform0.p + extents0.x*axis00;
}
// return generateContacts(ctcPts, depths, extents0.y, extents0.z, extents1, trs, transform1, contactDistance);
return generateContacts(contactBuffer, ctcNrm, extents0.y, extents0.z, extents1, trs, transform1, contactDistance);
case AXIS_A1:
// *ctcNrm = axis01;
trs.m.column2 = axis00; // Factored out
if(sign)
{
ctcNrm = axis01;
trs.m.column0 = axis01;
trs.m.column1 = axis02;
trs.p = transform0.p - extents0.y*axis01;
}
else
{
// *ctcNrm = -*ctcNrm;
ctcNrm = -axis01;
trs.m.column0 = -axis01;
trs.m.column1 = -axis02;
trs.p = transform0.p + extents0.y*axis01;
}
// return generateContacts(ctcPts, depths, extents0.z, extents0.x, extents1, trs, transform1, contactDistance);
return generateContacts(contactBuffer, ctcNrm, extents0.z, extents0.x, extents1, trs, transform1, contactDistance);
case AXIS_A2:
// *ctcNrm = axis02;
trs.m.column2 = axis01; // Factored out
if(sign)
{
ctcNrm = axis02;
trs.m.column0 = axis02;
trs.m.column1 = axis00;
trs.p = transform0.p - extents0.z*axis02;
}
else
{
// *ctcNrm = -*ctcNrm;
ctcNrm = -axis02;
trs.m.column0 = -axis02;
trs.m.column1 = -axis00;
trs.p = transform0.p + extents0.z*axis02;
}
// return generateContacts(ctcPts, depths, extents0.x, extents0.y, extents1, trs, transform1, contactDistance);
return generateContacts(contactBuffer, ctcNrm, extents0.x, extents0.y, extents1, trs, transform1, contactDistance);
case AXIS_B0:
// *ctcNrm = axis10;
if(sign)
{
ctcNrm = axis10;
trs.m.column0 = -axis10;
trs.m.column1 = -axis11;
trs.m.column2 = axis12;
trs.p = transform1.p + extents1.x*axis10;
}
else
{
// *ctcNrm = -*ctcNrm;
ctcNrm = -axis10;
trs.m = transform1.m;
trs.p = transform1.p - extents1.x*axis10;
}
// return generateContacts(ctcPts, depths, extents1.y, extents1.z, extents0, trs, transform0, contactDistance);
return generateContacts(contactBuffer, ctcNrm, extents1.y, extents1.z, extents0, trs, transform0, contactDistance);
case AXIS_B1:
// *ctcNrm = axis11;
trs.m.column2 = axis10; // Factored out
if(sign)
{
ctcNrm = axis11;
trs.m.column0 = -axis11;
trs.m.column1 = -axis12;
trs.p = transform1.p + extents1.y*axis11;
}
else
{
// *ctcNrm = -*ctcNrm;
ctcNrm = -axis11;
trs.m.column0 = axis11;
trs.m.column1 = axis12;
trs.m.column2 = axis10;
trs.p = transform1.p - extents1.y*axis11;
}
// return generateContacts(ctcPts, depths, extents1.z, extents1.x, extents0, trs, transform0, contactDistance);
return generateContacts(contactBuffer, ctcNrm, extents1.z, extents1.x, extents0, trs, transform0, contactDistance);
case AXIS_B2:
// *ctcNrm = axis12;
trs.m.column2 = axis11; // Factored out
if(sign)
{
ctcNrm = axis12;
trs.m.column0 = -axis12;
trs.m.column1 = -axis10;
trs.p = transform1.p + extents1.z*axis12;
}
else
{
// *ctcNrm = -*ctcNrm;
ctcNrm = -axis12;
trs.m.column0 = axis12;
trs.m.column1 = axis10;
trs.p = transform1.p - extents1.z*axis12;
}
// return generateContacts(ctcPts, depths, extents1.x, extents1.y, extents0, trs, transform0, contactDistance);
return generateContacts(contactBuffer, ctcNrm, extents1.x, extents1.y, extents0, trs, transform0, contactDistance);
}
}