diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1b6be53876..79339b03de 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2756,7 +2756,6 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); - myAvatar->relayDriveKeysToCharacterController(); static VectorOfMotionStates motionStates; _entitySimulation.getObjectsToDelete(motionStates); @@ -2783,6 +2782,8 @@ void Application::update(float deltaTime) { avatarManager->getObjectsToChange(motionStates); _physicsEngine->changeObjects(motionStates); + myAvatar->prepareForPhysicsSimulation(); + _entities.getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); @@ -2807,6 +2808,8 @@ void Application::update(float deltaTime) { // and will simulate entity motion (the EntityTree has been given an EntitySimulation). _entities.update(); // update the models... } + + myAvatar->harvestResultsFromPhysicsSimulation(); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5920543dca..e52e56cd89 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -109,8 +109,13 @@ MyAvatar::MyAvatar(RigPointer rig) : _goToOrientation(), _rig(rig), _prevShouldDrawHead(true), - _audioListenerMode(FROM_HEAD), - _hmdAtRestDetector(glm::vec3(0), glm::quat()) + _audioListenerMode(FROM_HEAD) +#ifdef OLD_HMD_TRACKER + ,_hmdAtRestDetector(glm::vec3(0), glm::quat()) +#else + ,_avatarOffsetFromHMD(0.0f) + ,_hmdVelocity(0.0f) +#endif // OLD_HMD_TRACKER { for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; @@ -154,7 +159,10 @@ void MyAvatar::reset(bool andReload) { } // Reset dynamic state. - _wasPushing = _isPushing = _isBraking = _billboardValid = _straighteningLean = false; + _wasPushing = _isPushing = _isBraking = _billboardValid = false; +#ifdef OLD_HMD_TRACKER + _isFollowingHMD = false; +#endif // OLD_HMD_TRACKER _skeletonModel.reset(); getHead()->reset(); _targetVelocity = glm::vec3(0.0f); @@ -302,9 +310,10 @@ glm::mat4 MyAvatar::getSensorToWorldMatrix() const { return _sensorToWorldMatrix; } +#ifdef OLD_HMD_TRACKER // returns true if pos is OUTSIDE of the vertical capsule // where the middle cylinder length is defined by capsuleLen and the radius by capsuleRad. -static bool capsuleCheck(const glm::vec3& pos, float capsuleLen, float capsuleRad) { +static bool pointIsOutsideCapsule(const glm::vec3& pos, float capsuleLen, float capsuleRad) { const float halfCapsuleLen = capsuleLen / 2.0f; if (fabs(pos.y) <= halfCapsuleLen) { // cylinder check for middle capsule @@ -320,12 +329,18 @@ static bool capsuleCheck(const glm::vec3& pos, float capsuleLen, float capsuleRa return false; } } +#endif // OLD_HMD_TRACKER // Pass a recent sample of the HMD to the avatar. // This can also update the avatar's position to follow the HMD // as it moves through the world. void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { + // update the sensorMatrices based on the new hmd pose + _hmdSensorMatrix = hmdSensorMatrix; + _hmdSensorPosition = extractTranslation(hmdSensorMatrix); + _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix); +#ifdef OLD_HMD_TRACKER // calc deltaTime auto now = usecTimestampNow(); auto deltaUsecs = now - _lastUpdateFromHMDTime; @@ -334,11 +349,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { const float BIGGEST_DELTA_TIME_SECS = 0.25f; float deltaTime = glm::clamp((float)actualDeltaTime, 0.0f, BIGGEST_DELTA_TIME_SECS); - // update the sensorMatrices based on the new hmd pose - _hmdSensorMatrix = hmdSensorMatrix; - _hmdSensorPosition = extractTranslation(hmdSensorMatrix); - _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix); - bool hmdIsAtRest = _hmdAtRestDetector.update(deltaTime, _hmdSensorPosition, _hmdSensorOrientation); // It can be more accurate/smooth to use velocity rather than position, @@ -360,58 +370,57 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving; _lastIsMoving = isMoving; - if (shouldBeginStraighteningLean() || hmdIsAtRest || justStartedMoving) { - beginStraighteningLean(); + if (shouldFollowHMD() || hmdIsAtRest || justStartedMoving) { + beginFollowingHMD(); } - processStraighteningLean(deltaTime); + followHMD(deltaTime); +#endif // OLD_HMD_TRACKER } -void MyAvatar::beginStraighteningLean() { +#ifdef OLD_HMD_TRACKER +void MyAvatar::beginFollowingHMD() { // begin homing toward derived body position. - if (!_straighteningLean) { - _straighteningLean = true; - _straighteningLeanAlpha = 0.0f; + if (!_isFollowingHMD) { + _isFollowingHMD = true; + _followHMDAlpha = 0.0f; } } -bool MyAvatar::shouldBeginStraighteningLean() const { - // define a vertical capsule - const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters - const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. - - // detect if the derived body position is outside of a capsule around the _bodySensorMatrix - auto newBodySensorMatrix = deriveBodyFromHMDSensor(); - glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix); - bool isBodyPosOutsideCapsule = capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS); - - if (isBodyPosOutsideCapsule) { - return true; - } else { - return false; +bool MyAvatar::shouldFollowHMD() const { + if (!_isFollowingHMD) { + // define a vertical capsule + const float FOLLOW_HMD_CAPSULE_RADIUS = 0.2f; // meters + const float FOLLOW_HMD_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. + + // detect if the derived body position is outside of a capsule around the _bodySensorMatrix + auto newBodySensorMatrix = deriveBodyFromHMDSensor(); + glm::vec3 localPoint = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix); + return pointIsOutsideCapsule(localPoint, FOLLOW_HMD_CAPSULE_LENGTH, FOLLOW_HMD_CAPSULE_RADIUS); } + return false; } -void MyAvatar::processStraighteningLean(float deltaTime) { - if (_straighteningLean) { +void MyAvatar::followHMD(float deltaTime) { + if (_isFollowingHMD) { - const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds + const float FOLLOW_HMD_DURATION = 0.5f; // seconds auto newBodySensorMatrix = deriveBodyFromHMDSensor(); auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); - _straighteningLeanAlpha += (1.0f / STRAIGHTENING_LEAN_DURATION) * deltaTime; + _followHMDAlpha += (1.0f / FOLLOW_HMD_DURATION) * deltaTime; - if (_straighteningLeanAlpha >= 1.0f) { - _straighteningLean = false; + if (_followHMDAlpha >= 1.0f) { + _isFollowingHMD = false; nextAttitude(worldBodyPos, worldBodyRot); _bodySensorMatrix = newBodySensorMatrix; } else { // interp position toward the desired pos - glm::vec3 pos = lerp(getPosition(), worldBodyPos, _straighteningLeanAlpha); - glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _straighteningLeanAlpha)); + glm::vec3 pos = lerp(getPosition(), worldBodyPos, _followHMDAlpha); + glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _followHMDAlpha)); nextAttitude(pos, rot); // interp sensor matrix toward desired @@ -419,12 +428,17 @@ void MyAvatar::processStraighteningLean(float deltaTime) { glm::quat nextBodyRot = glm::normalize(glm::quat_cast(newBodySensorMatrix)); glm::vec3 prevBodyPos = extractTranslation(_bodySensorMatrix); glm::quat prevBodyRot = glm::normalize(glm::quat_cast(_bodySensorMatrix)); - pos = lerp(prevBodyPos, nextBodyPos, _straighteningLeanAlpha); - rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _straighteningLeanAlpha)); + pos = lerp(prevBodyPos, nextBodyPos, _followHMDAlpha); + rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _followHMDAlpha)); _bodySensorMatrix = createMatFromQuatAndPos(rot, pos); } } } +#else +void MyAvatar::harvestHMDOffset(glm::vec3 offset) { + +} +#endif // USE_OLD // best called at end of main loop, just before rendering. // update sensor to world matrix from current body position and hmd sensor. @@ -1274,6 +1288,21 @@ void MyAvatar::rebuildSkeletonBody() { _characterController.setLocalBoundingBox(corner, scale); } +void MyAvatar::prepareForPhysicsSimulation() { + relayDriveKeysToCharacterController(); + _characterController.setTargetVelocity(getTargetVelocity()); + _characterController.setAvatarPositionAndOrientation(getPosition(), getOrientation()); + //_characterController.setHMDVelocity(hmdVelocity); +} + +void MyAvatar::harvestResultsFromPhysicsSimulation() { + glm::vec3 position = getPosition(); + glm::quat orientation = getOrientation(); + _characterController.getAvatarPositionAndOrientation(position, orientation); + nextAttitude(position, orientation); + setVelocity(_characterController.getLinearVelocity()); +} + QString MyAvatar::getScriptedMotorFrame() const { QString frame = "avatar"; if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7347419fee..f3f55f4a7a 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -12,12 +12,16 @@ #ifndef hifi_MyAvatar_h #define hifi_MyAvatar_h +#include + #include -#include #include #include "Avatar.h" -#include "AtRestDetector.h" +//#include "AtRestDetector.h" +#include "MyAvatarController.h" + +//#define OLD_HMD_TRACKER class ModelItemID; @@ -154,8 +158,10 @@ public: virtual void setAttachmentData(const QVector& attachmentData) override; - DynamicCharacterController* getCharacterController() { return &_characterController; } + MyAvatarController* getCharacterController() { return &_characterController; } + void prepareForPhysicsSimulation(); + void harvestResultsFromPhysicsSimulation(); const QString& getCollisionSoundURL() {return _collisionSoundURL; } void setCollisionSoundURL(const QString& url); @@ -262,9 +268,13 @@ private: const RecorderPointer getRecorder() const { return _recorder; } const PlayerPointer getPlayer() const { return _player; } - void beginStraighteningLean(); - bool shouldBeginStraighteningLean() const; - void processStraighteningLean(float deltaTime); +#ifdef OLD_HMD_TRACKER + void beginFollowingHMD(); + bool shouldFollowHMD() const; + void followHMD(float deltaTime); +#else + void harvestHMDOffset(glm::vec3 offset); +#endif bool cameraInsideHead() const; @@ -295,7 +305,7 @@ private: quint32 _motionBehaviors; QString _collisionSoundURL; - DynamicCharacterController _characterController; + MyAvatarController _characterController; AvatarWeakPointer _lookAtTargetAvatar; glm::vec3 _targetAvatarPosition; @@ -348,21 +358,26 @@ private: RigPointer _rig; bool _prevShouldDrawHead; - bool _enableDebugDrawBindPose = false; - bool _enableDebugDrawAnimPose = false; - AnimSkeleton::ConstPointer _debugDrawSkeleton = nullptr; + bool _enableDebugDrawBindPose { false }; + bool _enableDebugDrawAnimPose { false }; + AnimSkeleton::ConstPointer _debugDrawSkeleton { nullptr }; AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; glm::quat _customListenOrientation; - bool _straighteningLean = false; - float _straighteningLeanAlpha = 0.0f; +#ifdef OLD_HMD_TRACKER + bool _isFollowingHMD { false }; + float _followHMDAlpha{0.0f}; - quint64 _lastUpdateFromHMDTime = usecTimestampNow(); + quint64 _lastUpdateFromHMDTime{usecTimestampNow()}; AtRestDetector _hmdAtRestDetector; glm::vec3 _lastPosition; - bool _lastIsMoving = false; + bool _lastIsMoving { false }; +#else + glm::vec3 _avatarOffsetFromHMD; + glm::vec3 _hmdVelocity; +#endif // OLD_HMD_TRACKER }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/interface/src/avatar/MyAvatarController.cpp similarity index 81% rename from libraries/physics/src/DynamicCharacterController.cpp rename to interface/src/avatar/MyAvatarController.cpp index 604326168c..931c8b9b08 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/interface/src/avatar/MyAvatarController.cpp @@ -1,13 +1,27 @@ +// +// MyAvatar.h +// interface/src/avatar +// +// Created by AndrewMeadows 2015.10.21 +// 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 +// + +#include "MyAvatarController.h" + #include #include #include #include +#include +#include +#include #include -#include "BulletUtil.h" -#include "DynamicCharacterController.h" -#include "PhysicsLogging.h" +#include "MyAvatar.h" const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float DEFAULT_GRAVITY = -5.0f; @@ -15,11 +29,6 @@ const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; -const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; -const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; -const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2; -const uint32_t PENDING_FLAG_JUMP = 1U << 3; - // TODO: improve walking up steps // TODO: make avatars able to walk up and down steps/slopes // TODO: make avatars stand on steep slope @@ -41,19 +50,19 @@ protected: btRigidBody* _me; }; -DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) { +MyAvatarController::MyAvatarController(MyAvatar* avatar) { _halfHeight = 1.0f; _shape = nullptr; - _rigidBody = nullptr; - assert(avatarData); - _avatarData = avatarData; + assert(avatar); + _avatar = avatar; _enabled = false; _floorDistance = MAX_FALL_HEIGHT; - _walkVelocity.setValue(0.0f,0.0f,0.0f); + _walkVelocity.setValue(0.0f, 0.0f, 0.0f); + _hmdVelocity.setValue(0.0f, 0.0f, 0.0f); _jumpSpeed = JUMP_SPEED; _isOnGround = false; _isJumping = false; @@ -61,21 +70,16 @@ DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) { _isHovering = true; _isPushingUp = false; _jumpToHoverStart = 0; + _lastStepDuration = 0.0f; _pendingFlags = PENDING_FLAG_UPDATE_SHAPE; updateShapeIfNecessary(); } -DynamicCharacterController::~DynamicCharacterController() { +MyAvatarController::~MyAvatarController() { } -// virtual -void DynamicCharacterController::setWalkDirection(const btVector3& walkDirection) { - // do nothing -- walkVelocity is upated in preSimulation() - //_walkVelocity = walkDirection; -} - -void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) { +void MyAvatarController::preStep(btCollisionWorld* collisionWorld) { // trace a ray straight down to see if we're standing on the ground const btTransform& xform = _rigidBody->getWorldTransform(); @@ -96,7 +100,7 @@ void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) { } } -void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { +void MyAvatarController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { btVector3 actualVelocity = _rigidBody->getLinearVelocity(); btScalar actualSpeed = actualVelocity.length(); @@ -160,7 +164,7 @@ void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScala } } -void DynamicCharacterController::jump() { +void MyAvatarController::jump() { // check for case where user is holding down "jump" key... // we'll eventually tansition to "hover" if (!_isJumping) { @@ -178,12 +182,12 @@ void DynamicCharacterController::jump() { } } -bool DynamicCharacterController::onGround() const { +bool MyAvatarController::onGround() const { const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius; return _floorDistance < FLOOR_PROXIMITY_THRESHOLD; } -void DynamicCharacterController::setHovering(bool hover) { +void MyAvatarController::setHovering(bool hover) { if (hover != _isHovering) { _isHovering = hover; _isJumping = false; @@ -198,7 +202,7 @@ void DynamicCharacterController::setHovering(bool hover) { } } -void DynamicCharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { +void MyAvatarController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { _boxScale = scale; float x = _boxScale.x; @@ -231,15 +235,17 @@ void DynamicCharacterController::setLocalBoundingBox(const glm::vec3& corner, co _shapeLocalOffset = corner + 0.5f * _boxScale; } -bool DynamicCharacterController::needsRemoval() const { +/* moved to base class +bool MyAvatarController::needsRemoval() const { return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION); } -bool DynamicCharacterController::needsAddition() const { +bool MyAvatarController::needsAddition() const { return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION); } +*/ -void DynamicCharacterController::setEnabled(bool enabled) { +void MyAvatarController::setEnabled(bool enabled) { if (enabled != _enabled) { if (enabled) { // Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit. @@ -257,7 +263,8 @@ void DynamicCharacterController::setEnabled(bool enabled) { } } -void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) { +/* moved to base class +void MyAvatarController::setDynamicsWorld(btDynamicsWorld* world) { if (_dynamicsWorld != world) { if (_dynamicsWorld) { if (_rigidBody) { @@ -284,9 +291,9 @@ void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) { } else { _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; } -} +}*/ -void DynamicCharacterController::updateShapeIfNecessary() { +void MyAvatarController::updateShapeIfNecessary() { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { // make sure there is NO pending removal from simulation at this point // (don't want to delete _rigidBody out from under the simulation) @@ -321,8 +328,8 @@ void DynamicCharacterController::updateShapeIfNecessary() { _rigidBody = new btRigidBody(mass, nullptr, _shape, inertia); _rigidBody->setSleepingThresholds(0.0f, 0.0f); _rigidBody->setAngularFactor(0.0f); - _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); + _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()), + glmToBullet(_avatar->getPosition()))); if (_isHovering) { _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); } else { @@ -335,7 +342,7 @@ void DynamicCharacterController::updateShapeIfNecessary() { } } -void DynamicCharacterController::updateUpAxis(const glm::quat& rotation) { +void MyAvatarController::updateUpAxis(const glm::quat& rotation) { btVector3 oldUp = _currentUp; _currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS); if (!_isHovering) { @@ -346,24 +353,57 @@ void DynamicCharacterController::updateUpAxis(const glm::quat& rotation) { } } -void DynamicCharacterController::preSimulation(btScalar timeStep) { - if (_enabled && _dynamicsWorld) { - glm::quat rotation = _avatarData->getOrientation(); +void MyAvatarController::setAvatarPositionAndOrientation( + const glm::vec3& position, + const glm::quat& orientation) { + // TODO: update gravity if up has changed + updateUpAxis(orientation); + btQuaternion bodyOrientation = glmToBullet(orientation); + btVector3 bodyPosition = glmToBullet(position + orientation * _shapeLocalOffset); + _avatarBodyTransform = btTransform(bodyOrientation, bodyPosition); +} + +void MyAvatarController::getAvatarPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const { + if (_enabled && _rigidBody) { + const btTransform& avatarTransform = _rigidBody->getWorldTransform(); + rotation = bulletToGLM(avatarTransform.getRotation()); + position = bulletToGLM(avatarTransform.getOrigin()) - rotation * _shapeLocalOffset; + } +} + +void MyAvatarController::setTargetVelocity(const glm::vec3& velocity) { + //_walkVelocity = glmToBullet(_avatarData->getTargetVelocity()); + _walkVelocity = glmToBullet(velocity); +} + +void MyAvatarController::setHMDVelocity(const glm::vec3& velocity) { + _hmdVelocity = glmToBullet(velocity); +} + +glm::vec3 MyAvatarController::getLinearVelocity() const { + glm::vec3 velocity(0.0f); + if (_rigidBody) { + velocity = bulletToGLM(_rigidBody->getLinearVelocity()); + } + return velocity; +} + +void MyAvatarController::preSimulation() { + if (_enabled && _dynamicsWorld) { + /* + glm::quat rotation = _avatarData->getOrientation(); // TODO: update gravity if up has changed updateUpAxis(rotation); - glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; _rigidBody->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); + */ - // the rotation is dictated by AvatarData - btTransform xform = _rigidBody->getWorldTransform(); - xform.setRotation(glmToBullet(rotation)); - _rigidBody->setWorldTransform(xform); + _rigidBody->setWorldTransform(_avatarBodyTransform); // scan for distant floor // rayStart is at center of bottom sphere - btVector3 rayStart = xform.getOrigin() - _halfHeight * _currentUp; + btVector3 rayStart = _avatarBodyTransform.getOrigin() - _halfHeight * _currentUp; // rayEnd is straight down MAX_FALL_HEIGHT btScalar rayLength = _radius + MAX_FALL_HEIGHT; @@ -388,8 +428,6 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) { setHovering(true); } - _walkVelocity = glmToBullet(_avatarData->getTargetVelocity()); - if (_pendingFlags & PENDING_FLAG_JUMP) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (onGround()) { @@ -402,7 +440,9 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) { } } -void DynamicCharacterController::postSimulation() { +void MyAvatarController::postSimulation() { + /* + _lastStepDuration += timeStep; if (_enabled && _rigidBody) { const btTransform& avatarTransform = _rigidBody->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); @@ -410,5 +450,8 @@ void DynamicCharacterController::postSimulation() { _avatarData->nextAttitude(position - rotation * _shapeLocalOffset, rotation); _avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity())); + _avatarData->applySimulationTime(_lastStepDuration); } + _lastStepDuration = 0.0f; + */ } diff --git a/interface/src/avatar/MyAvatarController.h b/interface/src/avatar/MyAvatarController.h new file mode 100644 index 0000000000..a973905653 --- /dev/null +++ b/interface/src/avatar/MyAvatarController.h @@ -0,0 +1,106 @@ +// +// MyAvatar.h +// interface/src/avatar +// +// Created by AndrewMeadows 2015.10.21 +// 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_MyAvatarController_h +#define hifi_MyAvatarController_h + +#include +#include + +#include +#include + +class btCollisionShape; +class MyAvatar; + +class MyAvatarController : public CharacterController { +public: + MyAvatarController(MyAvatar* avatar); + ~MyAvatarController (); + + // TODO: implement these when needed + virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) override { assert(false); } + virtual void reset(btCollisionWorld* collisionWorld) override { } + virtual void warp(const btVector3& origin) override { } + virtual void debugDraw(btIDebugDraw* debugDrawer) override { } + virtual void setUpInterpolate(bool value) override { } + + // overrides from btCharacterControllerInterface + virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) override { + preStep(collisionWorld); + playerStep(collisionWorld, deltaTime); + } + virtual void preStep(btCollisionWorld* collisionWorld) override; + virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt) override; + virtual bool canJump() const override { assert(false); return false; } // never call this + virtual void jump() override; // call this every frame the jump button is pressed + virtual bool onGround() const override; + + // overrides from CharacterController + virtual void preSimulation() override; + virtual void postSimulation() override; + virtual void incrementSimulationTime(btScalar timeStep) override { _lastStepDuration += timeStep; } + + bool isHovering() const { return _isHovering; } + void setHovering(bool enabled); + + void setEnabled(bool enabled); + bool isEnabled() const { return _enabled && _dynamicsWorld; } + + void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); + + virtual void updateShapeIfNecessary() override; + + void setAvatarPositionAndOrientation( const glm::vec3& position, const glm::quat& orientation); + void getAvatarPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const; + + void setTargetVelocity(const glm::vec3& velocity); + void setHMDVelocity(const glm::vec3& velocity); + + glm::vec3 getLinearVelocity() const; + +protected: + void updateUpAxis(const glm::quat& rotation); + +protected: + btVector3 _currentUp; + btVector3 _walkVelocity; + btVector3 _hmdVelocity; + btTransform _avatarBodyTransform; + + glm::vec3 _shapeLocalOffset; + glm::vec3 _boxScale; // used to compute capsule shape + + quint64 _jumpToHoverStart; + + btCollisionShape* _shape { nullptr }; + MyAvatar* _avatar { nullptr }; + + btScalar _halfHeight; + btScalar _radius; + + btScalar _floorDistance; + + btScalar _gravity; + + btScalar _jumpSpeed; + btScalar _lastStepDuration; + + bool _enabled; + bool _isOnGround; + bool _isJumping; + bool _isFalling; + bool _isHovering; + bool _isPushingUp; +}; + +#endif // hifi_MyAvatarController_h diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp new file mode 100644 index 0000000000..9ba22cf2db --- /dev/null +++ b/libraries/physics/src/CharacterController.cpp @@ -0,0 +1,52 @@ +// +// CharacterControllerInterface.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.10.21 +// 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 +// + +#include "CharacterController.h" + +#include "PhysicsCollisionGroups.h" + +bool CharacterController::needsRemoval() const { + return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION); +} + +bool CharacterController::needsAddition() const { + return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION); +} + +void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { + if (_dynamicsWorld != world) { + if (_dynamicsWorld) { + if (_rigidBody) { + _dynamicsWorld->removeRigidBody(_rigidBody); + _dynamicsWorld->removeAction(this); + } + _dynamicsWorld = nullptr; + } + if (world && _rigidBody) { + _dynamicsWorld = world; + _pendingFlags &= ~ PENDING_FLAG_JUMP; + _dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR); + _dynamicsWorld->addAction(this); + //reset(_dynamicsWorld); + } + } + if (_dynamicsWorld) { + if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { + // shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set + _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION; + } else { + _pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION; + } + } else { + _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; + } +} + diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h new file mode 100644 index 0000000000..cff257a790 --- /dev/null +++ b/libraries/physics/src/CharacterController.h @@ -0,0 +1,60 @@ +// +// CharacterControllerInterface.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.10.21 +// 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_CharacterControllerInterface_h +#define hifi_CharacterControllerInterface_h + +#include +#include +#include +#include + +const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; +const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; +const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2; +const uint32_t PENDING_FLAG_JUMP = 1U << 3; + + +class btRigidBody; +class btCollisionWorld; +class btDynamicsWorld; + +class CharacterController : public btCharacterControllerInterface { +public: + bool needsRemoval() const; + bool needsAddition() const; + void setDynamicsWorld(btDynamicsWorld* world); + btCollisionObject* getCollisionObject() { return _rigidBody; } + + virtual void updateShapeIfNecessary() = 0; + virtual void preSimulation() = 0; + virtual void incrementSimulationTime(btScalar stepTime) = 0; + virtual void postSimulation() = 0; + + virtual void setWalkDirection(const btVector3 &walkDirection) { assert(false); } + + /* these from btCharacterControllerInterface remain to be overridden + virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) = 0; + virtual void reset() = 0; + virtual void warp(const btVector3 &origin) = 0; + virtual void preStep(btCollisionWorld *collisionWorld) = 0; + virtual void playerStep(btCollisionWorld *collisionWorld, btScalar dt) = 0; + virtual bool canJump() const = 0; + virtual void jump() = 0; + virtual bool onGround() const = 0; + */ +protected: + btDynamicsWorld* _dynamicsWorld { nullptr }; + btRigidBody* _rigidBody { nullptr }; + uint32_t _pendingFlags { 0 }; +}; + +#endif // hifi_CharacterControllerInterface_h diff --git a/libraries/physics/src/DynamicCharacterController.h b/libraries/physics/src/DynamicCharacterController.h deleted file mode 100644 index d26c69c5a5..0000000000 --- a/libraries/physics/src/DynamicCharacterController.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef hifi_DynamicCharacterController_h -#define hifi_DynamicCharacterController_h - -#include -#include - -#include - -class btCollisionShape; -class btRigidBody; -class btCollisionWorld; - -const int NUM_CHARACTER_CONTROLLER_RAYS = 2; - -class DynamicCharacterController : public btCharacterControllerInterface -{ -protected: - btScalar _halfHeight; - btScalar _radius; - btCollisionShape* _shape; - btRigidBody* _rigidBody; - - btVector3 _currentUp; - - btScalar _floorDistance; - - btVector3 _walkVelocity; - btScalar _gravity; - - glm::vec3 _shapeLocalOffset; - glm::vec3 _boxScale; // used to compute capsule shape - AvatarData* _avatarData = nullptr; - - bool _enabled; - bool _isOnGround; - bool _isJumping; - bool _isFalling; - bool _isHovering; - bool _isPushingUp; - quint64 _jumpToHoverStart; - uint32_t _pendingFlags; - - btDynamicsWorld* _dynamicsWorld = nullptr; - - btScalar _jumpSpeed; - -public: - DynamicCharacterController(AvatarData* avatarData); - ~DynamicCharacterController (); - - virtual void setWalkDirection(const btVector3& walkDirection); - virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) { assert(false); } - - // TODO: implement these when needed - virtual void reset(btCollisionWorld* collisionWorld) { } - virtual void warp(const btVector3& origin) { } - virtual void debugDraw(btIDebugDraw* debugDrawer) { } - virtual void setUpInterpolate(bool value) { } - - btCollisionObject* getCollisionObject() { return _rigidBody; } - - ///btActionInterface interface - virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) { - preStep(collisionWorld); - playerStep(collisionWorld, deltaTime); - } - - virtual void preStep(btCollisionWorld* collisionWorld); - virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt); - - virtual bool canJump() const { assert(false); return false; } // never call this - virtual void jump(); // call this every frame the jump button is pressed - virtual bool onGround() const; - bool isHovering() const { return _isHovering; } - void setHovering(bool enabled); - - bool needsRemoval() const; - bool needsAddition() const; - void setEnabled(bool enabled); - bool isEnabled() const { return _enabled && _dynamicsWorld; } - - void setDynamicsWorld(btDynamicsWorld* world); - - void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); - bool needsShapeUpdate() const; - void updateShapeIfNecessary(); - - void preSimulation(btScalar timeStep); - void postSimulation(); - -protected: - void updateUpAxis(const glm::quat& rotation); -}; - -#endif // hifi_DynamicCharacterController_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 75273e62ba..a6b8dbe959 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -11,6 +11,7 @@ #include +#include "CharacterController.h" #include "ObjectMotionState.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" @@ -23,7 +24,7 @@ uint32_t PhysicsEngine::getNumSubsteps() { PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), - _characterController(nullptr) { + _myAvatarController(nullptr) { // build table of masks with their group as the key _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT); _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC); @@ -38,8 +39,8 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : } PhysicsEngine::~PhysicsEngine() { - if (_characterController) { - _characterController->setDynamicsWorld(nullptr); + if (_myAvatarController) { + _myAvatarController->setDynamicsWorld(nullptr); } delete _collisionConfig; delete _collisionDispatcher; @@ -239,16 +240,18 @@ void PhysicsEngine::stepSimulation() { _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); - // TODO: move character->preSimulation() into relayIncomingChanges - if (_characterController) { - if (_characterController->needsRemoval()) { - _characterController->setDynamicsWorld(nullptr); + if (_myAvatarController) { + // ADEBUG TODO: move this stuff outside and in front of stepSimulation, because + // the updateShapeIfNecessary() call needs info from MyAvatar and should + // be done on the main thread during the pre-simulation stuff + if (_myAvatarController->needsRemoval()) { + _myAvatarController->setDynamicsWorld(nullptr); } - _characterController->updateShapeIfNecessary(); - if (_characterController->needsAddition()) { - _characterController->setDynamicsWorld(_dynamicsWorld); + _myAvatarController->updateShapeIfNecessary(); + if (_myAvatarController->needsAddition()) { + _myAvatarController->setDynamicsWorld(_dynamicsWorld); } - _characterController->preSimulation(timeStep); + _myAvatarController->preSimulation(); } int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); @@ -257,8 +260,8 @@ void PhysicsEngine::stepSimulation() { _numSubsteps += (uint32_t)numSubsteps; ObjectMotionState::setWorldSimulationStep(_numSubsteps); - if (_characterController) { - _characterController->postSimulation(); + if (_myAvatarController) { + _myAvatarController->postSimulation(); } updateContactMap(); _hasOutgoingChanges = true; @@ -268,7 +271,7 @@ void PhysicsEngine::stepSimulation() { void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { BT_PROFILE("ownershipInfection"); - const btCollisionObject* characterObject = _characterController ? _characterController->getCollisionObject() : nullptr; + const btCollisionObject* characterObject = _myAvatarController ? _myAvatarController->getCollisionObject() : nullptr; ObjectMotionState* motionStateA = static_cast(objectA->getUserPointer()); ObjectMotionState* motionStateB = static_cast(objectB->getUserPointer()); @@ -431,15 +434,15 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) { } } -void PhysicsEngine::setCharacterController(DynamicCharacterController* character) { - if (_characterController != character) { - if (_characterController) { +void PhysicsEngine::setCharacterController(CharacterController* character) { + if (_myAvatarController != character) { + if (_myAvatarController) { // remove the character from the DynamicsWorld immediately - _characterController->setDynamicsWorld(nullptr); - _characterController = nullptr; + _myAvatarController->setDynamicsWorld(nullptr); + _myAvatarController = nullptr; } // the character will be added to the DynamicsWorld later - _characterController = character; + _myAvatarController = character; } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 0a317652da..e7b5fd79d4 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -21,13 +21,14 @@ #include "BulletUtil.h" #include "ContactInfo.h" -#include "DynamicCharacterController.h" #include "ObjectMotionState.h" #include "ThreadSafeDynamicsWorld.h" #include "ObjectAction.h" const float HALF_SIMULATION_EXTENT = 512.0f; // meters +class CharacterController; + // simple class for keeping track of contacts class ContactKey { public: @@ -87,7 +88,7 @@ public: void removeRigidBody(btRigidBody* body); - void setCharacterController(DynamicCharacterController* character); + void setCharacterController(CharacterController* character); void dumpNextStats() { _dumpNextStats = true; } @@ -117,7 +118,7 @@ private: uint32_t _lastNumSubstepsAtUpdateInternal = 0; /// character collisions - DynamicCharacterController* _characterController = NULL; + CharacterController* _myAvatarController; bool _dumpNextStats = false; bool _hasOutgoingChanges = false;