mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge pull request #4592 from AndrewMeadows/thermonuclear
profiling for physics simulation
This commit is contained in:
commit
e06dada756
5 changed files with 128 additions and 94 deletions
|
@ -976,6 +976,11 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
_myAvatar->setDriveKeys(UP, 1.0f);
|
||||
break;
|
||||
|
||||
case Qt::Key_F: {
|
||||
_physicsEngine.dumpNextStats();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_Asterisk:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Stars);
|
||||
break;
|
||||
|
@ -1183,6 +1188,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
|
||||
case Qt::Key_Comma: {
|
||||
renderCollisionHulls = !renderCollisionHulls;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
@ -257,6 +257,7 @@ btPairCachingGhostObject* CharacterController::getGhostObject() {
|
|||
}
|
||||
|
||||
bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorld) {
|
||||
BT_PROFILE("recoverFromPenetration");
|
||||
// Here we must refresh the overlapping paircache as the penetrating movement itself or the
|
||||
// previous recovery iteration might have used setWorldTransform and pushed us into an object
|
||||
// that is not in the previous cache contents from the last timestep, as will happen if we
|
||||
|
@ -355,6 +356,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl
|
|||
|
||||
|
||||
void CharacterController::scanDown(btCollisionWorld* world) {
|
||||
BT_PROFILE("scanDown");
|
||||
// we test with downward raycast and if we don't find floor close enough then turn on "hover"
|
||||
btKinematicClosestNotMeRayResultCallback callback(_ghostObject);
|
||||
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
|
@ -374,6 +376,7 @@ void CharacterController::scanDown(btCollisionWorld* world) {
|
|||
}
|
||||
|
||||
void CharacterController::stepUp(btCollisionWorld* world) {
|
||||
BT_PROFILE("stepUp");
|
||||
// phase 1: up
|
||||
|
||||
// compute start and end
|
||||
|
@ -440,6 +443,7 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3&
|
|||
}
|
||||
|
||||
void CharacterController::stepForward(btCollisionWorld* collisionWorld, const btVector3& movement) {
|
||||
BT_PROFILE("stepForward");
|
||||
// phase 2: forward
|
||||
_targetPosition = _currentPosition + movement;
|
||||
|
||||
|
@ -496,6 +500,7 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt
|
|||
}
|
||||
|
||||
void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt) {
|
||||
BT_PROFILE("stepDown");
|
||||
// phase 3: down
|
||||
//
|
||||
// The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase.
|
||||
|
@ -607,6 +612,7 @@ void CharacterController::warp(const btVector3& origin) {
|
|||
|
||||
|
||||
void CharacterController::preStep(btCollisionWorld* collisionWorld) {
|
||||
BT_PROFILE("preStep");
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -627,6 +633,7 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) {
|
|||
}
|
||||
|
||||
void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt) {
|
||||
BT_PROFILE("playerStep");
|
||||
if (!_enabled) {
|
||||
return; // no motion
|
||||
}
|
||||
|
@ -875,6 +882,7 @@ void CharacterController::updateShapeIfNecessary() {
|
|||
}
|
||||
|
||||
void CharacterController::preSimulation(btScalar timeStep) {
|
||||
BT_PROFILE("preSimulation");
|
||||
if (_enabled && _dynamicsWorld) {
|
||||
glm::quat rotation = _avatarData->getOrientation();
|
||||
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
||||
|
@ -897,6 +905,7 @@ void CharacterController::preSimulation(btScalar timeStep) {
|
|||
}
|
||||
|
||||
void CharacterController::postSimulation() {
|
||||
BT_PROFILE("postSimulation");
|
||||
if (_enabled && _ghostObject) {
|
||||
const btTransform& avatarTransform = _ghostObject->getWorldTransform();
|
||||
glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
|
||||
|
|
|
@ -155,6 +155,7 @@ void PhysicsEngine::clearEntitiesInternal() {
|
|||
// end EntitySimulation overrides
|
||||
|
||||
void PhysicsEngine::relayIncomingChangesToSimulation() {
|
||||
BT_PROFILE("incomingChanges");
|
||||
// process incoming changes
|
||||
QSet<ObjectMotionState*>::iterator stateItr = _incomingChanges.begin();
|
||||
while (stateItr != _incomingChanges.end()) {
|
||||
|
@ -287,66 +288,76 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
|
|||
}
|
||||
|
||||
void PhysicsEngine::stepSimulation() {
|
||||
lock();
|
||||
// NOTE: the grand order of operations is:
|
||||
// (1) pull incoming changes
|
||||
// (2) step simulation
|
||||
// (3) synchronize outgoing motion states
|
||||
// (4) send outgoing packets
|
||||
|
||||
// This is step (1) pull incoming changes
|
||||
relayIncomingChangesToSimulation();
|
||||
|
||||
const int MAX_NUM_SUBSTEPS = 4;
|
||||
const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds());
|
||||
_clock.reset();
|
||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||
|
||||
// TODO: move character->preSimulation() into relayIncomingChanges
|
||||
if (_characterController) {
|
||||
if (_characterController->needsRemoval()) {
|
||||
_characterController->setDynamicsWorld(NULL);
|
||||
}
|
||||
_characterController->updateShapeIfNecessary();
|
||||
if (_characterController->needsAddition()) {
|
||||
_characterController->setDynamicsWorld(_dynamicsWorld);
|
||||
}
|
||||
_characterController->preSimulation(timeStep);
|
||||
}
|
||||
|
||||
// This is step (2) step simulation
|
||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
_numSubsteps += (uint32_t)numSubsteps;
|
||||
stepNonPhysicalKinematics(usecTimestampNow());
|
||||
unlock();
|
||||
|
||||
// TODO: make all of this harvest stuff into one function: relayOutgoingChanges()
|
||||
if (numSubsteps > 0) {
|
||||
// This is step (3) which is done outside of stepSimulation() so we can lock _entityTree.
|
||||
//
|
||||
// Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree
|
||||
// to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this
|
||||
// PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own
|
||||
// lock on the tree before we re-lock ourselves.
|
||||
//
|
||||
// TODO: untangle these lock sequences.
|
||||
_entityTree->lockForWrite();
|
||||
{
|
||||
lock();
|
||||
_dynamicsWorld->synchronizeMotionStates();
|
||||
CProfileManager::Reset();
|
||||
BT_PROFILE("stepSimulation");
|
||||
// NOTE: the grand order of operations is:
|
||||
// (1) pull incoming changes
|
||||
// (2) step simulation
|
||||
// (3) synchronize outgoing motion states
|
||||
// (4) send outgoing packets
|
||||
|
||||
if (_characterController) {
|
||||
_characterController->postSimulation();
|
||||
}
|
||||
|
||||
unlock();
|
||||
_entityTree->unlock();
|
||||
// This is step (1) pull incoming changes
|
||||
relayIncomingChangesToSimulation();
|
||||
|
||||
computeCollisionEvents();
|
||||
const int MAX_NUM_SUBSTEPS = 4;
|
||||
const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds());
|
||||
_clock.reset();
|
||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||
|
||||
// TODO: move character->preSimulation() into relayIncomingChanges
|
||||
if (_characterController) {
|
||||
if (_characterController->needsRemoval()) {
|
||||
_characterController->setDynamicsWorld(NULL);
|
||||
}
|
||||
_characterController->updateShapeIfNecessary();
|
||||
if (_characterController->needsAddition()) {
|
||||
_characterController->setDynamicsWorld(_dynamicsWorld);
|
||||
}
|
||||
_characterController->preSimulation(timeStep);
|
||||
}
|
||||
|
||||
// This is step (2) step simulation
|
||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
_numSubsteps += (uint32_t)numSubsteps;
|
||||
stepNonPhysicalKinematics(usecTimestampNow());
|
||||
unlock();
|
||||
|
||||
// TODO: make all of this harvest stuff into one function: relayOutgoingChanges()
|
||||
if (numSubsteps > 0) {
|
||||
BT_PROFILE("postSimulation");
|
||||
// This is step (3) which is done outside of stepSimulation() so we can lock _entityTree.
|
||||
//
|
||||
// Unfortunately we have to unlock the simulation (above) before we try to lock the _entityTree
|
||||
// to avoid deadlock -- the _entityTree may try to lock its EntitySimulation (from which this
|
||||
// PhysicsEngine derives) when updating/adding/deleting entities so we need to wait for our own
|
||||
// lock on the tree before we re-lock ourselves.
|
||||
//
|
||||
// TODO: untangle these lock sequences.
|
||||
_entityTree->lockForWrite();
|
||||
lock();
|
||||
_dynamicsWorld->synchronizeMotionStates();
|
||||
|
||||
if (_characterController) {
|
||||
_characterController->postSimulation();
|
||||
}
|
||||
|
||||
unlock();
|
||||
_entityTree->unlock();
|
||||
|
||||
computeCollisionEvents();
|
||||
}
|
||||
}
|
||||
if (_dumpNextStats) {
|
||||
_dumpNextStats = false;
|
||||
CProfileManager::dumpAll();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) {
|
||||
BT_PROFILE("nonPhysicalKinematics");
|
||||
QSet<ObjectMotionState*>::iterator stateItr = _nonPhysicalKinematicObjects.begin();
|
||||
while (stateItr != _nonPhysicalKinematicObjects.end()) {
|
||||
ObjectMotionState* motionState = *stateItr;
|
||||
|
@ -358,6 +369,7 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) {
|
|||
// TODO?: need to occasionally scan for stopped non-physical kinematics objects
|
||||
|
||||
void PhysicsEngine::computeCollisionEvents() {
|
||||
BT_PROFILE("computeCollisionEvents");
|
||||
// update all contacts every frame
|
||||
int numManifolds = _collisionDispatcher->getNumManifolds();
|
||||
for (int i = 0; i < numManifolds; ++i) {
|
||||
|
|
|
@ -86,6 +86,8 @@ public:
|
|||
|
||||
void setCharacterController(CharacterController* character);
|
||||
|
||||
void dumpNextStats() { _dumpNextStats = true; }
|
||||
|
||||
private:
|
||||
/// \param motionState pointer to Object's MotionState
|
||||
void removeObjectFromBullet(ObjectMotionState* motionState);
|
||||
|
@ -121,6 +123,8 @@ private:
|
|||
|
||||
/// character collisions
|
||||
CharacterController* _characterController = NULL;
|
||||
|
||||
bool _dumpNextStats = false;
|
||||
};
|
||||
|
||||
#endif // hifi_PhysicsEngine_h
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
* Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12.
|
||||
* */
|
||||
|
||||
#include <LinearMath/btQuickprof.h>
|
||||
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
|
||||
ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
||||
|
@ -25,50 +27,51 @@ ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
|||
: btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) {
|
||||
}
|
||||
|
||||
int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) {
|
||||
int subSteps = 0;
|
||||
if (maxSubSteps) {
|
||||
//fixed timestep with interpolation
|
||||
m_fixedTimeStep = fixedTimeStep;
|
||||
m_localTime += timeStep;
|
||||
if (m_localTime >= fixedTimeStep)
|
||||
{
|
||||
subSteps = int( m_localTime / fixedTimeStep);
|
||||
m_localTime -= subSteps * fixedTimeStep;
|
||||
}
|
||||
} else {
|
||||
//variable timestep
|
||||
fixedTimeStep = timeStep;
|
||||
m_localTime = m_latencyMotionStateInterpolation ? 0 : timeStep;
|
||||
m_fixedTimeStep = 0;
|
||||
if (btFuzzyZero(timeStep))
|
||||
{
|
||||
subSteps = 0;
|
||||
maxSubSteps = 0;
|
||||
} else
|
||||
{
|
||||
subSteps = 1;
|
||||
maxSubSteps = 1;
|
||||
}
|
||||
}
|
||||
int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) {
|
||||
BT_PROFILE("stepSimulation");
|
||||
int subSteps = 0;
|
||||
if (maxSubSteps) {
|
||||
//fixed timestep with interpolation
|
||||
m_fixedTimeStep = fixedTimeStep;
|
||||
m_localTime += timeStep;
|
||||
if (m_localTime >= fixedTimeStep)
|
||||
{
|
||||
subSteps = int( m_localTime / fixedTimeStep);
|
||||
m_localTime -= subSteps * fixedTimeStep;
|
||||
}
|
||||
} else {
|
||||
//variable timestep
|
||||
fixedTimeStep = timeStep;
|
||||
m_localTime = m_latencyMotionStateInterpolation ? 0 : timeStep;
|
||||
m_fixedTimeStep = 0;
|
||||
if (btFuzzyZero(timeStep))
|
||||
{
|
||||
subSteps = 0;
|
||||
maxSubSteps = 0;
|
||||
} else
|
||||
{
|
||||
subSteps = 1;
|
||||
maxSubSteps = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*//process some debugging flags
|
||||
if (getDebugDrawer()) {
|
||||
btIDebugDraw* debugDrawer = getDebugDrawer ();
|
||||
gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
|
||||
}*/
|
||||
if (subSteps) {
|
||||
//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
|
||||
int clampedSimulationSteps = (subSteps > maxSubSteps)? maxSubSteps : subSteps;
|
||||
/*//process some debugging flags
|
||||
if (getDebugDrawer()) {
|
||||
btIDebugDraw* debugDrawer = getDebugDrawer ();
|
||||
gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
|
||||
}*/
|
||||
if (subSteps) {
|
||||
//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
|
||||
int clampedSimulationSteps = (subSteps > maxSubSteps)? maxSubSteps : subSteps;
|
||||
|
||||
saveKinematicState(fixedTimeStep*clampedSimulationSteps);
|
||||
saveKinematicState(fixedTimeStep*clampedSimulationSteps);
|
||||
|
||||
applyGravity();
|
||||
applyGravity();
|
||||
|
||||
for (int i=0;i<clampedSimulationSteps;i++) {
|
||||
internalSingleStepSimulation(fixedTimeStep);
|
||||
}
|
||||
}
|
||||
for (int i=0;i<clampedSimulationSteps;i++) {
|
||||
internalSingleStepSimulation(fixedTimeStep);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: We do NOT call synchronizeMotionState() after each substep (to avoid multiple locks on the
|
||||
// object data outside of the physics engine). A consequence of this is that the transforms of the
|
||||
|
@ -77,7 +80,7 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps,
|
|||
// NOTE: We do NOT call synchronizeMotionStates() here. Instead it is called by an external class
|
||||
// that knows how to lock threads correctly.
|
||||
|
||||
clearForces();
|
||||
clearForces();
|
||||
|
||||
return subSteps;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue