Merge pull request #4089 from AndrewMeadows/inertia

fix glitchy entity motion in Bullet simulation
This commit is contained in:
Brad Hefta-Gaub 2015-01-13 17:10:35 -08:00
commit 284ee32b7b
10 changed files with 179 additions and 138 deletions

View file

@ -35,25 +35,25 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_created = UNKNOWN_CREATED_TIME;
_changedOnServer = 0;
_position = glm::vec3(0,0,0);
_dimensions = DEFAULT_DIMENSIONS;
_rotation = DEFAULT_ROTATION;
_glowLevel = DEFAULT_GLOW_LEVEL;
_localRenderAlpha = DEFAULT_LOCAL_RENDER_ALPHA;
_mass = DEFAULT_MASS;
_velocity = DEFAULT_VELOCITY;
_gravity = DEFAULT_GRAVITY;
_damping = DEFAULT_DAMPING;
_lifetime = DEFAULT_LIFETIME;
_script = DEFAULT_SCRIPT;
_registrationPoint = DEFAULT_REGISTRATION_POINT;
_angularVelocity = DEFAULT_ANGULAR_VELOCITY;
_angularDamping = DEFAULT_ANGULAR_DAMPING;
_visible = DEFAULT_VISIBLE;
_ignoreForCollisions = DEFAULT_IGNORE_FOR_COLLISIONS;
_collisionsWillMove = DEFAULT_COLLISIONS_WILL_MOVE;
_locked = DEFAULT_LOCKED;
_userData = DEFAULT_USER_DATA;
_position = ENTITY_ITEM_ZERO_VEC3;
_dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS;
_rotation = ENTITY_ITEM_DEFAULT_ROTATION;
_glowLevel = ENTITY_ITEM_DEFAULT_GLOW_LEVEL;
_localRenderAlpha = ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA;
_mass = ENTITY_ITEM_DEFAULT_MASS;
_velocity = ENTITY_ITEM_DEFAULT_VELOCITY;
_gravity = ENTITY_ITEM_DEFAULT_GRAVITY;
_damping = ENTITY_ITEM_DEFAULT_DAMPING;
_lifetime = ENTITY_ITEM_DEFAULT_LIFETIME;
_script = ENTITY_ITEM_DEFAULT_SCRIPT;
_registrationPoint = ENTITY_ITEM_DEFAULT_REGISTRATION_POINT;
_angularVelocity = ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY;
_angularDamping = ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING;
_visible = ENTITY_ITEM_DEFAULT_VISIBLE;
_ignoreForCollisions = ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS;
_collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE;
_locked = ENTITY_ITEM_DEFAULT_LOCKED;
_userData = ENTITY_ITEM_DEFAULT_USER_DATA;
recalculateCollisionShape();
}
@ -555,6 +555,8 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
}
}
const float ENTITY_ITEM_EPSILON_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE;
// TODO: we probably want to change this to make "down" be the direction of the entity's gravity vector
// for now, this is always true DOWN even if entity has non-down gravity.
// TODO: the old code had "&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON" --- what was I thinking?
@ -562,7 +564,7 @@ bool EntityItem::isRestingOnSurface() const {
glm::vec3 downwardVelocity = glm::vec3(0.0f, _velocity.y, 0.0f);
return _position.y <= getDistanceToBottomOfEntity()
&& (glm::length(downwardVelocity) <= EPSILON_VELOCITY_LENGTH)
&& (glm::length(downwardVelocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH)
&& _gravity.y < 0.0f;
}
@ -639,7 +641,7 @@ void EntityItem::simulate(const quint64& now) {
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; //
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
setAngularVelocity(NO_ANGULAR_VELOCITY);
setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
} else {
// NOTE: angularSpeed is currently in degrees/sec!!!
// TODO: Andrew to convert to radians/sec
@ -668,7 +670,7 @@ void EntityItem::simulate(const quint64& now) {
qDebug() << " damping:" << _damping;
qDebug() << " velocity AFTER dampingResistance:" << velocity;
qDebug() << " glm::length(velocity):" << glm::length(velocity);
qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH;
qDebug() << " velocityEspilon :" << ENTITY_ITEM_EPSILON_VELOCITY_LENGTH;
}
}
@ -696,8 +698,8 @@ void EntityItem::simulate(const quint64& now) {
#ifndef USE_BULLET_PHYSICS
// if we've slowed considerably, then just stop moving, but only if no BULLET
if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
velocity = NO_VELOCITY;
if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) {
velocity = ENTITY_ITEM_ZERO_VEC3;
}
#endif // !USE_BULLET_PHYSICS
@ -720,8 +722,8 @@ void EntityItem::simulate(const quint64& now) {
// When Bullet is available we assume that it will tell us when velocities go to zero...
#else // !USE_BULLET_PHYSICS
// ... otherwise we help things come to rest by clamping small velocities.
if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
velocity = NO_VELOCITY;
if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) {
velocity = ENTITY_ITEM_ZERO_VEC3;
}
#endif // USE_BULLET_PHYSICS
@ -909,7 +911,7 @@ AACube EntityItem::getMinimumAACube() const {
// _position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
@ -934,7 +936,7 @@ AABox EntityItem::getAABox() const {
// _position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
@ -998,7 +1000,7 @@ void EntityItem::recalculateCollisionShape() {
const float MIN_POSITION_DELTA = 0.0001f;
const float MIN_ALIGNMENT_DOT = 0.9999f;
const float MIN_MASS_DELTA = 0.001f;
const float MIN_VELOCITY_DELTA = 0.025f;
const float MIN_VELOCITY_DELTA = 0.01f;
const float MIN_DAMPING_DELTA = 0.001f;
const float MIN_GRAVITY_DELTA = 0.001f;
const float MIN_SPIN_DELTA = 0.0003f;
@ -1055,7 +1057,7 @@ void EntityItem::updateMass(float value) {
void EntityItem::updateVelocity(const glm::vec3& value) {
if (glm::distance(_velocity, value) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) {
if (glm::length(value) * (float)TREE_SCALE < MIN_VELOCITY_DELTA) {
_velocity = glm::vec3(0.0f);
_velocity = ENTITY_ITEM_ZERO_VEC3;
} else {
_velocity = value;
}
@ -1067,7 +1069,7 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) {
glm::vec3 velocity = value / (float) TREE_SCALE;
if (glm::distance(_velocity, velocity) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) {
if (glm::length(value) < MIN_VELOCITY_DELTA) {
_velocity = glm::vec3(0.0f);
_velocity = ENTITY_ITEM_ZERO_VEC3;
} else {
_velocity = velocity;
}

View file

@ -26,6 +26,7 @@
#include "EntityItemID.h"
#include "EntityItemProperties.h"
#include "EntityItemPropertiesDefaults.h"
#include "EntityTypes.h"
class EntityTree;
@ -35,30 +36,6 @@ class EntityTreeElementExtraEncodeData;
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { };
const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f) / (float)TREE_SCALE;
const glm::quat DEFAULT_ROTATION;
const float DEFAULT_GLOW_LEVEL = 0.0f;
const float DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float DEFAULT_MASS = 1.0f;
const glm::vec3 NO_VELOCITY= glm::vec3(0.0f);
const glm::vec3 DEFAULT_VELOCITY = NO_VELOCITY;
const float EPSILON_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE;
const glm::vec3 NO_GRAVITY = glm::vec3(0.0f);
const glm::vec3 DEFAULT_GRAVITY = NO_GRAVITY;
const glm::vec3 REGULAR_GRAVITY = glm::vec3(0, -9.8f / (float)TREE_SCALE, 0);
const float DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header)
const float IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime
const float DEFAULT_LIFETIME = IMMORTAL;
const QString DEFAULT_SCRIPT = QString("");
const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center
const glm::vec3 NO_ANGULAR_VELOCITY = glm::vec3(0.0f);
const glm::vec3 DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY;
const float DEFAULT_ANGULAR_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header)
const bool DEFAULT_VISIBLE = true;
const bool DEFAULT_IGNORE_FOR_COLLISIONS = false;
const bool DEFAULT_COLLISIONS_WILL_MOVE = false;
const bool DEFAULT_LOCKED = false;
const QString DEFAULT_USER_DATA = QString("");
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
@ -201,13 +178,13 @@ public:
glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second
void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters
bool hasVelocity() const { return _velocity != NO_VELOCITY; }
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared
glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared
void setGravityInMeters(const glm::vec3& value) { _gravity = value / (float) TREE_SCALE; } /// gravity in meters
bool hasGravity() const { return _gravity != NO_GRAVITY; }
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
// TODO: this should eventually be updated to support resting on collisions with other surfaces
bool isRestingOnSurface() const;
@ -220,10 +197,10 @@ public:
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
/// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted
bool isImmortal() const { return _lifetime == IMMORTAL; }
bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; }
/// is this entity mortal, in that it has a lifetime set, and will automatically be deleted when that lifetime expires
bool isMortal() const { return _lifetime != IMMORTAL; }
bool isMortal() const { return _lifetime != ENTITY_ITEM_IMMORTAL_LIFETIME; }
/// age of this entity in seconds
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
@ -247,7 +224,7 @@ public:
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; }
bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; }
bool hasAngularVelocity() const { return _angularVelocity != ENTITY_ITEM_ZERO_VEC3; }
float getAngularDamping() const { return _angularDamping; }
void setAngularDamping(float value) { _angularDamping = value; }

View file

@ -19,32 +19,34 @@
#include "EntityItem.h"
#include "EntityItemProperties.h"
#include "EntityItemPropertiesDefaults.h"
#include "ModelEntityItem.h"
#include "TextEntityItem.h"
EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(visible, DEFAULT_VISIBLE),
CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE),
CONSTRUCT_PROPERTY(position, 0),
CONSTRUCT_PROPERTY(dimensions, DEFAULT_DIMENSIONS),
CONSTRUCT_PROPERTY(rotation, DEFAULT_ROTATION),
CONSTRUCT_PROPERTY(mass, DEFAULT_MASS),
CONSTRUCT_PROPERTY(velocity, DEFAULT_VELOCITY),
CONSTRUCT_PROPERTY(gravity, DEFAULT_GRAVITY),
CONSTRUCT_PROPERTY(damping, DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(lifetime, DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(script, DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS),
CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION),
CONSTRUCT_PROPERTY(mass, ENTITY_ITEM_DEFAULT_MASS),
CONSTRUCT_PROPERTY(velocity, ENTITY_ITEM_DEFAULT_VELOCITY),
CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY),
CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(modelURL, ""),
CONSTRUCT_PROPERTY(animationURL, ""),
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
CONSTRUCT_PROPERTY(animationIsPlaying, ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING),
CONSTRUCT_PROPERTY(registrationPoint, DEFAULT_REGISTRATION_POINT),
CONSTRUCT_PROPERTY(angularVelocity, DEFAULT_ANGULAR_VELOCITY),
CONSTRUCT_PROPERTY(angularDamping, DEFAULT_ANGULAR_DAMPING),
CONSTRUCT_PROPERTY(ignoreForCollisions, DEFAULT_IGNORE_FOR_COLLISIONS),
CONSTRUCT_PROPERTY(collisionsWillMove, DEFAULT_COLLISIONS_WILL_MOVE),
CONSTRUCT_PROPERTY(registrationPoint, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
CONSTRUCT_PROPERTY(angularVelocity, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
CONSTRUCT_PROPERTY(angularDamping, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
CONSTRUCT_PROPERTY(isSpotlight, false),
CONSTRUCT_PROPERTY(diffuseColor, ),
CONSTRUCT_PROPERTY(ambientColor, ),
@ -54,10 +56,10 @@ EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(quadraticAttenuation, 0.0f),
CONSTRUCT_PROPERTY(exponent, 0.0f),
CONSTRUCT_PROPERTY(cutoff, PI),
CONSTRUCT_PROPERTY(locked, false),
CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED),
CONSTRUCT_PROPERTY(textures, ""),
CONSTRUCT_PROPERTY(animationSettings, ""),
CONSTRUCT_PROPERTY(userData, DEFAULT_USER_DATA),
CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA),
CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT),
CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT),
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
@ -858,7 +860,7 @@ AABox EntityItemProperties::getAABoxInMeters() const {
// _position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());

View file

@ -0,0 +1,51 @@
//
// EntityItemPropertiesDefaults.h
// libraries/entities/src
//
// Created by Andrew Meadows on 2015.01.12
// 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_EntityItemPropertiesDefaults_h
#define hifi_EntityItemPropertiesDefaults_h
#include <stdint.h>
#include <glm/glm.hpp>
// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than
// creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization.
const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f);
const glm::vec3 REGULAR_GRAVITY = glm::vec3(0, -9.8f / (float)TREE_SCALE, 0);
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
const glm::vec3 ENTITY_ITEM_DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center
const float ENTITY_ITEM_IMMORTAL_LIFETIME = -1.0f; /// special lifetime which means the entity lives for ever
const float ENTITY_ITEM_DEFAULT_LIFETIME = ENTITY_ITEM_IMMORTAL_LIFETIME;
const glm::quat ENTITY_ITEM_DEFAULT_ROTATION;
const glm::vec3 ENTITY_ITEM_DEFAULT_DIMENSIONS = glm::vec3(0.1f) / (float)TREE_SCALE;
const float ENTITY_ITEM_DEFAULT_MASS = 1.0f;
const glm::vec3 ENTITY_ITEM_DEFAULT_VELOCITY = ENTITY_ITEM_ZERO_VEC3;
const glm::vec3 ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY = ENTITY_ITEM_ZERO_VEC3;
const glm::vec3 ENTITY_ITEM_DEFAULT_GRAVITY = ENTITY_ITEM_ZERO_VEC3;
const float ENTITY_ITEM_DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header)
const float ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header)
const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false;
const bool ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE = false;
#endif // hifi_EntityItemPropertiesDefaults_h

View file

@ -79,21 +79,59 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
}
#endif // USE_BULLET_PHYSICS
void EntityMotionState::applyVelocities() const {
void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) {
#ifdef USE_BULLET_PHYSICS
if (_body) {
setVelocity(_entity->getVelocityInMeters());
// DANGER! EntityItem stores angularVelocity in degrees/sec!!!
setAngularVelocity(glm::radians(_entity->getAngularVelocity()));
_body->setActivationState(ACTIVE_TAG);
}
#endif // USE_BULLET_PHYSICS
}
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
if (flags & EntityItem::DIRTY_POSITION) {
_sentPosition = _entity->getPositionInMeters() - ObjectMotionState::getWorldOffset();
btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_sentPosition));
void EntityMotionState::applyGravity() const {
_sentRotation = _entity->getRotation();
worldTrans.setRotation(glmToBullet(_sentRotation));
_body->setWorldTransform(worldTrans);
}
if (flags & EntityItem::DIRTY_VELOCITY) {
updateObjectVelocities();
}
_sentFrame = frame;
}
// TODO: entity support for friction and restitution
//_restitution = _entity->getRestitution();
_body->setRestitution(_restitution);
//_friction = _entity->getFriction();
_body->setFriction(_friction);
_linearDamping = _entity->getDamping();
_angularDamping = _entity->getAngularDamping();
_body->setDamping(_linearDamping, _angularDamping);
if (flags & EntityItem::DIRTY_MASS) {
float mass = getMass();
btVector3 inertia(0.0f, 0.0f, 0.0f);
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
_body->setMassProps(mass, inertia);
_body->updateInertiaTensor();
}
_body->activate();
#endif // USE_BULLET_PHYSICS
};
void EntityMotionState::updateObjectVelocities() {
#ifdef USE_BULLET_PHYSICS
if (_body) {
setGravity(_entity->getGravityInMeters());
_sentVelocity = _entity->getVelocityInMeters();
setVelocity(_sentVelocity);
// DANGER! EntityItem stores angularVelocity in degrees/sec!!!
_sentAngularVelocity = glm::radians(_entity->getAngularVelocity());
setAngularVelocity(_sentAngularVelocity);
_sentAcceleration = _entity->getGravityInMeters();
setGravity(_sentAcceleration);
_body->setActivationState(ACTIVE_TAG);
}
#endif // USE_BULLET_PHYSICS
@ -123,7 +161,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
_sentAngularVelocity = bulletToGLM(_body->getAngularVelocity());
// if the speeds are very small we zero them out
const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 4.0e-6f; // 2mm/sec
const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec
bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED);
if (zeroSpeed) {
_sentVelocity = glm::vec3(0.0f);

View file

@ -54,8 +54,8 @@ public:
#endif // USE_BULLET_PHYSICS
// these relay incoming values to the RigidBody
void applyVelocities() const;
void applyGravity() const;
void updateObjectEasy(uint32_t flags, uint32_t frame);
void updateObjectVelocities();
void computeShapeInfo(ShapeInfo& info);

View file

@ -123,9 +123,9 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const {
const float FIXED_SUBSTEP = 1.0f / 60.0f;
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) {
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
assert(_body);
float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder;
float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP;
_sentFrame = simulationFrame;
bool isActive = _body->isActive();
@ -183,7 +183,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep
}
const float MIN_ROTATION_DOT = 0.98f;
glm::quat actualRotation = bulletToGLM(worldTrans.getRotation());
return (glm::dot(actualRotation, _sentRotation) < MIN_ROTATION_DOT);
return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT);
}
#endif // USE_BULLET_PHYSICS

View file

@ -56,8 +56,9 @@ public:
ObjectMotionState();
~ObjectMotionState();
virtual void applyVelocities() const = 0;
virtual void applyGravity() const = 0;
// An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine
virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0;
virtual void updateObjectVelocities() = 0;
virtual void computeShapeInfo(ShapeInfo& info) = 0;
@ -84,7 +85,7 @@ public:
void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; }
bool doesNotNeedToSendUpdate() const;
virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder);
virtual bool shouldSendUpdate(uint32_t simulationFrame);
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0;
virtual MotionType computeMotionType() const = 0;

View file

@ -41,14 +41,12 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) {
// this is step (4)
QSet<ObjectMotionState*>::iterator stateItr = _outgoingPackets.begin();
uint32_t frame = getFrameCount();
float subStepRemainder = getSubStepRemainder();
while (stateItr != _outgoingPackets.end()) {
ObjectMotionState* state = *stateItr;
if (state->doesNotNeedToSendUpdate()) {
stateItr = _outgoingPackets.erase(stateItr);
} else if (state->shouldSendUpdate(frame, subStepRemainder)) {
state->sendUpdate(_entityPacketSender, frame);
} else if (state->shouldSendUpdate(_frameCount)) {
state->sendUpdate(_entityPacketSender, _frameCount);
++stateItr;
} else {
++stateItr;
@ -140,7 +138,8 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
updateObjectHard(body, motionState, flags);
} else if (flags) {
// an EASY update does NOT require that the body be pulled out of physics engine
updateObjectEasy(body, motionState, flags);
// hence the MotionState has all the knowledge and authority to perform the update.
motionState->updateObjectEasy(flags, _frameCount);
}
}
@ -269,8 +268,12 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) {
body = new btRigidBody(mass, motionState, shape, inertia);
body->updateInertiaTensor();
motionState->_body = body;
motionState->applyVelocities();
motionState->applyGravity();
motionState->updateObjectVelocities();
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
const float LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
const float ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
body->setSleepingThresholds(LINEAR_VELOCITY_THRESHOLD, ANGULAR_VELOCITY_THRESHOLD);
break;
}
case MOTION_TYPE_STATIC:
@ -334,7 +337,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
}
bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS;
if (easyUpdate) {
updateObjectEasy(body, motionState, flags);
motionState->updateObjectEasy(flags, _frameCount);
}
// update the motion parameters
@ -385,31 +388,4 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
body->activate();
}
// private
void PhysicsEngine::updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
if (flags & EntityItem::DIRTY_POSITION) {
btTransform transform;
motionState->getWorldTransform(transform);
body->setWorldTransform(transform);
}
if (flags & EntityItem::DIRTY_VELOCITY) {
motionState->applyVelocities();
motionState->applyGravity();
}
body->setRestitution(motionState->_restitution);
body->setFriction(motionState->_friction);
body->setDamping(motionState->_linearDamping, motionState->_angularDamping);
if (flags & EntityItem::DIRTY_MASS) {
float mass = motionState->getMass();
btVector3 inertia(0.0f, 0.0f, 0.0f);
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
body->setMassProps(mass, inertia);
body->updateInertiaTensor();
}
body->activate();
// TODO: support collision groups
};
#endif // USE_BULLET_PHYSICS

View file

@ -71,12 +71,6 @@ public:
/// \return number of simulation frames the physics engine has taken
uint32_t getFrameCount() const { return _frameCount; }
/// \return substep remainder used for Bullet MotionState extrapolation
// Bullet will extrapolate the positions provided to MotionState::setWorldTransform() in an effort to provide
// smoother visible motion when the render frame rate does not match that of the simulation loop. We provide
// access to this fraction for improved filtering of update packets to interested parties.
float getSubStepRemainder() { return _dynamicsWorld->getLocalTimeAccumulation(); }
protected:
void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);