📄 opc_obbcollider.cpp
字号:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an OBB collider.
* \file OPC_OBBCollider.cpp
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains an OBB-vs-tree collider.
*
* \class OBBCollider
* \author Pierre Terdiman
* \version 1.3
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Opcode/Stdafx.h"
using namespace Opcode;
using namespace IceMaths;
#include "Opcode/OPC_BoxBoxOverlap.h"
#include "Opcode/OPC_TriBoxOverlap.h"
#define SET_CONTACT(prim_index, flag) \
/* Set contact status */ \
mFlags |= flag; \
mTouchedPrimitives->Add(prim_index);
//! OBB-triangle test
#define OBB_PRIM(prim_index, flag) \
/* Request vertices from the app */ \
VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
/* Transform them in a common space with scales */ \
TransformPoint(mLeafVerts[0], *VP.Vertex[0], mSRModelToBox, mTModelToBox); \
TransformPoint(mLeafVerts[1], *VP.Vertex[1], mSRModelToBox, mTModelToBox); \
TransformPoint(mLeafVerts[2], *VP.Vertex[2], mSRModelToBox, mTModelToBox); \
/* Perform triangle-box overlap test */ \
if(TriBoxOverlap()) \
{ \
SET_CONTACT(prim_index, flag) \
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OBBCollider::OBBCollider() : mFullBoxBoxTest(true)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OBBCollider::~OBBCollider()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* OBBCollider::ValidateSettings()
{
if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
return VolumeCollider::ValidateSettings();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a box cache
* \param box [in] collision OBB in local space
* \param model [in] Opcode model to collide with
* \param worldb [in] OBB's world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED IN THE BOX WORLD MATRIX. The matrix must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBBCollider::Collide(OBBCache& cache, const IceMaths::OBB& box, const Model& model, const IceMaths::Matrix4x4* worldb, const IceMaths::Matrix4x4* worldm)
{
// Checkings
if(!Setup(&model)) return false;
// Init collision query
if(InitQuery(cache, box, worldb, worldm)) return true;
if(!model.HasLeafNodes())
{
if(model.IsQuantized())
{
const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
// Setup dequantization coeffs
mCenterCoeff = Tree->mCenterCoeff;
mExtentsCoeff = Tree->mExtentsCoeff;
// Perform collision query
if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
else _Collide(Tree->GetNodes());
}
else
{
const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
// Perform collision query
if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
else _Collide(Tree->GetNodes());
}
}
else
{
if(model.IsQuantized())
{
const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
// Setup dequantization coeffs
mCenterCoeff = Tree->mCenterCoeff;
mExtentsCoeff = Tree->mExtentsCoeff;
// Perform collision query
if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
else _Collide(Tree->GetNodes());
}
else
{
const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
// Perform collision query
if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
else _Collide(Tree->GetNodes());
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes a collision query :
* - reset stats & contact status
* - setup matrices
* - check temporal coherence
*
* \param cache [in/out] a box cache
* \param box [in] obb in local space
* \param worldb [in] obb's world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return TRUE if we can return immediately
* \warning SCALE NOT SUPPORTED IN OBB WORLD MATRIX. The matrix must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL OBBCollider::InitQuery(OBBCache& cache, const IceMaths::OBB& box, const IceMaths::Matrix4x4* worldb, const IceMaths::Matrix4x4* worldm)
{
// 1) Call the base method
VolumeCollider::InitQuery();
// 2) Compute obb in world space
mBoxExtents = box.mExtents;
IceMaths::Matrix4x4 WorldB;
if(worldb)
{
// normalizes world matrix and gets scale
Point obbScale;
Matrix4x4 normWorldB;
NormalizePRSMatrix( normWorldB, obbScale, *worldb );
WorldB = Matrix4x4( box.mRot * Matrix3x3(normWorldB) );
// note that scale is pre-applied to center and extents
WorldB.SetTrans((box.mCenter*obbScale) * normWorldB);
mBoxExtents *= obbScale;
}
else
{
WorldB = box.mRot;
WorldB.SetTrans(box.mCenter);
}
// Setup matrices
IceMaths::Matrix4x4 InvWorldB;
InvertPRMatrix(InvWorldB, WorldB);
if(worldm)
{
// Matrix normalization & scaling stripping
IceMaths::Matrix4x4 normWorldM;
NormalizePRSMatrix( normWorldM, mLocalScale, *worldm );
// uses the PR part of the world matrix
IceMaths::Matrix4x4 InvWorldM;
InvertPRMatrix(InvWorldM, normWorldM);
IceMaths::Matrix4x4 WorldBtoM = WorldB * InvWorldM;
IceMaths::Matrix4x4 WorldMtoB = normWorldM * InvWorldB;
mSRModelToBox = *worldm * InvWorldB; // for scales
mRModelToBox = WorldMtoB; WorldMtoB.GetTrans(mTModelToBox);
mRBoxToModel = WorldBtoM; WorldBtoM.GetTrans(mTBoxToModel);
}
else
{
mLocalScale.Set(1.0,1.0,1.0);
mSRModelToBox = 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;
}
}
// 5) 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())
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -