From 2f9a35412f91ec7826900d525f9bd9c89291353b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Nov 2014 15:56:52 -0800 Subject: [PATCH] initial support for STATIC and KINEMATIC motion --- libraries/entities/src/EntityMotionState.cpp | 7 ++ libraries/entities/src/EntityMotionState.h | 2 + libraries/entities/src/EntityTree.cpp | 24 ++-- libraries/physics/src/CustomMotionState.cpp | 3 +- libraries/physics/src/CustomMotionState.h | 9 +- libraries/physics/src/PhysicsWorld.cpp | 118 +++++++++++++++++-- libraries/physics/src/PhysicsWorld.h | 8 +- 7 files changed, 147 insertions(+), 24 deletions(-) diff --git a/libraries/entities/src/EntityMotionState.cpp b/libraries/entities/src/EntityMotionState.cpp index 26349290ea..be15f1cfe9 100644 --- a/libraries/entities/src/EntityMotionState.cpp +++ b/libraries/entities/src/EntityMotionState.cpp @@ -37,6 +37,13 @@ EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { EntityMotionState::~EntityMotionState() { } +MotionType EntityMotionState::getMotionType() const { + // HACK: According to EntityTree the meaning of "static" is "not moving" whereas + // to Bullet it means "can't move". For demo purposes we temporarily interpret + // Entity::weightless to mean Bullet::static. + return _entity->hasGravity() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC; +} + // This callback is invoked by the physics simulation in two cases: // (1) when the RigidBody is first added to the world // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) diff --git a/libraries/entities/src/EntityMotionState.h b/libraries/entities/src/EntityMotionState.h index c80df13f7e..3b69abcd9d 100644 --- a/libraries/entities/src/EntityMotionState.h +++ b/libraries/entities/src/EntityMotionState.h @@ -27,6 +27,8 @@ public: EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); + MotionType getMotionType() const; + void getWorldTransform (btTransform &worldTrans) const; void setWorldTransform (const btTransform &worldTrans); void applyVelocities() const; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 97647501ea..967d45b5af 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -77,9 +77,9 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons } /// Adds a new entity item to the tree -void EntityTree::addEntityItem(EntityItem* entityItem) { +void EntityTree::addEntityItem(EntityItem* entity) { // You should not call this on existing entities that are already part of the tree! Call updateEntity() - EntityItemID entityID = entityItem->getEntityItemID(); + EntityItemID entityID = entity->getEntityItemID(); EntityTreeElement* containingElement = getContainingElement(entityID); if (containingElement) { qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing entity items. entityID=" << entityID; @@ -87,12 +87,15 @@ void EntityTree::addEntityItem(EntityItem* entityItem) { } // Recurse the tree and store the entity in the correct tree element - AddEntityOperator theOperator(this, entityItem); + AddEntityOperator theOperator(this, entity); recurseTreeWithOperator(&theOperator); // check to see if we need to simulate this entity.. - // BOOKMARK -- add entity to physics engine here - changeEntityState(entityItem, EntityItem::Static, entityItem->getSimulationState()); + changeEntityState(entity, EntityItem::Static, entity->getSimulationState()); + + if (_physicsWorld && !entity->getMotionState()) { + addEntityToPhysicsWorld(entity); + } _isDirty = true; } @@ -530,7 +533,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char // search for the entity by EntityItemID EntityItem* existingEntity = findEntityByEntityItemID(entityItemID); - // if the entityItem exists, then update it + // if the EntityItem exists, then update it if (existingEntity) { updateEntity(entityItemID, properties); existingEntity->markAsChangedOnServer(); @@ -621,9 +624,6 @@ void EntityTree::changeEntityState(EntityItem* const entity, case EntityItem::Moving: _movingEntities.push_back(entity); - if (_physicsWorld && !entity->getMotionState()) { - addEntityToPhysicsWorld(entity); - } break; case EntityItem::Mortal: @@ -683,7 +683,11 @@ void EntityTree::updateChangingEntities(quint64 now, QSet& entitie // TODO: switch these to iterators so we can remove items that get deleted for (int i = 0; i < _changingEntities.size(); i++) { EntityItem* thisEntity = _changingEntities[i]; - thisEntity->update(now); + EntityMotionState* motionState = thisEntity->getMotionState(); + if (!motionState) { + thisEntity->update(now); + } + // always check to see if the lifetime has expired, for immortal entities this is always false if (thisEntity->lifetimeHasExpired()) { qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); diff --git a/libraries/physics/src/CustomMotionState.cpp b/libraries/physics/src/CustomMotionState.cpp index 5ccca75ab4..743ed26614 100644 --- a/libraries/physics/src/CustomMotionState.cpp +++ b/libraries/physics/src/CustomMotionState.cpp @@ -34,7 +34,8 @@ CustomMotionState::CustomMotionState() : _volume(DEFAULT_VOLUME), _friction(DEFAULT_FRICTION), _restitution(DEFAULT_RESTITUTION), - _motionType(MOTION_TYPE_STATIC), + _wasInWorld(false), + _motionType(MOTION_TYPE_STATIC), _body(NULL) { } diff --git a/libraries/physics/src/CustomMotionState.h b/libraries/physics/src/CustomMotionState.h index 87e911f879..7db25d3899 100644 --- a/libraries/physics/src/CustomMotionState.h +++ b/libraries/physics/src/CustomMotionState.h @@ -38,7 +38,7 @@ public: virtual void computeShapeInfo(ShapeInfo& info) = 0; - MotionType getMotionType() const { return _motionType; } + virtual MotionType getMotionType() const { return _motionType; } void setDensity(float density); void setFriction(float friction); @@ -54,15 +54,16 @@ public: void getAngularVelocity(glm::vec3& angularVelocityOut) const; friend class PhysicsWorld; -protected: +protected: float _density; float _volume; float _friction; float _restitution; - - // The data members below have NO setters. They are only changed by a PhysicsWorld instance. + bool _wasInWorld; MotionType _motionType; + + // _body has NO setters -- it is only changed by PhysicsWorld btRigidBody* _body; }; diff --git a/libraries/physics/src/PhysicsWorld.cpp b/libraries/physics/src/PhysicsWorld.cpp index b49fd8d802..518989c81f 100644 --- a/libraries/physics/src/PhysicsWorld.cpp +++ b/libraries/physics/src/PhysicsWorld.cpp @@ -23,6 +23,26 @@ void PhysicsWorld::init() { _broadphaseFilter = new btDbvtBroadphase(); _constraintSolver = new btSequentialImpulseConstraintSolver; _dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + + // TODO: once the initial physics system is working we will set gravity of the world to be zero + // and each object will have to specify its own local gravity, or we'll set up gravity zones. + //_dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + // + // GROUND HACK: In the meantime we add a big planar floor to catch falling objects + // NOTE: we don't care about memory leaking groundShape and groundObject --> + // they'll exist until the executable exits. + const float halfSide = 200.0f; + const float halfHeight = 10.0f; + + btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide)); + btTransform groundTransform; + groundTransform.setIdentity(); + groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide)); + + btCollisionObject* groundObject = new btCollisionObject(); + groundObject->setCollisionShape(groundShape); + groundObject->setWorldTransform(groundTransform); + _dynamicsWorld->addCollisionObject(groundObject); } } @@ -93,19 +113,103 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) { return false; } +// Bullet collision flags are as follows: +// CF_STATIC_OBJECT= 1, +// CF_KINEMATIC_OBJECT= 2, +// CF_NO_CONTACT_RESPONSE = 4, +// CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution) +// CF_CHARACTER_OBJECT = 16, +// CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing +// CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing + bool PhysicsWorld::addEntity(CustomMotionState* motionState) { assert(motionState); ShapeInfo info; motionState->computeShapeInfo(info); btCollisionShape* shape = _shapeManager.getShape(info); if (shape) { - btVector3 inertia; - float mass = motionState->getMass(); - shape->calculateLocalInertia(mass, inertia); - btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); - motionState->_body = body; - motionState->applyVelocities(); - // TODO: set dynamic/kinematic/static property from data stored in motionState + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = 0.0f; + btRigidBody* body = NULL; + switch(motionState->_motionType) { + case MOTION_TYPE_KINEMATIC: { + body = new btRigidBody(mass, motionState, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->setActivationState(DISABLE_DEACTIVATION); + body->updateInertiaTensor(); + motionState->_body = body; + break; + } + case MOTION_TYPE_DYNAMIC: { + mass = motionState->getMass(); + shape->calculateLocalInertia(mass, inertia); + body = new btRigidBody(mass, motionState, shape, inertia); + body->updateInertiaTensor(); + motionState->_body = body; + motionState->applyVelocities(); + break; + } + default: { + // MOTION_TYPE_STATIC + body = new btRigidBody(mass, motionState, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + motionState->_body = body; + break; + } + } + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); + _dynamicsWorld->addRigidBody(body); + return true; + } + return false; +} + +bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState) { + btRigidBody* body = motionState->_body; + if (!body) { + return false; + } + + MotionType oldType = MOTION_TYPE_DYNAMIC; + if (body->isStaticObject()) { + oldType = MOTION_TYPE_STATIC; + } else if (body->isKinematicObject()) { + oldType = MOTION_TYPE_KINEMATIC; + } + MotionType newType = motionState->getMotionType(); + if (oldType != newType) { + // pull body out of physics engine + _dynamicsWorld->removeRigidBody(body); + + // update various properties and flags + switch (newType) { + case MOTION_TYPE_KINEMATIC: { + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->setActivationState(DISABLE_DEACTIVATION); + body->updateInertiaTensor(); + break; + } + case MOTION_TYPE_DYNAMIC: { + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = motionState->getMass(); + body->getCollisionShape()->calculateLocalInertia(mass, inertia); + body->updateInertiaTensor(); + motionState->applyVelocities(); + break; + } + default: { + // MOTION_TYPE_STATIC + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + break; + } + } + + // reinsert body into physics engine + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); _dynamicsWorld->addRigidBody(body); return true; } diff --git a/libraries/physics/src/PhysicsWorld.h b/libraries/physics/src/PhysicsWorld.h index 04d0563f84..1ff06c9c5d 100644 --- a/libraries/physics/src/PhysicsWorld.h +++ b/libraries/physics/src/PhysicsWorld.h @@ -59,11 +59,15 @@ public: /// \return true if Voxel removed bool removeVoxel(const glm::vec3& position, float scale); - /// \param info information about collision shapes to create + /// \param motionState pointer to Entity's MotionState /// \return true if Entity added bool addEntity(CustomMotionState* motionState); - /// \param id UUID of the entity + /// \param motionState pointer to Entity's MotionState + /// \return true if entity updated + bool updateEntityMotionType(CustomMotionState* motionState); + + /// \param motionState pointer to Entity's MotionState /// \return true if Entity removed bool removeEntity(CustomMotionState* motionState);