initial support for STATIC and KINEMATIC motion

This commit is contained in:
Andrew Meadows 2014-11-14 15:56:52 -08:00
parent bd34ac4357
commit 2f9a35412f
7 changed files with 147 additions and 24 deletions

View file

@ -37,6 +37,13 @@ EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) {
EntityMotionState::~EntityMotionState() { 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: // This callback is invoked by the physics simulation in two cases:
// (1) when the RigidBody is first added to the world // (1) when the RigidBody is first added to the world
// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) // (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC)

View file

@ -27,6 +27,8 @@ public:
EntityMotionState(EntityItem* item); EntityMotionState(EntityItem* item);
virtual ~EntityMotionState(); virtual ~EntityMotionState();
MotionType getMotionType() const;
void getWorldTransform (btTransform &worldTrans) const; void getWorldTransform (btTransform &worldTrans) const;
void setWorldTransform (const btTransform &worldTrans); void setWorldTransform (const btTransform &worldTrans);
void applyVelocities() const; void applyVelocities() const;

View file

@ -77,9 +77,9 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons
} }
/// Adds a new entity item to the tree /// 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() // 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); EntityTreeElement* containingElement = getContainingElement(entityID);
if (containingElement) { if (containingElement) {
qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing entity items. entityID=" << entityID; 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 // Recurse the tree and store the entity in the correct tree element
AddEntityOperator theOperator(this, entityItem); AddEntityOperator theOperator(this, entity);
recurseTreeWithOperator(&theOperator); recurseTreeWithOperator(&theOperator);
// check to see if we need to simulate this entity.. // check to see if we need to simulate this entity..
// BOOKMARK -- add entity to physics engine here changeEntityState(entity, EntityItem::Static, entity->getSimulationState());
changeEntityState(entityItem, EntityItem::Static, entityItem->getSimulationState());
if (_physicsWorld && !entity->getMotionState()) {
addEntityToPhysicsWorld(entity);
}
_isDirty = true; _isDirty = true;
} }
@ -530,7 +533,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
// search for the entity by EntityItemID // search for the entity by EntityItemID
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID); EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
// if the entityItem exists, then update it // if the EntityItem exists, then update it
if (existingEntity) { if (existingEntity) {
updateEntity(entityItemID, properties); updateEntity(entityItemID, properties);
existingEntity->markAsChangedOnServer(); existingEntity->markAsChangedOnServer();
@ -621,9 +624,6 @@ void EntityTree::changeEntityState(EntityItem* const entity,
case EntityItem::Moving: case EntityItem::Moving:
_movingEntities.push_back(entity); _movingEntities.push_back(entity);
if (_physicsWorld && !entity->getMotionState()) {
addEntityToPhysicsWorld(entity);
}
break; break;
case EntityItem::Mortal: case EntityItem::Mortal:
@ -683,7 +683,11 @@ void EntityTree::updateChangingEntities(quint64 now, QSet<EntityItemID>& entitie
// TODO: switch these to iterators so we can remove items that get deleted // TODO: switch these to iterators so we can remove items that get deleted
for (int i = 0; i < _changingEntities.size(); i++) { for (int i = 0; i < _changingEntities.size(); i++) {
EntityItem* thisEntity = _changingEntities[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 // always check to see if the lifetime has expired, for immortal entities this is always false
if (thisEntity->lifetimeHasExpired()) { if (thisEntity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();

View file

@ -34,7 +34,8 @@ CustomMotionState::CustomMotionState() :
_volume(DEFAULT_VOLUME), _volume(DEFAULT_VOLUME),
_friction(DEFAULT_FRICTION), _friction(DEFAULT_FRICTION),
_restitution(DEFAULT_RESTITUTION), _restitution(DEFAULT_RESTITUTION),
_motionType(MOTION_TYPE_STATIC), _wasInWorld(false),
_motionType(MOTION_TYPE_STATIC),
_body(NULL) { _body(NULL) {
} }

View file

@ -38,7 +38,7 @@ public:
virtual void computeShapeInfo(ShapeInfo& info) = 0; virtual void computeShapeInfo(ShapeInfo& info) = 0;
MotionType getMotionType() const { return _motionType; } virtual MotionType getMotionType() const { return _motionType; }
void setDensity(float density); void setDensity(float density);
void setFriction(float friction); void setFriction(float friction);
@ -54,15 +54,16 @@ public:
void getAngularVelocity(glm::vec3& angularVelocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const;
friend class PhysicsWorld; friend class PhysicsWorld;
protected:
protected:
float _density; float _density;
float _volume; float _volume;
float _friction; float _friction;
float _restitution; float _restitution;
bool _wasInWorld;
// The data members below have NO setters. They are only changed by a PhysicsWorld instance.
MotionType _motionType; MotionType _motionType;
// _body has NO setters -- it is only changed by PhysicsWorld
btRigidBody* _body; btRigidBody* _body;
}; };

View file

@ -23,6 +23,26 @@ void PhysicsWorld::init() {
_broadphaseFilter = new btDbvtBroadphase(); _broadphaseFilter = new btDbvtBroadphase();
_constraintSolver = new btSequentialImpulseConstraintSolver; _constraintSolver = new btSequentialImpulseConstraintSolver;
_dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); _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; 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) { bool PhysicsWorld::addEntity(CustomMotionState* motionState) {
assert(motionState); assert(motionState);
ShapeInfo info; ShapeInfo info;
motionState->computeShapeInfo(info); motionState->computeShapeInfo(info);
btCollisionShape* shape = _shapeManager.getShape(info); btCollisionShape* shape = _shapeManager.getShape(info);
if (shape) { if (shape) {
btVector3 inertia; btVector3 inertia(0.0f, 0.0f, 0.0f);
float mass = motionState->getMass(); float mass = 0.0f;
shape->calculateLocalInertia(mass, inertia); btRigidBody* body = NULL;
btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia); switch(motionState->_motionType) {
motionState->_body = body; case MOTION_TYPE_KINEMATIC: {
motionState->applyVelocities(); body = new btRigidBody(mass, motionState, shape, inertia);
// TODO: set dynamic/kinematic/static property from data stored in motionState 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); _dynamicsWorld->addRigidBody(body);
return true; return true;
} }

View file

@ -59,11 +59,15 @@ public:
/// \return true if Voxel removed /// \return true if Voxel removed
bool removeVoxel(const glm::vec3& position, float scale); 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 /// \return true if Entity added
bool addEntity(CustomMotionState* motionState); 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 /// \return true if Entity removed
bool removeEntity(CustomMotionState* motionState); bool removeEntity(CustomMotionState* motionState);