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;
		}
	}
Example #2
0
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();