mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 15:49:51 +02:00
initial implementation of PhysicalEntitySimulation
This commit is contained in:
parent
e3d29d74af
commit
304850372e
2 changed files with 399 additions and 0 deletions
333
libraries/physics/src/PhysicalEntitySimulation.cpp
Normal file
333
libraries/physics/src/PhysicalEntitySimulation.cpp
Normal file
|
@ -0,0 +1,333 @@
|
|||
//
|
||||
// PhysicalEntitySimulation.cpp
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.04.27
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <AABox.h>
|
||||
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
#include "ShapeInfoUtil.h"
|
||||
#include "PhysicsHelpers.h"
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
#include "PhysicsLogging.h"
|
||||
|
||||
PhysicalEntitySimulation::PhysicalEntitySimulation() :
|
||||
}
|
||||
|
||||
PhysicalEntitySimulation::~PhysicalEntitySimulation() {
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::init(
|
||||
EntityTree* tree,
|
||||
PhysicsEngine* physicsEngine,
|
||||
ShapeManager* shapeManager,
|
||||
EntityEditPacketSender* packetSender) {
|
||||
assert(tree);
|
||||
setEntityTree(tree);
|
||||
|
||||
assert(*physicsEngine);
|
||||
_physicsEngine = physicsEngine;
|
||||
|
||||
assert(*shapeManager);
|
||||
_shapeManager = shapeManager;
|
||||
|
||||
assert(packetSender);
|
||||
_entityPacketSender = packetSender;
|
||||
}
|
||||
|
||||
// begin EntitySimulation overrides
|
||||
void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) {
|
||||
// TODO: add back non-physical kinematic objects and step them forward here
|
||||
}
|
||||
|
||||
/* {
|
||||
uint32_t numSubsteps = _physicsEngine->getNumSubsteps();
|
||||
if (_lastNumSubstepsAtUpdateInternal != numSubsteps) {
|
||||
_lastNumSubstepsAtUpdateInternal = numSubsteps;
|
||||
|
||||
SetOfMotionStates::iterator stateItr = _outgoingPackets.begin();
|
||||
while (stateItr != _outgoingPackets.end()) {
|
||||
ObjectMotionState* state = *stateItr;
|
||||
if (state->doesNotNeedToSendUpdate()) {
|
||||
stateItr = _outgoingPackets.erase(stateItr);
|
||||
} else if (state->shouldSendUpdate(numSubsteps)) {
|
||||
state->sendUpdate(_entityPacketSender, numSubsteps);
|
||||
++stateItr;
|
||||
} else {
|
||||
++stateItr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) {
|
||||
assert(entity);
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
if (!physicsInfo) {
|
||||
_pendingAdds.insert(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::get {
|
||||
if (entity->isReadyToComputeShape()) {
|
||||
ShapeInfo shapeInfo;
|
||||
entity->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = _physicsEngine->getShape(shapeInfo);
|
||||
if (shape) {
|
||||
EntityMotionState* motionState = new EntityMotionState(entity);
|
||||
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||
_physicalEntities.insert(motionState);
|
||||
_physicsEngine->addObject(shapeInfo, shape, motionState);
|
||||
motionState->setPhysical(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) {
|
||||
assert(entity);
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
if (physicsInfo) {
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||
_pendingRemoves.insert(motionState);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::entityChangedInternal(EntityItem* entity) {
|
||||
// queue incoming changes: from external sources (script, EntityServer, etc) to physics engine
|
||||
assert(entity);
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
if (physicsInfo) {
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||
_pendingUpdates.insert(motionState);
|
||||
} else {
|
||||
if (!entity->ignoreForCollisions()) {
|
||||
// The intent is for this object to be in the PhysicsEngine.
|
||||
// Perhaps it's shape has changed and it can now be added?
|
||||
_pendingAdds.insert(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::sortEntitiesThatMovedInternal() {
|
||||
// entities that have been simulated forward (hence in the _entitiesToBeSorted list)
|
||||
// also need to be put in the outgoingPackets list
|
||||
QSet<EntityItem*>::iterator entityItr = _entitiesToBeSorted.begin();
|
||||
while (entityItr != _entitiesToBeSorted.end()) {
|
||||
EntityItem* entity = *entityItr;
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
assert(physicsInfo);
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||
_outgoingPackets.insert(motionState);
|
||||
++entityItr;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::clearEntitiesInternal() {
|
||||
SetOfMotionStates::const_iterator stateItr = _physicalEntities.begin();
|
||||
for (stateItr = _physicalEntities.begin(); stateItr != _physicalEntities.end(); ++stateItr) {
|
||||
removeObjectFromBullet(*stateItr);
|
||||
delete (*stateItr);
|
||||
}
|
||||
_physicalEntities.clear();
|
||||
_pendingRemoves.clear();
|
||||
_pendingAdds.clear();
|
||||
_pendingUpdates.clear();
|
||||
}
|
||||
// end EntitySimulation overrides
|
||||
|
||||
|
||||
SetOfMotionState& PhysicalEntitySimulation::getObjectsToRemove() {
|
||||
_tempSet.clear();
|
||||
for (auto entityItr : _pendingRemoves) {
|
||||
EntityItem* entity = *entityItr;
|
||||
_pendingAdds.remove(entity);
|
||||
_pendingUpdates.remove(entity);
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
|
||||
if (motionState) {
|
||||
_tempSet.push_back(motionState);
|
||||
}
|
||||
}
|
||||
// DO NOT clear _pendingRemoves -- we still need to remove from _physicalEntities
|
||||
// and then communicate to the EntityTree that they can really can be deleted.
|
||||
// TODO: build the pipeline for this.
|
||||
//_pendingRemoves.clear();
|
||||
return _tempSet;
|
||||
}
|
||||
|
||||
SetOfMotionState& PhysicalEntitySimulation::getObjectsToAdd() {
|
||||
_tempSet.clear();
|
||||
SetOfEntities::iterator entityItr = _pendingAdds.begin();
|
||||
while (entityItr != _pendingAdds.end()) {
|
||||
EntityItem* entity = *entityItr;
|
||||
assert(!entity->getPhysicsInfo());
|
||||
|
||||
if (entity->isReadyToComputeShape()) {
|
||||
ShapeInfo shapeInfo;
|
||||
entity->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = _shapeManager->getShape(shapeInfo);
|
||||
if (shape) {
|
||||
shapeInfo.setShape(shape);
|
||||
EntityMotionState* motionState = new EntityMotionState(entity);
|
||||
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||
_physicalEntities.insert(motionState);
|
||||
entityItr = _pendingAdds.erase(entityItr);
|
||||
// TODO: figure out how to get shapeInfo (or relevant info) to PhysicsEngine during add
|
||||
//_physicsEngine->addObject(shapeInfo, motionState);
|
||||
} else {
|
||||
++entityItr;
|
||||
}
|
||||
}
|
||||
_tempSet.push_back(motionState);
|
||||
}
|
||||
return _tempSet;
|
||||
}
|
||||
|
||||
SetOfMotionState& PhysicalEntitySimulation::getObjectsToUpdate() {
|
||||
_tempSet.clear();
|
||||
for (auto entityItr : _pendingUpdates) {
|
||||
EntityItem* entity = *entityItr;
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
|
||||
if (motionState) {
|
||||
_tempSet.push_back(motionState);
|
||||
}
|
||||
}
|
||||
_pendingUpdates.clear();
|
||||
return _tempSet;
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::clearIncomingChanges() {
|
||||
// TODO: finalize deletes in the EntityTree?
|
||||
// or should we allow EntityMotionState::_entity to be NULL during normal operation?
|
||||
// (In order to do this _pendingDeletes would have to be list of MotionStates, or something)
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::bump(EntityItem* bumpEntity) {
|
||||
}
|
||||
|
||||
/* useful CRUFT
|
||||
void PhysicalEntitySimulation::relayIncomingChangesToSimulation() {
|
||||
BT_PROFILE("incomingChanges");
|
||||
// process incoming changes
|
||||
SetOfMotionStates::iterator stateItr = _incomingChanges.begin();
|
||||
while (stateItr != _incomingChanges.end()) {
|
||||
ObjectMotionState* motionState = *stateItr;
|
||||
++stateItr;
|
||||
uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS;
|
||||
|
||||
bool removeMotionState = false;
|
||||
btRigidBody* body = motionState->getRigidBody();
|
||||
if (body) {
|
||||
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
|
||||
// a HARD update requires the body be pulled out of physics engine, changed, then reinserted
|
||||
// but it also handles all EASY changes
|
||||
bool success = updateObjectHard(body, motionState, flags);
|
||||
if (!success) {
|
||||
// NOTE: since updateObjectHard() failed we know that motionState has been removed
|
||||
// from simulation and body has been deleted. Depending on what else has changed
|
||||
// we might need to remove motionState altogether...
|
||||
if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||
motionState->updateKinematicState(_numSubsteps);
|
||||
if (motionState->isKinematic()) {
|
||||
// all is NOT lost, we still need to move this object around kinematically
|
||||
_nonPhysicalKinematicEntities.insert(motionState);
|
||||
} else {
|
||||
// no need to keep motionState around
|
||||
removeMotionState = true;
|
||||
}
|
||||
} else {
|
||||
// no need to keep motionState around
|
||||
removeMotionState = true;
|
||||
}
|
||||
}
|
||||
} else if (flags) {
|
||||
// an EASY update does NOT require that the body be pulled out of physics engine
|
||||
// hence the MotionState has all the knowledge and authority to perform the update.
|
||||
motionState->updateObjectEasy(flags, _numSubsteps);
|
||||
}
|
||||
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
|
||||
motionState->resetMeasuredBodyAcceleration();
|
||||
}
|
||||
} else {
|
||||
// the only way we should ever get here (motionState exists but no body) is when the object
|
||||
// is undergoing non-physical kinematic motion.
|
||||
assert(_nonPhysicalKinematicEntities.contains(motionState));
|
||||
|
||||
// it is possible that the changes are such that the object can now be added to the physical simulation
|
||||
if (flags & EntityItem::DIRTY_SHAPE) {
|
||||
ShapeInfo shapeInfo;
|
||||
motionState->computeObjectShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
|
||||
if (shape) {
|
||||
addObject(shapeInfo, shape, motionState);
|
||||
_nonPhysicalKinematicEntities.remove(motionState);
|
||||
} else if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||
// although we couldn't add the object to the simulation, might need to update kinematic motion...
|
||||
motionState->updateKinematicState(_numSubsteps);
|
||||
if (!motionState->isKinematic()) {
|
||||
_nonPhysicalKinematicEntities.remove(motionState);
|
||||
removeMotionState = true;
|
||||
}
|
||||
}
|
||||
} else if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||
// although we still can't add to physics simulation, might need to update kinematic motion...
|
||||
motionState->updateKinematicState(_numSubsteps);
|
||||
if (!motionState->isKinematic()) {
|
||||
_nonPhysicalKinematicEntities.remove(motionState);
|
||||
removeMotionState = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removeMotionState) {
|
||||
// if we get here then there is no need to keep this motionState around (no physics or kinematics)
|
||||
_outgoingPackets.remove(motionState);
|
||||
if (motionState->getType() == MOTION_STATE_TYPE_ENTITY) {
|
||||
_physicalEntities.remove(static_cast<EntityMotionState*>(motionState));
|
||||
}
|
||||
// NOTE: motionState will clean up its own backpointers in the Object
|
||||
delete motionState;
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: the grand order of operations is:
|
||||
// (1) relay incoming changes
|
||||
// (2) step simulation
|
||||
// (3) synchronize outgoing motion states
|
||||
// (4) send outgoing packets
|
||||
//
|
||||
// We're in the middle of step (1) hence incoming changes should trump corresponding
|
||||
// outgoing changes at this point.
|
||||
motionState->clearOutgoingPacketFlags(flags); // clear outgoing flags that were trumped
|
||||
motionState->clearIncomingDirtyFlags(flags); // clear incoming flags that were processed
|
||||
}
|
||||
_incomingChanges.clear();
|
||||
}
|
||||
|
||||
{
|
||||
// TODO: re-enable non-physical-kinematics
|
||||
// step non-physical kinematic objects
|
||||
SetOfMotionStates::iterator stateItr = _nonPhysicalKinematicEntities.begin();
|
||||
// TODO?: need to occasionally scan for stopped non-physical kinematics objects
|
||||
while (stateItr != _nonPhysicalKinematicEntities.end()) {
|
||||
ObjectMotionState* motionState = *stateItr;
|
||||
motionState->stepKinematicSimulation(now);
|
||||
++stateItr;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalEntitySimulation::stepNonPhysicalKinematics(const quint64& now) {
|
||||
SetOfMotionStates::iterator stateItr = _nonPhysicalKinematicEntities.begin();
|
||||
// TODO?: need to occasionally scan for stopped non-physical kinematics objects
|
||||
while (stateItr != _nonPhysicalKinematicEntities.end()) {
|
||||
ObjectMotionState* motionState = *stateItr;
|
||||
motionState->stepKinematicSimulation(now);
|
||||
++stateItr;
|
||||
}
|
||||
}
|
||||
*/
|
66
libraries/physics/src/PhysicalEntitySimulation.h
Normal file
66
libraries/physics/src/PhysicalEntitySimulation.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// PhysicalEntitySimulation.h
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.04.27
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_PhysicalEntitySimulation_h
|
||||
#define hifi_PhysicalEntitySimulation_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QSet>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
||||
|
||||
#include <EntityItem.h>
|
||||
#include <EntitySimulation.h>
|
||||
|
||||
#include "PhysicsEngine.h"
|
||||
|
||||
typedef QSet<EntityItem*> SetOfEntities;
|
||||
|
||||
class PhysicalEntitySimulation :public EntitySimulation {
|
||||
public:
|
||||
PhysicalEntitySimulation();
|
||||
~PhysicalEntitySimulation();
|
||||
|
||||
void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender);
|
||||
|
||||
// overrides for EntitySimulation
|
||||
void updateEntitiesInternal(const quint64& now);
|
||||
void addEntityInternal(EntityItem* entity);
|
||||
void removeEntityInternal(EntityItem* entity);
|
||||
void entityChangedInternal(EntityItem* entity);
|
||||
void sortEntitiesThatMovedInternal();
|
||||
void clearEntitiesInternal();
|
||||
|
||||
SetOfMotionState& getObjectsToRemove();
|
||||
SetOfMotionState& getObjectsToAdd();
|
||||
SetOfMotionState& getObjectsToUpdate();
|
||||
|
||||
void clearIncomingChanges();
|
||||
|
||||
private:
|
||||
void bump(EntityItem* bumpEntity);
|
||||
|
||||
SetOfEntities _pendingRemoves; // entities to be removed from simulation
|
||||
SetOfEntities _pendingAdds; // entities to be be added to simulation
|
||||
SetOfEntities _pendingUpdates; // entities to be updated in simulation
|
||||
|
||||
SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine
|
||||
VectorOfMotionStates _tempSet; // temporary list valid immediately after call to getObjectsToRemove/Add/Update()
|
||||
|
||||
ShapeManager* _shapeManager = nullptr;
|
||||
PhysicsEngine* _physicsEngine = nullptr;
|
||||
EntityEditPacketSender* _entityPacketSender = nullptr;
|
||||
|
||||
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
|
||||
};
|
||||
|
||||
#endif // hifi_PhysicalEntitySimulation_h
|
Loading…
Reference in a new issue