mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
track EntityItem adds to physcis with pending shape
This commit is contained in:
parent
deee159892
commit
3c8c68d187
6 changed files with 133 additions and 32 deletions
|
@ -323,7 +323,7 @@ public:
|
||||||
bool getDynamic() const;
|
bool getDynamic() const;
|
||||||
void setDynamic(bool value);
|
void setDynamic(bool value);
|
||||||
|
|
||||||
virtual bool shouldBePhysical() const { return !isDead(); }
|
virtual bool shouldBePhysical() const { return !isDead() && getShapeType() != SHAPE_TYPE_NONE; }
|
||||||
bool isVisuallyReady() const { return _visuallyReady; }
|
bool isVisuallyReady() const { return _visuallyReady; }
|
||||||
|
|
||||||
bool getLocked() const;
|
bool getLocked() const;
|
||||||
|
|
|
@ -230,19 +230,16 @@ void PhysicalEntitySimulation::prepareEntityForDelete(EntityItemPointer entity)
|
||||||
const VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemoveFromPhysics() {
|
const VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemoveFromPhysics() {
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
for (auto entity: _entitiesToRemoveFromPhysics) {
|
for (auto entity: _entitiesToRemoveFromPhysics) {
|
||||||
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
|
_entitiesToAddToPhysics.remove(entity);
|
||||||
assert(motionState);
|
if (entity->isDead() && entity->getElement()) {
|
||||||
// TODO CLEan this, just a n extra check to avoid the crash that shouldn;t happen
|
_deadEntities.insert(entity);
|
||||||
if (motionState) {
|
}
|
||||||
_entitiesToAddToPhysics.remove(entity);
|
|
||||||
if (entity->isDead() && entity->getElement()) {
|
|
||||||
_deadEntities.insert(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
|
||||||
|
if (motionState) {
|
||||||
_incomingChanges.remove(motionState);
|
_incomingChanges.remove(motionState);
|
||||||
removeOwnershipData(motionState);
|
removeOwnershipData(motionState);
|
||||||
_physicalObjects.remove(motionState);
|
_physicalObjects.remove(motionState);
|
||||||
|
|
||||||
// remember this motionState and delete it later (after removing its RigidBody from the PhysicsEngine)
|
// remember this motionState and delete it later (after removing its RigidBody from the PhysicsEngine)
|
||||||
_objectsToDelete.push_back(motionState);
|
_objectsToDelete.push_back(motionState);
|
||||||
}
|
}
|
||||||
|
@ -264,7 +261,75 @@ void PhysicalEntitySimulation::deleteObjectsRemovedFromPhysics() {
|
||||||
|
|
||||||
void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& result) {
|
void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& result) {
|
||||||
result.clear();
|
result.clear();
|
||||||
|
|
||||||
|
// this lambda for when we decide to actually build the motionState
|
||||||
|
auto buildMotionState = [&](btCollisionShape* shape, EntityItemPointer entity) {
|
||||||
|
EntityMotionState* motionState = new EntityMotionState(shape, entity);
|
||||||
|
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||||
|
motionState->setRegion(_space->getRegion(entity->getSpaceIndex()));
|
||||||
|
_physicalObjects.insert(motionState);
|
||||||
|
result.push_back(motionState);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// (1) make all changes to MotionState in "managers" (PhysicalEntitySimulation and AvatarManager)
|
||||||
|
// (2) store relevant change-flags on MotionState (maybe just EASY or HARD?)
|
||||||
|
// (3) remove knowledge of PhysicsEngine from ObjectMotionState
|
||||||
|
// (4) instead PhysicsEngine gets list of changed MotionStates, reads change-flags and applies changes accordingly
|
||||||
|
|
||||||
QMutexLocker lock(&_mutex);
|
QMutexLocker lock(&_mutex);
|
||||||
|
uint32_t deliveryCount = ObjectMotionState::getShapeManager()->getWorkDeliveryCount();
|
||||||
|
if (deliveryCount != _lastWorkDeliveryCount) {
|
||||||
|
// new off-thread shapes have arrived --> find adds whose shapes have arrived
|
||||||
|
_lastWorkDeliveryCount = deliveryCount;
|
||||||
|
ShapeRequests::iterator requestItr = _shapeRequests.begin();
|
||||||
|
while (requestItr != _shapeRequests.end()) {
|
||||||
|
EntityItemPointer entity = requestItr->entity;
|
||||||
|
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
|
||||||
|
if (!motionState) {
|
||||||
|
// this is an ADD because motionState doesn't exist yet
|
||||||
|
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShapeByKey(requestItr->shapeHash));
|
||||||
|
if (shape) {
|
||||||
|
// shape is ready at last!
|
||||||
|
// But the entity's desired shape might have changed since last requested
|
||||||
|
// --> rebuild the ShapeInfo to verify hash
|
||||||
|
// TODO? is there a better way to do this?
|
||||||
|
ShapeInfo shapeInfo;
|
||||||
|
entity->computeShapeInfo(shapeInfo);
|
||||||
|
if (shapeInfo.getHash() != requestItr->shapeHash) {
|
||||||
|
// bummer, the hashes are different and we no longer want the shape we've received
|
||||||
|
ObjectMotionState::getShapeManager()->releaseShape(shape);
|
||||||
|
// try again
|
||||||
|
shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||||
|
if (shape) {
|
||||||
|
buildMotionState(shape, entity);
|
||||||
|
requestItr = _shapeRequests.erase(requestItr);
|
||||||
|
} else {
|
||||||
|
requestItr->shapeHash = shapeInfo.getHash();
|
||||||
|
++requestItr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buildMotionState(shape, entity);
|
||||||
|
requestItr = _shapeRequests.erase(requestItr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// shape not ready
|
||||||
|
++requestItr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// this is a CHANGE because motionState already exists
|
||||||
|
if (ObjectMotionState::getShapeManager()->hasShapeWithKey(requestItr->shapeHash)) {
|
||||||
|
// TODO? reset DIRTY_SHAPE flag?
|
||||||
|
_incomingChanges.insert(motionState);
|
||||||
|
requestItr = _shapeRequests.erase(requestItr);
|
||||||
|
} else {
|
||||||
|
// shape not ready
|
||||||
|
++requestItr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetOfEntities::iterator entityItr = _entitiesToAddToPhysics.begin();
|
SetOfEntities::iterator entityItr = _entitiesToAddToPhysics.begin();
|
||||||
while (entityItr != _entitiesToAddToPhysics.end()) {
|
while (entityItr != _entitiesToAddToPhysics.end()) {
|
||||||
EntityItemPointer entity = (*entityItr);
|
EntityItemPointer entity = (*entityItr);
|
||||||
|
@ -282,30 +347,25 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (entity->isReadyToComputeShape()) {
|
} else if (entity->isReadyToComputeShape()) {
|
||||||
ShapeInfo shapeInfo;
|
// check to see if we're waiting for a shape
|
||||||
entity->computeShapeInfo(shapeInfo);
|
ShapeRequest shapeRequest(entity);
|
||||||
int numPoints = shapeInfo.getLargestSubshapePointCount();
|
ShapeRequests::iterator requestItr = _shapeRequests.find(shapeRequest);
|
||||||
if (shapeInfo.getType() == SHAPE_TYPE_COMPOUND) {
|
if (requestItr == _shapeRequests.end()) {
|
||||||
if (numPoints > MAX_HULL_POINTS) {
|
ShapeInfo shapeInfo;
|
||||||
qWarning() << "convex hull with" << numPoints
|
entity->computeShapeInfo(shapeInfo);
|
||||||
<< "points for entity" << entity->getName()
|
uint32_t requestCount = ObjectMotionState::getShapeManager()->getWorkRequestCount();
|
||||||
<< "at" << entity->getWorldPosition() << " will be reduced";
|
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||||
|
if (shape) {
|
||||||
|
buildMotionState(shape, entity);
|
||||||
|
} else if (requestCount != ObjectMotionState::getShapeManager()->getWorkRequestCount()) {
|
||||||
|
// shape doesn't exist but a new worker has been spawned to build it --> add to shapeRequests and wait
|
||||||
|
shapeRequest.shapeHash = shapeInfo.getHash();
|
||||||
|
_shapeRequests.insert(shapeRequest);
|
||||||
|
} else {
|
||||||
|
// failed to build shape --> will not be added
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
entityItr = _entitiesToAddToPhysics.erase(entityItr);
|
||||||
if (shape) {
|
|
||||||
EntityMotionState* motionState = new EntityMotionState(shape, entity);
|
|
||||||
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
|
||||||
_physicalObjects.insert(motionState);
|
|
||||||
result.push_back(motionState);
|
|
||||||
entityItr = _entitiesToAddToPhysics.erase(entityItr);
|
|
||||||
|
|
||||||
// make sure the motionState's region is up-to-date before it is actually added to physics
|
|
||||||
motionState->setRegion(_space->getRegion(entity->getSpaceIndex()));
|
|
||||||
} else {
|
|
||||||
//qWarning() << "Failed to generate new shape for entity." << entity->getName();
|
|
||||||
++entityItr;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
++entityItr;
|
++entityItr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_PhysicalEntitySimulation_h
|
#define hifi_PhysicalEntitySimulation_h
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <btBulletDynamicsCommon.h>
|
#include <btBulletDynamicsCommon.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
||||||
|
@ -98,6 +99,15 @@ public:
|
||||||
void sendOwnedUpdates(uint32_t numSubsteps);
|
void sendOwnedUpdates(uint32_t numSubsteps);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class ShapeRequest {
|
||||||
|
public:
|
||||||
|
ShapeRequest() : entity(), shapeHash(0) {}
|
||||||
|
ShapeRequest(const EntityItemPointer& e) : entity(e), shapeHash(0) {}
|
||||||
|
bool operator<(const ShapeRequest& other) const { return entity.get() < other.entity.get(); }
|
||||||
|
bool operator==(const ShapeRequest& other) const { return entity.get() == other.entity.get(); }
|
||||||
|
EntityItemPointer entity;
|
||||||
|
mutable uint64_t shapeHash;
|
||||||
|
};
|
||||||
SetOfEntities _entitiesToAddToPhysics;
|
SetOfEntities _entitiesToAddToPhysics;
|
||||||
SetOfEntities _entitiesToRemoveFromPhysics;
|
SetOfEntities _entitiesToRemoveFromPhysics;
|
||||||
|
|
||||||
|
@ -108,6 +118,9 @@ private:
|
||||||
|
|
||||||
SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine
|
SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine
|
||||||
|
|
||||||
|
using ShapeRequests = std::set<ShapeRequest>;
|
||||||
|
ShapeRequests _shapeRequests;
|
||||||
|
|
||||||
PhysicsEnginePointer _physicsEngine = nullptr;
|
PhysicsEnginePointer _physicsEngine = nullptr;
|
||||||
EntityEditPacketSender* _entityPacketSender = nullptr;
|
EntityEditPacketSender* _entityPacketSender = nullptr;
|
||||||
|
|
||||||
|
@ -117,6 +130,7 @@ private:
|
||||||
workload::SpacePointer _space;
|
workload::SpacePointer _space;
|
||||||
uint64_t _nextBidExpiry;
|
uint64_t _nextBidExpiry;
|
||||||
uint32_t _lastStepSendPackets { 0 };
|
uint32_t _lastStepSendPackets { 0 };
|
||||||
|
uint32_t _lastWorkDeliveryCount { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -433,6 +433,8 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (shape) {
|
if (shape) {
|
||||||
if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) {
|
if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
||||||
if (itr == _pendingMeshShapes.end()) {
|
if (itr == _pendingMeshShapes.end()) {
|
||||||
// start a worker
|
// start a worker
|
||||||
_pendingMeshShapes.push_back(hash);
|
_pendingMeshShapes.push_back(hash);
|
||||||
|
++_workRequestCount;
|
||||||
// try to recycle old deadWorker
|
// try to recycle old deadWorker
|
||||||
ShapeFactory::Worker* worker = _deadWorker;
|
ShapeFactory::Worker* worker = _deadWorker;
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
|
@ -76,6 +77,22 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const btCollisionShape* ShapeManager::getShapeByKey(uint64_t key) {
|
||||||
|
HashKey hashKey(key);
|
||||||
|
ShapeReference* shapeRef = _shapeMap.find(hashKey);
|
||||||
|
if (shapeRef) {
|
||||||
|
shapeRef->refCount++;
|
||||||
|
return shapeRef->shape;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeManager::hasShapeWithKey(uint64_t key) const {
|
||||||
|
HashKey hashKey(key);
|
||||||
|
const ShapeReference* shapeRef = _shapeMap.find(hashKey);
|
||||||
|
return (bool)shapeRef;
|
||||||
|
}
|
||||||
|
|
||||||
void ShapeManager::addToGarbage(uint64_t key) {
|
void ShapeManager::addToGarbage(uint64_t key) {
|
||||||
// look for existing entry in _garbageRing
|
// look for existing entry in _garbageRing
|
||||||
int32_t ringSize = (int32_t)(_garbageRing.size());
|
int32_t ringSize = (int32_t)(_garbageRing.size());
|
||||||
|
@ -249,4 +266,5 @@ void ShapeManager::acceptWork(ShapeFactory::Worker* worker) {
|
||||||
worker->shapeInfo.clear();
|
worker->shapeInfo.clear();
|
||||||
worker->shape = nullptr;
|
worker->shape = nullptr;
|
||||||
_deadWorker = worker;
|
_deadWorker = worker;
|
||||||
|
++_workDeliveryCount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_ShapeManager_h
|
#ifndef hifi_ShapeManager_h
|
||||||
#define hifi_ShapeManager_h
|
#define hifi_ShapeManager_h
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
@ -55,6 +56,8 @@ public:
|
||||||
|
|
||||||
/// \return pointer to shape
|
/// \return pointer to shape
|
||||||
const btCollisionShape* getShape(const ShapeInfo& info);
|
const btCollisionShape* getShape(const ShapeInfo& info);
|
||||||
|
const btCollisionShape* getShapeByKey(uint64_t key);
|
||||||
|
bool hasShapeWithKey(uint64_t key) const;
|
||||||
|
|
||||||
/// \return true if shape was found and released
|
/// \return true if shape was found and released
|
||||||
bool releaseShape(const btCollisionShape* shape);
|
bool releaseShape(const btCollisionShape* shape);
|
||||||
|
@ -67,6 +70,8 @@ public:
|
||||||
int getNumReferences(const ShapeInfo& info) const;
|
int getNumReferences(const ShapeInfo& info) const;
|
||||||
int getNumReferences(const btCollisionShape* shape) const;
|
int getNumReferences(const btCollisionShape* shape) const;
|
||||||
bool hasShape(const btCollisionShape* shape) const;
|
bool hasShape(const btCollisionShape* shape) const;
|
||||||
|
uint32_t getWorkRequestCount() const { return _workRequestCount; }
|
||||||
|
uint32_t getWorkDeliveryCount() const { return _workDeliveryCount; }
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void acceptWork(ShapeFactory::Worker* worker);
|
void acceptWork(ShapeFactory::Worker* worker);
|
||||||
|
@ -99,6 +104,8 @@ private:
|
||||||
ShapeFactory::Worker* _deadWorker { nullptr };
|
ShapeFactory::Worker* _deadWorker { nullptr };
|
||||||
TimePoint _nextOrphanExpiry;
|
TimePoint _nextOrphanExpiry;
|
||||||
uint32_t _ringIndex { 0 };
|
uint32_t _ringIndex { 0 };
|
||||||
|
std::atomic_uint32_t _workRequestCount { 0 };
|
||||||
|
std::atomic_uint32_t _workDeliveryCount { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ShapeManager_h
|
#endif // hifi_ShapeManager_h
|
||||||
|
|
Loading…
Reference in a new issue