BOOL OBBCollider::InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb, const Matrix4x4* worldm) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Compute obb in world space mBoxExtents = box.mExtents; Matrix4x4 WorldB; if(worldb) { WorldB = Matrix4x4( box.mRot * Matrix3x3(*worldb) ); WorldB.SetTrans(box.mCenter * *worldb); } else { WorldB = box.mRot; WorldB.SetTrans(box.mCenter); } // Setup matrices Matrix4x4 InvWorldB; InvertPRMatrix(InvWorldB, WorldB); if(worldm) { Matrix4x4 InvWorldM; InvertPRMatrix(InvWorldM, *worldm); Matrix4x4 WorldBtoM = WorldB * InvWorldM; Matrix4x4 WorldMtoB = *worldm * InvWorldB; mRModelToBox = WorldMtoB; WorldMtoB.GetTrans(mTModelToBox); mRBoxToModel = WorldBtoM; WorldBtoM.GetTrans(mTBoxToModel); } else { mRModelToBox = InvWorldB; InvWorldB.GetTrans(mTModelToBox); mRBoxToModel = WorldB; WorldB.GetTrans(mTBoxToModel); } // 3) Setup destination pointer mTouchedPrimitives = &cache.TouchedPrimitives; // 4) Special case: 1-triangle meshes [Opcode 1.3] if(mCurrentModel && mCurrentModel->HasSingleNode()) { if(!SkipPrimitiveTests()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. mTouchedPrimitives->Reset(); // Perform overlap test between the unique triangle and the box (and set contact status if needed) OBB_PRIM(udword(0), OPC_CONTACT) // Return immediately regardless of status return TRUE; } }
BOOL OBBCollider::InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb, const Matrix4x4* worldm) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Compute obb in world space mBoxExtents = box.mExtents; Matrix4x4 WorldB; if(worldb) { WorldB = Matrix4x4( box.mRot2 * Matrix3x3(*worldb) ); WorldB.SetTrans(box.mCenter * *worldb); } else { WorldB = box.mRot2; WorldB.SetTrans(box.mCenter); } // Setup matrices Matrix4x4 InvWorldB; InvertPRMatrix(InvWorldB, WorldB); if(worldm) { Matrix4x4 InvWorldM; InvertPRMatrix(InvWorldM, *worldm); Matrix4x4 WorldBtoM = WorldB * InvWorldM; Matrix4x4 WorldMtoB = *worldm * InvWorldB; mRModelToBox = WorldMtoB; WorldMtoB.GetTrans(mTModelToBox); mRBoxToModel = WorldBtoM; WorldBtoM.GetTrans(mTBoxToModel); } else { mRModelToBox = InvWorldB; InvWorldB.GetTrans(mTModelToBox); mRBoxToModel = WorldB; WorldB.GetTrans(mTBoxToModel); } // Precompute absolute box-to-model rotation matrix for(udword i=0;i<3;i++) { for(udword j=0;j<3;j++) { // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID) mAR.m[i][j] = 1e-6f + fabsf(mRBoxToModel.m[i][j]); } } // Precompute bounds for box-in-box test mB0 = mBoxExtents - mTModelToBox; mB1 = - mBoxExtents - mTModelToBox; // Precompute box-box data - Courtesy of Erwin de Vries Point Box = mBoxExtents; mBBx1 = Box.x*mAR.m[0][0] + Box.y*mAR.m[1][0] + Box.z*mAR.m[2][0]; mBBy1 = Box.x*mAR.m[0][1] + Box.y*mAR.m[1][1] + Box.z*mAR.m[2][1]; mBBz1 = Box.x*mAR.m[0][2] + Box.y*mAR.m[1][2] + Box.z*mAR.m[2][2]; mBB_1 = Box.y*mAR.m[2][0] + Box.z*mAR.m[1][0]; mBB_2 = Box.x*mAR.m[2][0] + Box.z*mAR.m[0][0]; mBB_3 = Box.x*mAR.m[1][0] + Box.y*mAR.m[0][0]; mBB_4 = Box.y*mAR.m[2][1] + Box.z*mAR.m[1][1]; mBB_5 = Box.x*mAR.m[2][1] + Box.z*mAR.m[0][1]; mBB_6 = Box.x*mAR.m[1][1] + Box.y*mAR.m[0][1]; mBB_7 = Box.y*mAR.m[2][2] + Box.z*mAR.m[1][2]; mBB_8 = Box.x*mAR.m[2][2] + Box.z*mAR.m[0][2]; mBB_9 = Box.x*mAR.m[1][2] + Box.y*mAR.m[0][2]; // 3) Setup destination pointer mTouchedPrimitives = &cache.TouchedPrimitives; // 4) Check temporal coherence: if(TemporalCoherenceEnabled()) { // Here we use temporal coherence // => check results from previous frame before performing the collision query if(FirstContactEnabled()) { // We're only interested in the first contact found => test the unique previously touched face if(mTouchedPrimitives->GetNbEntries()) { // Get index of previously touched face = the first entry in the array udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); // Then reset the array: // - if the overlap test below is successful, the index we'll get added back anyway // - if it isn't, then the array should be reset anyway for the normal query mTouchedPrimitives->Reset(); // Perform overlap test between the cached triangle and the box (and set contact status if needed) OBB_PRIM(PreviouslyTouchedFace) } // else no face has been touched during previous query // => we'll have to perform a normal query } else mTouchedPrimitives->Reset();