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() {
}
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)

View file

@ -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;

View file

@ -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<EntityItemID>& 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();

View file

@ -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) {
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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);