Browse Source

Rework PhysX collision flutter bug workaround

To better handle erroneous trigger events under the new timing method, use the number of times the simulation has actually advanced instead of the number of evals received.

Cleaned up a bit.
Skoader 12 years ago committed by Adam Johnson
parent
commit
d3ea8fe333
  1. 3
      Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
  2. 3
      Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
  3. 221
      Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp
  4. 53
      Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h

3
Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp

@ -283,6 +283,7 @@ plSimulationMgr* plSimulationMgr::GetInstance()
plSimulationMgr::plSimulationMgr() plSimulationMgr::plSimulationMgr()
: fSuspended(true) : fSuspended(true)
, fAccumulator(0.0f) , fAccumulator(0.0f)
, fStepCount(0)
, fLOSDispatch(new plLOSDispatch()) , fLOSDispatch(new plLOSDispatch())
, fSoundMgr(new plPhysicsSoundMgr) , fSoundMgr(new plPhysicsSoundMgr)
, fLog(nil) , fLog(nil)
@ -468,6 +469,8 @@ void plSimulationMgr::Advance(float delSecs)
fAccumulator = kDefaultMaxDelta; fAccumulator = kDefaultMaxDelta;
} }
++fStepCount;
// Perform as many whole substeps as possible saving the remainder in our accumulator. // Perform as many whole substeps as possible saving the remainder in our accumulator.
int numSubSteps = (int)(fAccumulator / kDefaultStepSize + 0.000001f); int numSubSteps = (int)(fAccumulator / kDefaultStepSize + 0.000001f);
float delta = numSubSteps * kDefaultStepSize; float delta = numSubSteps * kDefaultStepSize;

3
Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h

@ -99,6 +99,8 @@ public:
int GetMaterialIdx(NxScene* scene, float friction, float restitution); int GetMaterialIdx(NxScene* scene, float friction, float restitution);
uint32_t GetStepCount() const { return fStepCount; }
//Fix to Move collision messages and their handling out of the simulation step //Fix to Move collision messages and their handling out of the simulation step
void AddCollisionMsg(plKey hitee, plKey hitter, bool entering); void AddCollisionMsg(plKey hitee, plKey hitter, bool entering);
void AddCollisionMsg(plCollideMsg* msg); void AddCollisionMsg(plCollideMsg* msg);
@ -139,6 +141,7 @@ protected:
bool fSuspended; bool fSuspended;
float fAccumulator; float fAccumulator;
uint32_t fStepCount;
// A utility class to keep track of a request for a physical synchronization. // A utility class to keep track of a request for a physical synchronization.
// These requests must pass a certain criteria (see the code for the latest) // These requests must pass a certain criteria (see the code for the latest)

221
Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp

@ -68,8 +68,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plModifier/plDetectorLog.h" #include "plModifier/plDetectorLog.h"
#define USE_PHYSX_MULTIPLE_CAMREGION_ENTER 1 #ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
#define USE_PHYSX_COLLISION_FLUTTER_WORKAROUND 1 #include "plPhysX/plSimulationMgr.h"
#endif
plArmatureMod* plCollisionDetector::IGetAvatarModifier(plKey key) plArmatureMod* plCollisionDetector::IGetAvatarModifier(plKey key)
{ {
@ -240,58 +243,19 @@ plCameraRegionDetector::~plCameraRegionDetector()
hsRefCnt_SafeUnRef(*it); hsRefCnt_SafeUnRef(*it);
} }
void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate) void plCameraRegionDetector::ISendTriggerMsg()
{ {
if (fSavingSendMsg) for (plCameraMsgVec::iterator it = fMessages.begin(); it != fMessages.end(); ++it)
DetectorLogRed("%s: Stale messages on ITrigger. This should never happen!", GetKeyName().c_str());
if (fIsInside && entering)
DetectorLogRed("%s: Duplicate enter! Did we miss an exit?", GetKeyName().c_str());
else if (!fIsInside && !entering)
DetectorLogRed("%s: Duplicate exit! Did we miss an enter?", GetKeyName().c_str());
fSavingSendMsg = true;
fSavedMsgEnterFlag = entering;
if (entering)
{
DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName().c_str(),fNumEvals);
fLastEnterEval = fNumEvals;
}
else
{
DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName().c_str(),fNumEvals);
fLastExitEval = fNumEvals;
}
if (immediate)
ISendSavedTriggerMsgs();
}
void plCameraRegionDetector::ISendSavedTriggerMsgs()
{
if (fSavingSendMsg)
{ {
for (size_t i = 0; i < fMessages.size(); ++i) plCameraMsg* msg = *it;
{ if (fIsInside)
hsRefCnt_SafeRef(fMessages[i]); msg->SetCmd(plCameraMsg::kEntering);
if (fSavedMsgEnterFlag) else
{ msg->ClearCmd(plCameraMsg::kEntering);
fMessages[i]->SetCmd(plCameraMsg::kEntering); msg->SendAndKeep();
DetectorLog("Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size());
fIsInside = true;
}
else
{
fMessages[i]->ClearCmd(plCameraMsg::kEntering);
DetectorLog("Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size());
fIsInside = false;
}
plgDispatch::MsgSend(fMessages[i]);
}
} }
fSavingSendMsg = false;
} }
bool plCameraRegionDetector::MsgReceive(plMessage* msg) bool plCameraRegionDetector::MsgReceive(plMessage* msg)
{ {
plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg);
@ -300,8 +264,16 @@ bool plCameraRegionDetector::MsgReceive(plMessage* msg)
// camera collisions are only for the local player // camera collisions are only for the local player
if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey) if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey)
return true; return true;
// Fall through to plObjectInVolumeDetector, which will register us for plEvalMsg
// and handle it for us. (Hint: See ISendSavedTriggerMsgs) if (!fWaitingForEval)
IRegisterForEval();
fEntering = (pCollMsg->fEntering != 0);
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
fLastStep = plSimulationMgr::GetInstance()->GetStepCount();
#endif
return true;
} }
return plObjectInVolumeDetector::MsgReceive(msg); return plObjectInVolumeDetector::MsgReceive(msg);
@ -327,56 +299,72 @@ void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr)
} }
void plCameraRegionDetector::IHandleEval(plEvalMsg*)
{
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
if (plSimulationMgr::GetInstance()->GetStepCount() - fLastStep > 1)
{
#endif
if (fIsInside != fEntering)
{
fIsInside = fEntering;
DetectorLog("%s CameraRegion: %s", fIsInside ? "Entering" : "Exiting", GetKeyName().c_str());
ISendTriggerMsg();
}
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
fWaitingForEval = false;
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
}
#endif
}
///////////////////////////////// /////////////////////////////////
///////////////////////////////// /////////////////////////////////
///////////////////////////////// /////////////////////////////////
///////////////////////////////// /////////////////////////////////
// object-in-volume detector // object-in-volume detector
void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immediate) void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering)
{ {
hsRefCnt_SafeUnRef(fSavedActivatorMsg); #ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
fSavedActivatorMsg = new plActivatorMsg; for (bookKeepingList::iterator it = fCollisionList.begin(); it != fCollisionList.end(); ++it)
fSavedActivatorMsg->AddReceivers(fReceivers);
if (fProxyKey)
fSavedActivatorMsg->fHiteeObj = fProxyKey;
else
fSavedActivatorMsg->fHiteeObj = GetTarget()->GetKey();
fSavedActivatorMsg->fHitterObj = hitter;
fSavedActivatorMsg->SetSender(GetKey());
if (entering)
{
DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter);
fLastEnterEval = fNumEvals;
}
else
{ {
DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals); plCollisionBookKeepingInfo* collisionInfo = *it;
fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); if (collisionInfo->fHitter == hitter)
fLastExitEval = fNumEvals; {
collisionInfo->fEntering = entering;
collisionInfo->fLastStep = plSimulationMgr::GetInstance()->GetStepCount();
return;
}
} }
#endif
if (immediate) plCollisionBookKeepingInfo* collisionInfo = new plCollisionBookKeepingInfo(hitter, entering);
ISendSavedTriggerMsgs(); fCollisionList.push_back(collisionInfo);
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
collisionInfo->fLastStep = plSimulationMgr::GetInstance()->GetStepCount();
#endif
} }
void plObjectInVolumeDetector::ISendSavedTriggerMsgs() void plObjectInVolumeDetector::IRegisterForEval()
{ {
if (fSavedActivatorMsg) fWaitingForEval = true;
{ plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
if (fSavedActivatorMsg->fTriggerType == plActivatorMsg::kVolumeEnter) }
DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
else
DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
// we're saving the message to be dispatched later... void plObjectInVolumeDetector::ISendTriggerMsg(plKey hitter, bool entering)
plgDispatch::MsgSend(fSavedActivatorMsg); {
} plActivatorMsg* activatorMsg = new plActivatorMsg();
fSavedActivatorMsg = nil; activatorMsg->SetSender(GetKey());
activatorMsg->AddReceivers(fReceivers);
activatorMsg->fHiteeObj = fProxyKey ? fProxyKey : GetTarget()->GetKey();
activatorMsg->fHitterObj = hitter;
if (entering)
activatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter);
else
activatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit);
plgDispatch::MsgSend(activatorMsg);
} }
bool plObjectInVolumeDetector::MsgReceive(plMessage* msg) bool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
@ -387,18 +375,17 @@ bool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
// If the avatar is disabled (flying around), don't trigger // If the avatar is disabled (flying around), don't trigger
if (IIsDisabledAvatar(pCollMsg->fOtherKey)) if (IIsDisabledAvatar(pCollMsg->fOtherKey))
return false; return false;
if (!fWaitingForEval)
IRegisterForEval();
ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0)); ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0));
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
return true; return true;
} }
plEvalMsg* pEvalMsg = plEvalMsg::ConvertNoRef(msg); plEvalMsg* pEvalMsg = plEvalMsg::ConvertNoRef(msg);
if (pEvalMsg) if (pEvalMsg)
{ IHandleEval(pEvalMsg);
fNumEvals++;
ISendSavedTriggerMsgs();
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
}
plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg); plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg);
if (pageMsg && pageMsg->fUnload) if (pageMsg && pageMsg->fUnload)
@ -409,6 +396,48 @@ bool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
return plCollisionDetector::MsgReceive(msg); return plCollisionDetector::MsgReceive(msg);
} }
void plObjectInVolumeDetector::IHandleEval(plEvalMsg*)
{
bookKeepingList::iterator it = fCollisionList.begin();
while (it != fCollisionList.end())
{
plCollisionBookKeepingInfo* collisionInfo = *it;
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
if (plSimulationMgr::GetInstance()->GetStepCount() - collisionInfo->fLastStep > 1)
{
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
ResidentSet::iterator j = fCurrentResidents.find(collisionInfo->fHitter);
bool wasInside = j != fCurrentResidents.end();
if (collisionInfo->fEntering != wasInside)
{
if (collisionInfo->fEntering)
{
fCurrentResidents.insert(collisionInfo->fHitter);
DetectorLog("%s: Sending Volume Enter ActivatorMsg", GetKeyName().c_str());
ISendTriggerMsg(collisionInfo->fHitter, true);
}
else
{
fCurrentResidents.erase(j);
DetectorLog("%s: Sending Volume Exit ActivatorMsg", GetKeyName().c_str());
ISendTriggerMsg(collisionInfo->fHitter, false);
}
}
delete collisionInfo;
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
it = fCollisionList.erase(it);
}
else
{
++it;
}
#else
++it;
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
}
}
void plObjectInVolumeDetector::SetTarget(plSceneObject* so) void plObjectInVolumeDetector::SetTarget(plSceneObject* so)
{ {
plCollisionDetector::SetTarget(so); plCollisionDetector::SetTarget(so);
@ -485,13 +514,13 @@ void plObjectInVolumeAndFacingDetector::ICheckForTrigger()
{ {
DetectorLog("%s: Trigger InVolume&Facing", GetKeyName().c_str()); DetectorLog("%s: Trigger InVolume&Facing", GetKeyName().c_str());
fTriggered = true; fTriggered = true;
ITrigger(avatar->GetKey(), true, true); ISendTriggerMsg(avatar->GetKey(), true);
} }
else if (!facing && fTriggered) else if (!facing && fTriggered)
{ {
DetectorLog("%s: Untrigger InVolume&Facing", GetKeyName().c_str()); DetectorLog("%s: Untrigger InVolume&Facing", GetKeyName().c_str());
fTriggered = false; fTriggered = false;
ITrigger(avatar->GetKey(), false, true); ISendTriggerMsg(avatar->GetKey(), false);
} }
} }
} }
@ -525,7 +554,7 @@ bool plObjectInVolumeAndFacingDetector::MsgReceive(plMessage* msg)
if (fTriggered) if (fTriggered)
{ {
fTriggered = false; fTriggered = false;
ITrigger(plNetClientApp::GetInstance()->GetLocalPlayerKey(), false, true); ISendTriggerMsg(plNetClientApp::GetInstance()->GetLocalPlayerKey(), false);
} }
} }

53
Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h

@ -53,6 +53,8 @@ class plArmatureMod;
class plActivatorMsg; class plActivatorMsg;
class plEvalMsg; class plEvalMsg;
#define USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
class plCollisionDetector : public plDetectorModifier class plCollisionDetector : public plDetectorModifier
{ {
protected: protected:
@ -92,23 +94,37 @@ public:
class plObjectInVolumeDetector : public plCollisionDetector class plObjectInVolumeDetector : public plCollisionDetector
{ {
protected: protected:
virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); class plCollisionBookKeepingInfo
virtual void ISendSavedTriggerMsgs(); {
public:
plCollisionBookKeepingInfo(const plKey& key, bool entering)
: fHitter(key), fEntering(entering) { }
plKey fHitter;
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
uint32_t fLastStep;
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
bool fEntering;
};
plActivatorMsg* fSavedActivatorMsg; void ITrigger(plKey hitter, bool entering);
uint32_t fNumEvals; void ISendTriggerMsg(plKey hitter, bool entering);
uint32_t fLastEnterEval; void IRegisterForEval();
uint32_t fLastExitEval; virtual void IHandleEval(plEvalMsg*);
bool fWaitingForEval;
typedef std::list<plCollisionBookKeepingInfo*> bookKeepingList;
bookKeepingList fCollisionList;
typedef std::set<plKey> ResidentSet;
ResidentSet fCurrentResidents;
public: public:
plObjectInVolumeDetector() plObjectInVolumeDetector()
: plCollisionDetector(), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0) : plCollisionDetector(), fWaitingForEval(false) { }
{ }
plObjectInVolumeDetector(int8_t type) plObjectInVolumeDetector(int8_t type)
: plCollisionDetector(type), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0) : plCollisionDetector(type), fWaitingForEval(false) { }
{ }
virtual ~plObjectInVolumeDetector() { } virtual ~plObjectInVolumeDetector() { }
@ -159,16 +175,17 @@ protected:
typedef std::vector<plCameraMsg*> plCameraMsgVec; typedef std::vector<plCameraMsg*> plCameraMsgVec;
plCameraMsgVec fMessages; plCameraMsgVec fMessages;
bool fIsInside; #ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
bool fSavingSendMsg; uint32_t fLastStep;
bool fSavedMsgEnterFlag; #endif
bool fIsInside;
virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); bool fEntering;
virtual void ISendSavedTriggerMsgs();
void ISendTriggerMsg();
virtual void IHandleEval(plEvalMsg*);
public: public:
plCameraRegionDetector() plCameraRegionDetector()
: plObjectInVolumeDetector(), fIsInside(false), fSavingSendMsg(false) : plObjectInVolumeDetector(), fIsInside(false) { }
{ }
~plCameraRegionDetector(); ~plCameraRegionDetector();
virtual bool MsgReceive(plMessage* msg); virtual bool MsgReceive(plMessage* msg);

Loading…
Cancel
Save