diff --git a/BUILD.md b/BUILD.md index ed3fea5c5f..0de8d32b82 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,7 +1,7 @@ ###Dependencies * [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2 -* [Qt](http://qt-project.org/downloads) ~> 5.3.2 +* [Qt](http://www.qt.io/download-open-source) ~> 5.4.1 * [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g * IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability. * [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) @@ -37,12 +37,12 @@ Hifi uses CMake to generate build files and project files for your platform. ####Qt In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation. -For example, a Qt5 5.3.2 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). +For example, a Qt5 5.4.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). The path it needs to be set to will depend on where and how Qt5 was installed. e.g. - export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/clang_64/lib/cmake/ - export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.3.2/lib/cmake + export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/clang_64/lib/cmake/ + export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake ####Generating build files @@ -57,7 +57,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation: - cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/lib/cmake + cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/lib/cmake ####Finding Dependencies diff --git a/BUILD_OSX.md b/BUILD_OSX.md index c199fe4c73..2598507c90 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -10,7 +10,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository. -*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.3.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.* +*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.4.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.* ###Xcode If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 372c399040..93aae14ced 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4452,7 +4452,6 @@ void Application::checkSkeleton() { _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default"); } else { - _myAvatar->updateCharacterController(); _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 63dd884bc6..b3439317d8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1058,3 +1058,20 @@ void Avatar::setShowDisplayName(bool showDisplayName) { } +// virtual +void Avatar::rebuildSkeletonBody() { + /* TODO: implement this and remove override from MyAvatar (when we have AvatarMotionStates working) + if (_motionState) { + // compute localAABox + const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); + float radius = capsule.getRadius(); + float height = 2.0f * (capsule.getHalfHeight() + radius); + glm::vec3 corner(-radius, -0.5f * height, -radius); + corner += _skeletonModel.getBoundingShapeOffset(); + glm::vec3 scale(2.0f * radius, height, 2.0f * radius); + //_characterController.setLocalBoundingBox(corner, scale); + _motionState->setBoundingBox(corner, scale); + } + */ +} + diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 032fe25c7d..a358e7e58d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -162,6 +162,8 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); + virtual void rebuildSkeletonBody(); + signals: void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); @@ -228,6 +230,8 @@ private: static int _jointConesID; int _voiceSphereID; + + //AvatarMotionState* _motionState = nullptr; }; #endif // hifi_Avatar_h diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 4912fabd33..1a833c5106 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -59,7 +59,7 @@ private: AvatarSharedPointer newSharedAvatar(); - // virtual override + // virtual overrides AvatarHash::iterator erase(const AvatarHash::iterator& iterator); QVector _avatarFades; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 17f361e6a8..cd7bedc19e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -987,6 +987,13 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { } void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, + Q_ARG(const QUrl&, fullAvatarURL), + Q_ARG(const QString&, modelName)); + return; + } + _useFullAvatar = true; if (_fullAvatarURLFromPreferences != fullAvatarURL) { @@ -1019,6 +1026,15 @@ void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) { } void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, + Q_ARG(const QUrl&, headURL), + Q_ARG(const QUrl&, bodyURL), + Q_ARG(const QString&, headName), + Q_ARG(const QString&, bodyName)); + return; + } + _useFullAvatar = false; if (_headURLFromPreferences != headURL) { @@ -1079,7 +1095,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::updateCharacterController() { +void MyAvatar::rebuildSkeletonBody() { // compute localAABox const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); float radius = capsule.getRadius(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 886d8ad590..4746a40099 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -138,7 +138,6 @@ public: virtual glm::vec3 getSkeletonPosition() const; void updateLocalAABox(); DynamicCharacterController* getCharacterController() { return &_characterController; } - void updateCharacterController(); void clearJointAnimationPriorities(); @@ -192,6 +191,8 @@ public slots: void stopRecording(); void saveRecording(QString filename); void loadLastRecording(); + + virtual void rebuildSkeletonBody(); signals: void transformChanged(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index dc5427ab48..8c52c79ca0 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -40,13 +40,14 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _clampedFootPosition(0.0f), _headClipDistance(DEFAULT_NEAR_CLIP) { + assert(_owningAvatar); } SkeletonModel::~SkeletonModel() { } -void SkeletonModel::setJointStates(QVector states) { - Model::setJointStates(states); +void SkeletonModel::initJointStates(QVector states) { + Model::initJointStates(states); // Determine the default eye position for avatar scale = 1.0 int headJointIndex = _geometry->getFBXGeometry().headJointIndex; @@ -83,6 +84,7 @@ void SkeletonModel::setJointStates(QVector states) { _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); + _owningAvatar->rebuildSkeletonBody(); emit skeletonLoaded(); } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 298d74fb7a..e28988326a 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -28,7 +28,7 @@ public: SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL); ~SkeletonModel(); - void setJointStates(QVector states); + virtual void initJointStates(QVector states); void simulate(float deltaTime, bool fullUpdate = true); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5552013ca2..1d358f175a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -680,6 +680,17 @@ void EntityItem::setMass(float mass) { } } +const float DEFAULT_ENTITY_RESTITUTION = 0.5f; +const float DEFAULT_ENTITY_FRICTION = 0.5f; + +float EntityItem::getRestitution() const { + return DEFAULT_ENTITY_RESTITUTION; +} + +float EntityItem::getFriction() const { + return DEFAULT_ENTITY_FRICTION; +} + void EntityItem::simulate(const quint64& now) { if (_lastSimulated == 0) { _lastSimulated = now; @@ -840,11 +851,11 @@ glm::mat4 EntityItem::getWorldToEntityMatrix() const { return glm::inverse(getEntityToWorldMatrix()); } -glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const { +glm::vec3 EntityItem::entityToWorld(const glm::vec3& point) const { return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f)); } -glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const { +glm::vec3 EntityItem::worldToEntity(const glm::vec3& point) const { return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f)); } @@ -1164,7 +1175,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) { void EntityItem::updateDamping(float value) { if (fabsf(_damping - value) > MIN_DAMPING_DELTA) { _damping = glm::clamp(value, 0.0f, 1.0f); - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_MATERIAL; } } @@ -1202,7 +1213,7 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { void EntityItem::updateAngularDamping(float value) { if (fabsf(_angularDamping - value) > MIN_DAMPING_DELTA) { _angularDamping = glm::clamp(value, 0.0f, 1.0f); - _dirtyFlags |= EntityItem::DIRTY_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_MATERIAL; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 890134828a..e71f88d723 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -55,7 +55,8 @@ public: DIRTY_SHAPE = 0x0020, DIRTY_LIFETIME = 0x0040, DIRTY_UPDATEABLE = 0x0080, - DIRTY_PHYSICS_NO_WAKE = 0x0100 // we want to update values in physics engine without "waking" the object up + DIRTY_MATERIAL = 0x00100, + DIRTY_PHYSICS_NO_WAKE = 0x0200 // we want to update values in physics engine without "waking" the object up }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -174,7 +175,7 @@ public: float getDensity() const { return _density; } - const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters + const glm::vec3& getVelocity() const { return _velocity; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; } @@ -182,13 +183,16 @@ public: void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; } - const glm::vec3 getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second + const glm::vec3& getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; } float getDamping() const { return _damping; } void setDamping(float value) { _damping = value; } + float getRestitution() const; + float getFriction() const; + // lifetime related properties. float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity @@ -298,8 +302,8 @@ public: glm::mat4 getEntityToWorldMatrix() const; glm::mat4 getWorldToEntityMatrix() const; - glm::vec3 worldToEntity(const glm::vec3 point) const; - glm::vec3 entityToWorld(const glm::vec3 point) const; + glm::vec3 worldToEntity(const glm::vec3& point) const; + glm::vec3 entityToWorld(const glm::vec3& point) const; protected: diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 04da26a1ff..1dbd67f3b2 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -16,6 +16,7 @@ #include "LightEntityItem.h" #include "ModelEntityItem.h" #include "ZoneEntityItem.h" +#include "EntitiesLogging.h" EntityScriptingInterface::EntityScriptingInterface() : @@ -78,19 +79,27 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro EntityItemProperties propertiesWithSimID = properties; - EntityItemID id(NEW_ENTITY, creatorTokenID, false ); + EntityItemID id(NEW_ENTITY, creatorTokenID, false); // If we have a local entity tree set, then also update it. + bool success = true; if (_entityTree) { _entityTree->lockForWrite(); EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID); - // This Node is creating a new object. If it's in motion, set this Node as the simulator. - setSimId(propertiesWithSimID, entity); + if (entity) { + // This Node is creating a new object. If it's in motion, set this Node as the simulator. + setSimId(propertiesWithSimID, entity); + } else { + qCDebug(entities) << "script failed to add new Entity to local Octree"; + success = false; + } _entityTree->unlock(); } // queue the packet - queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID); + if (success) { + queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID); + } return id; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a63a7ef7c3..436339b3fe 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -192,6 +192,14 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* result = NULL; + if (getIsClient()) { + // if our Node isn't allowed to create entities in this domain, don't try. + auto nodeList = DependencyManager::get(); + if (!nodeList->getThisNodeCanRez()) { + return NULL; + } + } + // NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems // that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs. bool recordCreationTime = false; diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index 3557511fab..6d1e295703 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -94,7 +94,7 @@ void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) { } } -void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld,btScalar dt) { +void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { btVector3 actualVelocity = _rigidBody->getLinearVelocity(); btScalar actualSpeed = actualVelocity.length(); @@ -315,10 +315,10 @@ void DynamicCharacterController::updateShapeIfNecessary() { float mass = 1.0f; btVector3 inertia(1.0f, 1.0f, 1.0f); _rigidBody = new btRigidBody(mass, NULL, _shape, inertia); - _rigidBody->setSleepingThresholds (0.0f, 0.0f); - _rigidBody->setAngularFactor (0.0f); + _rigidBody->setSleepingThresholds(0.0f, 0.0f); + _rigidBody->setAngularFactor(0.0f); _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); + glmToBullet(_avatarData->getPosition()))); if (_isHovering) { _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); } else { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6338736a19..a7245c32d4 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -51,7 +51,7 @@ EntityMotionState::~EntityMotionState() { _entity = NULL; } -MotionType EntityMotionState::computeMotionType() const { +MotionType EntityMotionState::computeObjectMotionType() const { if (_entity->getCollisionsWillMove()) { return MOTION_TYPE_DYNAMIC; } @@ -68,7 +68,7 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) { // which is different from physical kinematic motion (inside getWorldTransform()) // which steps in physics simulation time. _entity->simulate(now); - // TODO: we can't use ObjectMotionState::measureAcceleration() here because the entity + // TODO: we can't use measureBodyAcceleration() here because the entity // has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway. // Hence we must manually measure kinematic velocity and acceleration. } @@ -101,7 +101,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation step... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { - measureAcceleration(); + measureBodyAcceleration(); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); @@ -138,20 +138,20 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { #endif } -void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { +void EntityMotionState::updateBodyEasy(uint32_t flags, uint32_t step) { if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_PHYSICS_NO_WAKE)) { if (flags & EntityItem::DIRTY_POSITION) { - _sentPosition = _entity->getPosition() - ObjectMotionState::getWorldOffset(); + _sentPosition = getObjectPosition() - ObjectMotionState::getWorldOffset(); btTransform worldTrans; worldTrans.setOrigin(glmToBullet(_sentPosition)); - _sentRotation = _entity->getRotation(); + _sentRotation = getObjectRotation(); worldTrans.setRotation(glmToBullet(_sentRotation)); _body->setWorldTransform(worldTrans); } if (flags & EntityItem::DIRTY_VELOCITY) { - updateObjectVelocities(); + updateBodyVelocities(); } _sentStep = step; @@ -160,54 +160,54 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { } } - // 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_MATERIAL) { + updateBodyMaterialProperties(); + } if (flags & EntityItem::DIRTY_MASS) { - float mass = _entity->computeMass(); + ShapeInfo shapeInfo; + _entity->computeShapeInfo(shapeInfo); + float mass = computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); _body->getCollisionShape()->calculateLocalInertia(mass, inertia); _body->setMassProps(mass, inertia); _body->updateInertiaTensor(); } -}; +} -void EntityMotionState::updateObjectVelocities() { +void EntityMotionState::updateBodyMaterialProperties() { + _body->setRestitution(getObjectRestitution()); + _body->setFriction(getObjectFriction()); + _body->setDamping(fabsf(btMin(getObjectLinearDamping(), 1.0f)), fabsf(btMin(getObjectAngularDamping(), 1.0f))); +} + +void EntityMotionState::updateBodyVelocities() { if (_body) { - _sentVelocity = _entity->getVelocity(); - setVelocity(_sentVelocity); + _sentVelocity = getObjectLinearVelocity(); + setBodyVelocity(_sentVelocity); - _sentAngularVelocity = _entity->getAngularVelocity(); - setAngularVelocity(_sentAngularVelocity); + _sentAngularVelocity = getObjectAngularVelocity(); + setBodyAngularVelocity(_sentAngularVelocity); - _sentGravity = _entity->getGravity(); - setGravity(_sentGravity); + _sentGravity = getObjectGravity(); + setBodyGravity(_sentGravity); _body->setActivationState(ACTIVE_TAG); } } -void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) { +void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) { if (_entity->isReadyToComputeShape()) { _entity->computeShapeInfo(shapeInfo); } } -float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { +float EntityMotionState::computeObjectMass(const ShapeInfo& shapeInfo) const { return _entity->computeMass(); } bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { - bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame); - - if (!baseResult) { + if (!ObjectMotionState::shouldSendUpdate(simulationFrame)) { return false; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 087d5b49b9..98d05a0420 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -31,12 +31,11 @@ public: static void setOutgoingEntityList(QSet* list); static void enqueueOutgoingEntity(EntityItem* entity); - EntityMotionState() = delete; // prevent compiler from making default ctor EntityMotionState(EntityItem* item); virtual ~EntityMotionState(); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem - virtual MotionType computeMotionType() const; + virtual MotionType computeObjectMotionType() const; virtual void updateKinematicState(uint32_t substep); virtual void stepKinematicSimulation(quint64 now); @@ -50,11 +49,12 @@ public: virtual void setWorldTransform(const btTransform& worldTrans); // these relay incoming values to the RigidBody - virtual void updateObjectEasy(uint32_t flags, uint32_t step); - virtual void updateObjectVelocities(); + virtual void updateBodyEasy(uint32_t flags, uint32_t step); + virtual void updateBodyMaterialProperties(); + virtual void updateBodyVelocities(); - virtual void computeShapeInfo(ShapeInfo& shapeInfo); - virtual float computeMass(const ShapeInfo& shapeInfo) const; + virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo); + virtual float computeObjectMass(const ShapeInfo& shapeInfo) const; virtual bool shouldSendUpdate(uint32_t simulationFrame); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step); @@ -70,6 +70,17 @@ public: virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } + virtual float getObjectRestitution() const { return _entity->getRestitution(); } + virtual float getObjectFriction() const { return _entity->getFriction(); } + virtual float getObjectLinearDamping() const { return _entity->getDamping(); } + virtual float getObjectAngularDamping() const { return _entity->getAngularDamping(); } + + virtual const glm::vec3& getObjectPosition() const { return _entity->getPosition(); } + virtual const glm::quat& getObjectRotation() const { return _entity->getRotation(); } + virtual const glm::vec3& getObjectLinearVelocity() const { return _entity->getVelocity(); } + virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } + virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); } + protected: EntityItem* _entity; quint8 _accelerationNearlyGravityCount; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 3d8e578056..d8eb86f0b4 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -36,17 +36,13 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { } // static -uint32_t _simulationStep = 0; -void ObjectMotionState::setSimulationStep(uint32_t step) { - assert(step > _simulationStep); - _simulationStep = step; +uint32_t _worldSimulationStep = 0; +void ObjectMotionState::setWorldSimulationStep(uint32_t step) { + assert(step > _worldSimulationStep); + _worldSimulationStep = step; } ObjectMotionState::ObjectMotionState() : - _friction(DEFAULT_FRICTION), - _restitution(DEFAULT_RESTITUTION), - _linearDamping(0.0f), - _angularDamping(0.0f), _motionType(MOTION_TYPE_STATIC), _body(NULL), _sentMoving(false), @@ -69,52 +65,36 @@ ObjectMotionState::~ObjectMotionState() { assert(_body == NULL); } -void ObjectMotionState::measureAcceleration() { +void ObjectMotionState::measureBodyAcceleration() { // try to manually measure the true acceleration of the object - uint32_t numSubsteps = _simulationStep - _lastSimulationStep; + uint32_t numSubsteps = _worldSimulationStep - _lastSimulationStep; if (numSubsteps > 0) { float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP); float invDt = 1.0f / dt; - _lastSimulationStep = _simulationStep; + _lastSimulationStep = _worldSimulationStep; // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); - _measuredAcceleration = (velocity / powf(1.0f - _linearDamping, dt) - _lastVelocity) * invDt; + _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; _lastVelocity = velocity; } } -void ObjectMotionState::resetMeasuredAcceleration() { - _lastSimulationStep = _simulationStep; +void ObjectMotionState::resetMeasuredBodyAcceleration() { + _lastSimulationStep = _worldSimulationStep; _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } -void ObjectMotionState::setFriction(float friction) { - _friction = btMax(btMin(fabsf(friction), MAX_FRICTION), 0.0f); -} - -void ObjectMotionState::setRestitution(float restitution) { - _restitution = btMax(btMin(fabsf(restitution), 1.0f), 0.0f); -} - -void ObjectMotionState::setLinearDamping(float damping) { - _linearDamping = btMax(btMin(fabsf(damping), 1.0f), 0.0f); -} - -void ObjectMotionState::setAngularDamping(float damping) { - _angularDamping = btMax(btMin(fabsf(damping), 1.0f), 0.0f); -} - -void ObjectMotionState::setVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setBodyVelocity(const glm::vec3& velocity) const { _body->setLinearVelocity(glmToBullet(velocity)); } -void ObjectMotionState::setAngularVelocity(const glm::vec3& velocity) const { +void ObjectMotionState::setBodyAngularVelocity(const glm::vec3& velocity) const { _body->setAngularVelocity(glmToBullet(velocity)); } -void ObjectMotionState::setGravity(const glm::vec3& gravity) const { +void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const { _body->setGravity(glmToBullet(gravity)); } @@ -181,7 +161,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { // compute position error if (glm::length2(_sentVelocity) > 0.0f) { _sentVelocity += _sentAcceleration * dt; - _sentVelocity *= powf(1.0f - _linearDamping, dt); + _sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt); _sentPosition += dt * _sentVelocity; } @@ -206,7 +186,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) { if (glm::length2(_sentAngularVelocity) > 0.0f) { // compute rotation error - float attenuation = powf(1.0f - _angularDamping, dt); + float attenuation = powf(1.0f - _body->getAngularDamping(), dt); _sentAngularVelocity *= attenuation; // Bullet caps the effective rotation velocity inside its rotation integration step, therefore diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 9e0917a3ab..7c00eedd09 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -36,7 +36,7 @@ enum MotionStateType { // and re-added to the physics engine and "easy" which just updates the body properties. const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | - EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP); + EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL); // These are the set of incoming flags that the PhysicsEngine needs to hear about: const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS; @@ -59,32 +59,30 @@ public: static void setWorldOffset(const glm::vec3& offset); static const glm::vec3& getWorldOffset(); - static void setSimulationStep(uint32_t step); + // The WorldSimulationStep is a cached copy of number of SubSteps of the simulation, used for local time measurements. + static void setWorldSimulationStep(uint32_t step); ObjectMotionState(); ~ObjectMotionState(); - void measureAcceleration(); - void resetMeasuredAcceleration(); + void measureBodyAcceleration(); + void resetMeasuredBodyAcceleration(); // 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 updateBodyEasy(uint32_t flags, uint32_t frame) = 0; + + virtual void updateBodyMaterialProperties() = 0; + virtual void updateBodyVelocities() = 0; MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } - virtual void computeShapeInfo(ShapeInfo& info) = 0; - virtual float computeMass(const ShapeInfo& shapeInfo) const = 0; + virtual void computeObjectShapeInfo(ShapeInfo& info) = 0; + virtual float computeObjectMass(const ShapeInfo& shapeInfo) const = 0; - void setFriction(float friction); - void setRestitution(float restitution); - void setLinearDamping(float damping); - void setAngularDamping(float damping); - - void setVelocity(const glm::vec3& velocity) const; - void setAngularVelocity(const glm::vec3& velocity) const; - void setGravity(const glm::vec3& gravity) const; + void setBodyVelocity(const glm::vec3& velocity) const; + void setBodyAngularVelocity(const glm::vec3& velocity) const; + void setBodyGravity(const glm::vec3& gravity) const; void getVelocity(glm::vec3& velocityOut) const; void getAngularVelocity(glm::vec3& angularVelocityOut) const; @@ -97,7 +95,7 @@ public: virtual bool shouldSendUpdate(uint32_t simulationStep); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; - virtual MotionType computeMotionType() const = 0; + virtual MotionType computeObjectMotionType() const = 0; virtual void updateKinematicState(uint32_t substep) = 0; @@ -117,18 +115,26 @@ public: virtual void setShouldClaimSimulationOwnership(bool value) { } virtual bool getShouldClaimSimulationOwnership() { return false; } + // These pure virtual methods must be implemented for each MotionState type + // and make it possible to implement more complicated methods in this base class. + + virtual float getObjectRestitution() const = 0; + virtual float getObjectFriction() const = 0; + virtual float getObjectLinearDamping() const = 0; + virtual float getObjectAngularDamping() const = 0; + + virtual const glm::vec3& getObjectPosition() const = 0; + virtual const glm::quat& getObjectRotation() const = 0; + virtual const glm::vec3& getObjectLinearVelocity() const = 0; + virtual const glm::vec3& getObjectAngularVelocity() const = 0; + virtual const glm::vec3& getObjectGravity() const = 0; + protected: void setRigidBody(btRigidBody* body); - MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; + MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; // type of MotionState - // TODO: move these materials properties outside of ObjectMotionState - float _friction; - float _restitution; - float _linearDamping; - float _angularDamping; - - MotionType _motionType; + MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC btRigidBody* _body; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 27ea816440..603aef731c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -15,6 +15,7 @@ #include "ShapeInfoUtil.h" #include "PhysicsHelpers.h" #include "ThreadSafeDynamicsWorld.h" +#include "PhysicsLogging.h" static uint32_t _numSubsteps; @@ -172,9 +173,9 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { if (flags & HARD_DIRTY_PHYSICS_FLAGS) { // a HARD update requires the body be pulled out of physics engine, changed, then reinserted // but it also handles all EASY changes - bool success = updateObjectHard(body, motionState, flags); + bool success = updateBodyHard(body, motionState, flags); if (!success) { - // NOTE: since updateObjectHard() failed we know that motionState has been removed + // NOTE: since updateBodyHard() failed we know that motionState has been removed // from simulation and body has been deleted. Depending on what else has changed // we might need to remove motionState altogether... if (flags & EntityItem::DIRTY_VELOCITY) { @@ -194,10 +195,10 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } else if (flags) { // an EASY update does NOT require that the body be pulled out of physics engine // hence the MotionState has all the knowledge and authority to perform the update. - motionState->updateObjectEasy(flags, _numSubsteps); + motionState->updateBodyEasy(flags, _numSubsteps); } if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { - motionState->resetMeasuredAcceleration(); + motionState->resetMeasuredBodyAcceleration(); } } else { // the only way we should ever get here (motionState exists but no body) is when the object @@ -207,7 +208,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { // it is possible that the changes are such that the object can now be added to the physical simulation if (flags & EntityItem::DIRTY_SHAPE) { ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); + motionState->computeObjectShapeInfo(shapeInfo); btCollisionShape* shape = _shapeManager.getShape(shapeInfo); if (shape) { addObject(shapeInfo, shape, motionState); @@ -341,7 +342,7 @@ void PhysicsEngine::stepSimulation() { // lock on the tree before we re-lock ourselves. // // TODO: untangle these lock sequences. - ObjectMotionState::setSimulationStep(_numSubsteps); + ObjectMotionState::setWorldSimulationStep(_numSubsteps); _entityTree->lockForWrite(); lock(); _dynamicsWorld->synchronizeMotionStates(); @@ -498,7 +499,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap btVector3 inertia(0.0f, 0.0f, 0.0f); float mass = 0.0f; btRigidBody* body = NULL; - switch(motionState->computeMotionType()) { + switch(motionState->computeObjectMotionType()) { case MOTION_TYPE_KINEMATIC: { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); @@ -511,13 +512,13 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap break; } case MOTION_TYPE_DYNAMIC: { - mass = motionState->computeMass(shapeInfo); + mass = motionState->computeObjectMass(shapeInfo); shape->calculateLocalInertia(mass, inertia); body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); motionState->setRigidBody(body); motionState->setKinematic(false, _numSubsteps); - motionState->updateObjectVelocities(); + motionState->updateBodyVelocities(); // 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 DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec @@ -540,11 +541,10 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap } } body->setFlags(BT_DISABLE_WORLD_GRAVITY); - body->setRestitution(motionState->_restitution); - body->setFriction(motionState->_friction); - body->setDamping(motionState->_linearDamping, motionState->_angularDamping); + motionState->updateBodyMaterialProperties(); + _dynamicsWorld->addRigidBody(body); - motionState->resetMeasuredAcceleration(); + motionState->resetMeasuredBodyAcceleration(); } void PhysicsEngine::bump(EntityItem* bumpEntity) { @@ -608,8 +608,8 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { } // private -bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { - MotionType newType = motionState->computeMotionType(); +bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { + MotionType newType = motionState->computeObjectMotionType(); // pull body out of physics engine _dynamicsWorld->removeRigidBody(body); @@ -621,7 +621,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio // get new shape btCollisionShape* oldShape = body->getCollisionShape(); ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); + motionState->computeObjectShapeInfo(shapeInfo); btCollisionShape* newShape = _shapeManager.getShape(shapeInfo); if (!newShape) { // FAIL! we are unable to support these changes! @@ -640,7 +640,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio _shapeManager.releaseShape(oldShape); // compute mass properties - float mass = motionState->computeMass(shapeInfo); + float mass = motionState->computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); body->setMassProps(mass, inertia); @@ -653,7 +653,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio } bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; if (easyUpdate) { - motionState->updateObjectEasy(flags, _numSubsteps); + motionState->updateBodyEasy(flags, _numSubsteps); } // update the motion parameters @@ -675,8 +675,8 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio if (! (flags & EntityItem::DIRTY_MASS)) { // always update mass properties when going dynamic (unless it's already been done above) ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); - float mass = motionState->computeMass(shapeInfo); + motionState->computeObjectShapeInfo(shapeInfo); + float mass = motionState->computeObjectMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); body->setMassProps(mass, inertia); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9fe632d462..4f931d939a 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -39,8 +39,8 @@ public: ContactKey(void* a, void* b) : _a(a), _b(b) {} bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); } bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; } - void* _a; - void* _b; + void* _a; // EntityMotionState pointer + void* _b; // EntityMotionState pointer }; typedef std::map ContactMap; @@ -100,7 +100,7 @@ private: void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB); // return 'true' of update was successful - bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + bool updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3508570d6a..0114bc65f0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -426,12 +426,12 @@ bool Model::updateGeometry() { _dilatedTextures.clear(); _geometry = geometry; _meshGroupsKnown = false; - setJointStates(newJointStates); + initJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); if (fbxGeometry.joints.size() > 0) { - setJointStates(createJointStates(fbxGeometry)); + initJointStates(createJointStates(fbxGeometry)); needToRebuild = true; } } else if (!geometry->isLoaded()) { @@ -469,7 +469,7 @@ bool Model::updateGeometry() { } // virtual -void Model::setJointStates(QVector states) { +void Model::initJointStates(QVector states) { _jointStates = states; initJointTransforms(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 1559e73e61..b91d2116f8 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -244,7 +244,7 @@ protected: // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); - virtual void setJointStates(QVector states); + virtual void initJointStates(QVector states); void setScaleInternal(const glm::vec3& scale); void scaleToFit(); diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 47e5659c60..84c8ae4939 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -19,19 +19,10 @@ QString& PathUtils::resourcesPath() { -#ifdef DEBUG - static QString staticResourcePath; - if (staticResourcePath.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - staticResourcePath = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; - } -#else #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; #else static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; -#endif #endif return staticResourcePath;