From e9fd439ffd0210b0720b084bcecf9a1b91c07eb3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 28 Jan 2016 18:27:49 -0800 Subject: [PATCH 1/9] Added inAir animations --- .../defaultAvatar_full/avatar-animation.json | 80 +++++++++++++++++-- interface/src/avatar/SkeletonModel.cpp | 9 ++- libraries/animation/src/Rig.cpp | 38 ++++++++- libraries/animation/src/Rig.h | 11 ++- libraries/physics/src/CharacterController.h | 1 + 5 files changed, 125 insertions(+), 14 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 42ff64abc6..46912120db 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -247,7 +247,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -263,7 +264,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -278,7 +280,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -293,7 +296,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -308,7 +312,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -323,7 +328,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -338,7 +344,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -353,7 +360,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -385,8 +393,18 @@ "interpTarget": 6, "interpDuration": 6, "transitions": [ + { "var": "isAway", "state": "awayIntro" }, { "var": "isNotFlying", "state": "idle" } ] + }, + { + "id": "inAir", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isAway", "state": "awayIntro" }, + { "var": "isNotInAir", "state": "idle" } + ] } ] }, @@ -685,6 +703,52 @@ "loopFlag": true }, "children": [] + }, + { + "id": "inAir", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirPreApex", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 0.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "inAirApex", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", + "startFrame": 6.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "inAirPostApex", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", + "startFrame": 11.0, + "endFrame": 11.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] } ] } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6198a1b0a0..50cbbbbb00 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -133,7 +133,14 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateFromHandParameters(handParams, deltaTime); - _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), myAvatar->isHovering()); + Rig::CharacterControllerState ccState = Rig::CharacterControllerState::Ground; + if (myAvatar->getCharacterController()->isHovering()) { + ccState = Rig::CharacterControllerState::Hover; + } else if (myAvatar->getCharacterController()->isJumping()) { + ccState = Rig::CharacterControllerState::Jump; + } + + _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState); // evaluate AnimGraph animation and update jointStates. Model::updateRig(deltaTime, parentTransform); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 4d72bfbaea..94bc23cf06 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -504,7 +504,7 @@ static const std::vector FORWARD_SPEEDS = { 0.4f, 1.4f, 4.5f }; // m/s static const std::vector BACKWARD_SPEEDS = { 0.6f, 1.45f }; // m/s static const std::vector LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s -void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering) { +void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState) { glm::vec3 front = worldRotation * IDENTITY_FRONT; @@ -572,11 +572,16 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos const float TURN_ENTER_SPEED_THRESHOLD = 0.5f; // rad/sec const float TURN_EXIT_SPEED_THRESHOLD = 0.2f; // rad/sec - if (isHovering) { + if (ccState == CharacterControllerState::Hover) { if (_desiredState != RigRole::Hover) { _desiredStateAge = 0.0f; } _desiredState = RigRole::Hover; + } else if (ccState == CharacterControllerState::Jump) { + if (_desiredState != RigRole::Jump) { + _desiredStateAge = 0.0f; + } + _desiredState = RigRole::Jump; } else { float moveThresh; if (_state != RigRole::Move) { @@ -662,6 +667,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); } } else if (_state == RigRole::Turn) { if (turningSpeed > 0.0f) { @@ -682,6 +689,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotMoving", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); } else if (_state == RigRole::Idle ) { // default anim vars to notMoving and notTurning _animVars.set("isMovingForward", false); @@ -694,7 +703,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); - } else { + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Hover) { // flying. _animVars.set("isMovingForward", false); _animVars.set("isMovingBackward", false); @@ -706,6 +717,27 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", true); _animVars.set("isNotFlying", false); + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Jump) { + // jumping in-air + _animVars.set("isMovingForward", false); + _animVars.set("isMovingBackward", false); + _animVars.set("isMovingLeft", false); + _animVars.set("isMovingRight", false); + _animVars.set("isNotMoving", true); + _animVars.set("isTurningLeft", false); + _animVars.set("isTurningRight", false); + _animVars.set("isNotTurning", true); + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); + _animVars.set("isInAir", true); + _animVars.set("isNotInAir", false); + + // compute blend based on velocity + const float JUMP_SPEED = 3.5f; + float alpha = glm::clamp(-worldVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f; + _animVars.set("inAirAlpha", alpha); } t += deltaTime; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index cf96c6dc16..50d775d7f5 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -73,6 +73,12 @@ public: glm::quat rightOrientation = glm::quat(); // rig space (z forward) }; + enum class CharacterControllerState { + Ground = 0, + Jump, + Hover + }; + virtual ~Rig() {} void destroyAnimGraph(); @@ -141,7 +147,7 @@ public: glm::mat4 getJointTransform(int jointIndex) const; // Start or stop animations as needed. - void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering); + void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState); // Regardless of who started the animations or how many, update the joints. void updateAnimations(float deltaTime, glm::mat4 rootTransform); @@ -271,7 +277,8 @@ public: Idle = 0, Turn, Move, - Hover + Hover, + Jump }; RigRole _state { RigRole::Idle }; RigRole _desiredState { RigRole::Idle }; diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index c1c64a1a02..3c9fc476ca 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -75,6 +75,7 @@ public: glm::vec3 getLinearVelocity() const; + bool isJumping() const { return _isJumping; } bool isHovering() const { return _isHovering; } void setHovering(bool enabled); From 61c55ebf6c96857559280116a830dec7aa5c410a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 29 Jan 2016 11:57:14 -0800 Subject: [PATCH 2/9] Updated character controller with a state enumeration Also, adjusted checkForSupport logic such that very slanted walls are not considered support. --- interface/src/avatar/MyAvatar.cpp | 7 +-- interface/src/avatar/MyAvatar.h | 2 - .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 20 ++++--- libraries/animation/src/Rig.cpp | 8 +-- libraries/animation/src/Rig.h | 4 +- libraries/physics/src/CharacterController.cpp | 60 +++++++++---------- libraries/physics/src/CharacterController.h | 17 +++--- 8 files changed, 62 insertions(+), 58 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0c0b51bda2..0aadaed150 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1510,7 +1510,8 @@ void MyAvatar::updatePosition(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity; - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering()); + bool isHovering = _characterController.getState() == CharacterController::State::Hover; + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); // rotate back into world-frame @@ -1579,10 +1580,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float return false; } -bool MyAvatar::isHovering() const { - return _characterController.isHovering(); -} - void MyAvatar::increaseSize() { if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { _targetScale *= (1.0f + SCALING_RATIO); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 760f390de9..ac77784077 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -239,8 +239,6 @@ public: glm::quat getCustomListenOrientation() { return _customListenOrientation; } void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; } - bool isHovering() const; - public slots: void increaseSize(); void decreaseSize(); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index c7f2945757..07156e9294 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -67,7 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() { _rigidBody->setAngularFactor(0.0f); _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()), glmToBullet(_avatar->getPosition()))); - if (_isHovering) { + if (_state == State::Hover) { _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); } else { _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 50cbbbbb00..c8f14578b4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -72,6 +72,18 @@ void SkeletonModel::initJointStates() { emit skeletonLoaded(); } +Rig::CharacterControllerState convertCharacterControllerState(CharacterController::State state) { + switch (state) { + default: + case CharacterController::State::Ground: + return Rig::CharacterControllerState::Ground; + case CharacterController::State::InAir: + return Rig::CharacterControllerState::InAir; + case CharacterController::State::Hover: + return Rig::CharacterControllerState::Hover; + }; +} + // Called within Model::simulate call, below. void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Head* head = _owningAvatar->getHead(); @@ -133,13 +145,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateFromHandParameters(handParams, deltaTime); - Rig::CharacterControllerState ccState = Rig::CharacterControllerState::Ground; - if (myAvatar->getCharacterController()->isHovering()) { - ccState = Rig::CharacterControllerState::Hover; - } else if (myAvatar->getCharacterController()->isJumping()) { - ccState = Rig::CharacterControllerState::Jump; - } - + Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState()); _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState); // evaluate AnimGraph animation and update jointStates. diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 94bc23cf06..33c8f33ac8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -577,11 +577,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _desiredStateAge = 0.0f; } _desiredState = RigRole::Hover; - } else if (ccState == CharacterControllerState::Jump) { - if (_desiredState != RigRole::Jump) { + } else if (ccState == CharacterControllerState::InAir) { + if (_desiredState != RigRole::InAir) { _desiredStateAge = 0.0f; } - _desiredState = RigRole::Jump; + _desiredState = RigRole::InAir; } else { float moveThresh; if (_state != RigRole::Move) { @@ -719,7 +719,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotFlying", false); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); - } else if (_state == RigRole::Jump) { + } else if (_state == RigRole::InAir) { // jumping in-air _animVars.set("isMovingForward", false); _animVars.set("isMovingBackward", false); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 50d775d7f5..dc07a32efd 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -75,7 +75,7 @@ public: enum class CharacterControllerState { Ground = 0, - Jump, + InAir, Hover }; @@ -278,7 +278,7 @@ public: Turn, Move, Hover, - Jump + InAir }; RigRole _state { RigRole::Idle }; RigRole _desiredState { RigRole::Idle }; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index a30feec150..055f846793 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -1,4 +1,4 @@ -// + // // CharacterControllerInterface.cpp // libraries/physcis/src // @@ -51,10 +51,7 @@ CharacterController::CharacterController() { _followDesiredBodyTransform.setIdentity(); _followTimeRemaining = 0.0f; _jumpSpeed = JUMP_SPEED; - _isOnGround = false; - _isJumping = false; - _isFalling = false; - _isHovering = true; + _state = State::Hover; _isPushingUp = false; _jumpToHoverStart = 0; _followTime = 0.0f; @@ -107,6 +104,8 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } } +static const float COS_PI_OVER_THREE = cosf(PI / 3.0f); + bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) const { int numManifolds = collisionWorld->getDispatcher()->getNumManifolds(); for (int i = 0; i < numManifolds; i++) { @@ -119,8 +118,10 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) cons btManifoldPoint& pt = contactManifold->getContactPoint(j); // check to see if contact point is touching the bottom sphere of the capsule. + // and the contact normal is not slanted too much. float contactPointY = (obA == _rigidBody) ? pt.m_localPointA.getY() : pt.m_localPointB.getY(); - if (contactPointY < -_halfHeight) { + btVector3 normal = (obA == _rigidBody) ? pt.m_normalWorldOnB : -pt.m_normalWorldOnB; + if (contactPointY < -_halfHeight && normal.dot(_currentUp) > COS_PI_OVER_THREE) { return true; } } @@ -165,7 +166,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { } const btScalar MIN_SPEED = 0.001f; - if (_isHovering) { + if (_state == State::Hover) { if (desiredSpeed < MIN_SPEED) { if (actualSpeed < MIN_SPEED) { _rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); @@ -255,9 +256,9 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { void CharacterController::jump() { // check for case where user is holding down "jump" key... - // we'll eventually tansition to "hover" - if (!_isJumping) { - if (!_isHovering) { + // we'll eventually transition to "hover" + if (_state != State::InAir) { + if (_state != State::Hover) { _jumpToHoverStart = usecTimestampNow(); _pendingFlags |= PENDING_FLAG_JUMP; } @@ -266,7 +267,7 @@ void CharacterController::jump() { const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { _isPushingUp = true; - setHovering(true); + setState(State::Hover); } } } @@ -276,19 +277,19 @@ bool CharacterController::onGround() const { return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport; } -void CharacterController::setHovering(bool hover) { - if (hover != _isHovering) { - _isHovering = hover; - _isJumping = false; - +void CharacterController::setState(State desiredState) { + if (desiredState == State::Hover && _state != State::Hover) { + // hover enter if (_rigidBody) { - if (hover) { - _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - } else { - _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); - } + _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + } + } else if (_state == State::Hover && desiredState != State::Hover) { + // hover exit + if (_rigidBody) { + _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); } } + _state = desiredState; } void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { @@ -335,9 +336,8 @@ void CharacterController::setEnabled(bool enabled) { _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; - _isOnGround = false; } - setHovering(true); + setState(State::Hover); _enabled = enabled; } } @@ -345,7 +345,7 @@ void CharacterController::setEnabled(bool enabled) { void CharacterController::updateUpAxis(const glm::quat& rotation) { btVector3 oldUp = _currentUp; _currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS); - if (!_isHovering) { + if (_state != State::Hover) { const btScalar MIN_UP_ERROR = 0.01f; if (oldUp.distance(_currentUp) > MIN_UP_ERROR) { _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); @@ -425,23 +425,23 @@ void CharacterController::preSimulation() { if (rayCallback.hasHit()) { _floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius; const btScalar MIN_HOVER_HEIGHT = 3.0f; - if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) { - setHovering(false); + if (_state == State::Hover && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) { + setState(State::InAir); } // TODO: use collision events rather than ray-trace test to disable jumping const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_floorDistance < JUMP_PROXIMITY_THRESHOLD) { - _isJumping = false; + if (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport) { + setState(State::Ground); } } else if (!_hasSupport) { _floorDistance = FLT_MAX; - setHovering(true); + setState(State::Hover); } if (_pendingFlags & PENDING_FLAG_JUMP) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (onGround()) { - _isJumping = true; + setState(State::InAir); btVector3 velocity = _rigidBody->getLinearVelocity(); velocity += _jumpSpeed * _currentUp; _rigidBody->setLinearVelocity(velocity); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 3c9fc476ca..c8b360237d 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -75,9 +75,13 @@ public: glm::vec3 getLinearVelocity() const; - bool isJumping() const { return _isJumping; } - bool isHovering() const { return _isHovering; } - void setHovering(bool enabled); + enum class State { + Ground = 0, + InAir, + Hover + }; + + State getState() const { return _state; } void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); @@ -87,6 +91,8 @@ public: bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); protected: + void setState(State state); + void updateUpAxis(const glm::quat& rotation); bool checkForSupport(btCollisionWorld* collisionWorld) const; @@ -117,10 +123,7 @@ protected: btQuaternion _followAngularDisplacement; bool _enabled; - bool _isOnGround; - bool _isJumping; - bool _isFalling; - bool _isHovering; + State _state; bool _isPushingUp; btDynamicsWorld* _dynamicsWorld { nullptr }; From 2936811484541b5b6133f8e1560393a70a3a8e56 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 29 Jan 2016 18:05:18 -0800 Subject: [PATCH 3/9] Added takeoff animation, WIP Character controller still has some jump/in-air bugs. --- .../defaultAvatar_full/avatar-animation.json | 39 ++++++++++++++++--- interface/src/avatar/SkeletonModel.cpp | 2 + libraries/animation/src/Rig.cpp | 35 +++++++++++++++++ libraries/animation/src/Rig.h | 2 + libraries/physics/src/CharacterController.cpp | 33 ++++++++++------ libraries/physics/src/CharacterController.h | 2 + 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 46912120db..37da0c37cc 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -248,6 +248,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -265,6 +266,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -281,6 +283,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -297,6 +300,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -313,6 +317,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -329,6 +334,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -345,6 +351,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -361,6 +368,7 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -397,10 +405,19 @@ { "var": "isNotFlying", "state": "idle" } ] }, + { + "id": "takeoff", + "interpTarget": 0, + "interpDuration": 6, + "transitions": [ + { "var": "isAway", "state": "awayIntro" }, + { "var": "isNotTakeoff", "state": "inAir" } + ] + }, { "id": "inAir", - "interpTarget": 3, - "interpDuration": 3, + "interpTarget": 0, + "interpDuration": 6, "transitions": [ { "var": "isAway", "state": "awayIntro" }, { "var": "isNotInAir", "state": "idle" } @@ -704,6 +721,18 @@ }, "children": [] }, + { + "id": "takeoff", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_takeoff.fbx", + "startFrame": 1.0, + "endFrame": 2.5, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, { "id": "inAir", "type": "blendLinear", @@ -720,7 +749,7 @@ "startFrame": 0.0, "endFrame": 0.0, "timeScale": 0.0, - "loopFlag": true + "loopFlag": false }, "children": [] }, @@ -732,7 +761,7 @@ "startFrame": 6.0, "endFrame": 6.0, "timeScale": 1.0, - "loopFlag": true + "loopFlag": false }, "children": [] }, @@ -744,7 +773,7 @@ "startFrame": 11.0, "endFrame": 11.0, "timeScale": 1.0, - "loopFlag": true + "loopFlag": false }, "children": [] } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c8f14578b4..92bdef686d 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -77,6 +77,8 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle default: case CharacterController::State::Ground: return Rig::CharacterControllerState::Ground; + case CharacterController::State::Takeoff: + return Rig::CharacterControllerState::Takeoff; case CharacterController::State::InAir: return Rig::CharacterControllerState::InAir; case CharacterController::State::Hover: diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 33c8f33ac8..9e811fa358 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -582,6 +582,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _desiredStateAge = 0.0f; } _desiredState = RigRole::InAir; + } else if (ccState == CharacterControllerState::Takeoff) { + if (_desiredState != RigRole::Takeoff) { + _desiredStateAge = 0.0f; + } + _desiredState = RigRole::Takeoff; } else { float moveThresh; if (_state != RigRole::Move) { @@ -667,6 +672,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); } @@ -689,8 +696,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotMoving", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Idle ) { // default anim vars to notMoving and notTurning _animVars.set("isMovingForward", false); @@ -703,8 +713,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Hover) { // flying. _animVars.set("isMovingForward", false); @@ -717,8 +730,28 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", true); _animVars.set("isNotFlying", false); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); + + } else if (_state == RigRole::Takeoff) { + // jumping in-air + _animVars.set("isMovingForward", false); + _animVars.set("isMovingBackward", false); + _animVars.set("isMovingLeft", false); + _animVars.set("isMovingRight", false); + _animVars.set("isNotMoving", true); + _animVars.set("isTurningLeft", false); + _animVars.set("isTurningRight", false); + _animVars.set("isNotTurning", true); + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", true); + _animVars.set("isNotTakeoff", false); + _animVars.set("isInAir", true); + _animVars.set("isNotInAir", false); + } else if (_state == RigRole::InAir) { // jumping in-air _animVars.set("isMovingForward", false); @@ -731,6 +764,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", true); _animVars.set("isNotInAir", false); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index dc07a32efd..e12af16e41 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -75,6 +75,7 @@ public: enum class CharacterControllerState { Ground = 0, + Takeoff, InAir, Hover }; @@ -278,6 +279,7 @@ public: Turn, Move, Hover, + Takeoff, InAir }; RigRole _state { RigRole::Idle }; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 055f846793..93b924d9bc 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -54,6 +54,7 @@ CharacterController::CharacterController() { _state = State::Hover; _isPushingUp = false; _jumpToHoverStart = 0; + _takeoffToInAirStart = 0; _followTime = 0.0f; _followLinearDisplacement = btVector3(0, 0, 0); _followAngularDisplacement = btQuaternion::getIdentity(); @@ -257,18 +258,18 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { void CharacterController::jump() { // check for case where user is holding down "jump" key... // we'll eventually transition to "hover" - if (_state != State::InAir) { - if (_state != State::Hover) { - _jumpToHoverStart = usecTimestampNow(); - _pendingFlags |= PENDING_FLAG_JUMP; - } - } else { + if (_state == State::Hover) { quint64 now = usecTimestampNow(); const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { _isPushingUp = true; setState(State::Hover); } + } else { + if (_state != State::Takeoff) { + _jumpToHoverStart = usecTimestampNow(); + _pendingFlags |= PENDING_FLAG_JUMP; + } } } @@ -430,7 +431,7 @@ void CharacterController::preSimulation() { } // TODO: use collision events rather than ray-trace test to disable jumping const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport) { + if (_state != State::Takeoff && (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport)) { setState(State::Ground); } } else if (!_hasSupport) { @@ -438,15 +439,25 @@ void CharacterController::preSimulation() { setState(State::Hover); } + quint64 now = usecTimestampNow(); + if (_pendingFlags & PENDING_FLAG_JUMP) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (onGround()) { - setState(State::InAir); - btVector3 velocity = _rigidBody->getLinearVelocity(); - velocity += _jumpSpeed * _currentUp; - _rigidBody->setLinearVelocity(velocity); + setState(State::Takeoff); + _takeoffToInAirStart = now; } } + + const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; + if (_state == State::Takeoff && (now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { + setState(State::InAir); + + _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; + btVector3 velocity = _rigidBody->getLinearVelocity(); + velocity += _jumpSpeed * _currentUp; + _rigidBody->setLinearVelocity(velocity); + } } _followTime = 0.0f; diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index c8b360237d..5470104a1a 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -77,6 +77,7 @@ public: enum class State { Ground = 0, + Takeoff, InAir, Hover }; @@ -107,6 +108,7 @@ protected: glm::vec3 _boxScale; // used to compute capsule shape + quint64 _takeoffToInAirStart; quint64 _jumpToHoverStart; btScalar _halfHeight; From 47f3ce3786e97f744d7338bd5cc694511df05891 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 1 Feb 2016 14:18:30 -0800 Subject: [PATCH 4/9] CharacterController jump is more reliable. --- libraries/animation/src/Rig.cpp | 7 ++ libraries/physics/src/CharacterController.cpp | 80 +++++++++++++------ 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 9e811fa358..64935691c8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -624,6 +624,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos const float STATE_CHANGE_HYSTERESIS_TIMER = 0.1f; + // Skip hystersis timer for jump transitions. + if (_desiredState == RigRole::Takeoff) { + _desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER; + } else if (_state == RigRole::InAir && _desiredState != RigRole::InAir) { + _desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER; + } + if ((_desiredStateAge >= STATE_CHANGE_HYSTERESIS_TIMER) && _desiredState != _state) { _state = _desiredState; _desiredStateAge = 0.0f; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 93b924d9bc..ad6c9545d2 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -1,4 +1,4 @@ - // +// // CharacterControllerInterface.cpp // libraries/physcis/src // @@ -15,11 +15,14 @@ #include "PhysicsCollisionGroups.h" #include "ObjectMotionState.h" +#include "PhysicsLogging.h" const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; +#define DEBUG_STATE_CHANGE + // helper class for simple ray-traces from character class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { public: @@ -220,7 +223,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { // Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform. // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). - // These two computations must be kept in sync. + const float MINIMUM_TIME_REMAINING = 0.005f; const float MAX_DISPLACEMENT = 0.5f * _radius; _followTimeRemaining -= dt; @@ -258,18 +261,21 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { void CharacterController::jump() { // check for case where user is holding down "jump" key... // we'll eventually transition to "hover" - if (_state == State::Hover) { - quint64 now = usecTimestampNow(); - const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); - if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { - _isPushingUp = true; - setState(State::Hover); - } - } else { - if (_state != State::Takeoff) { - _jumpToHoverStart = usecTimestampNow(); + if (_state != State::Takeoff) { + if (_state == State::InAir) { + quint64 now = usecTimestampNow(); + if (!_isPushingUp) { + _isPushingUp = true; + _jumpToHoverStart = now; + } + const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; + if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { + setState(State::Hover); + } + } else { _pendingFlags |= PENDING_FLAG_JUMP; } + } } @@ -278,19 +284,41 @@ bool CharacterController::onGround() const { return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport; } -void CharacterController::setState(State desiredState) { - if (desiredState == State::Hover && _state != State::Hover) { - // hover enter - if (_rigidBody) { - _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - } - } else if (_state == State::Hover && desiredState != State::Hover) { - // hover exit - if (_rigidBody) { - _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); - } +#ifdef DEBUG_STATE_CHANGE +static const char* stateToStr(CharacterController::State state) { + switch (state) { + case CharacterController::State::Ground: + return "Ground"; + case CharacterController::State::Takeoff: + return "Takeoff"; + case CharacterController::State::InAir: + return "InAir"; + case CharacterController::State::Hover: + return "Hover"; + default: + return "Unknown"; + } +} +#endif // #ifdef DEBUG_STATE_CHANGE + +void CharacterController::setState(State desiredState) { + if (desiredState != _state) { +#ifdef DEBUG_STATE_CHANGE + qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "<-" << stateToStr(_state); +#endif + if (desiredState == State::Hover && _state != State::Hover) { + // hover enter + if (_rigidBody) { + _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + } + } else if (_state == State::Hover && desiredState != State::Hover) { + // hover exit + if (_rigidBody) { + _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); + } + } + _state = desiredState; } - _state = desiredState; } void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { @@ -411,6 +439,7 @@ void CharacterController::preSimulation() { if (_enabled && _dynamicsWorld) { // slam body to where it is supposed to be _rigidBody->setWorldTransform(_characterBodyTransform); + btVector3 velocity = _rigidBody->getLinearVelocity(); // scan for distant floor // rayStart is at center of bottom sphere @@ -431,7 +460,7 @@ void CharacterController::preSimulation() { } // TODO: use collision events rather than ray-trace test to disable jumping const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_state != State::Takeoff && (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport)) { + if (_state != State::Takeoff && (velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { setState(State::Ground); } } else if (!_hasSupport) { @@ -454,7 +483,6 @@ void CharacterController::preSimulation() { setState(State::InAir); _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; - btVector3 velocity = _rigidBody->getLinearVelocity(); velocity += _jumpSpeed * _currentUp; _rigidBody->setLinearVelocity(velocity); } From 8b5cf3e49abbd8f4d6f32edb1f1f06cbd8989b4b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 1 Feb 2016 20:43:41 -0800 Subject: [PATCH 5/9] CharacterController: refined state machine. --- libraries/physics/src/CharacterController.cpp | 201 +++++++++--------- libraries/physics/src/CharacterController.h | 6 +- 2 files changed, 109 insertions(+), 98 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index ad6c9545d2..f241be8b35 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -56,7 +56,8 @@ CharacterController::CharacterController() { _jumpSpeed = JUMP_SPEED; _state = State::Hover; _isPushingUp = false; - _jumpToHoverStart = 0; + _jumpButtonDownStart = 0; + _jumpButtonDownCount = 0; _takeoffToInAirStart = 0; _followTime = 0.0f; _followLinearDisplacement = btVector3(0, 0, 0); @@ -158,68 +159,57 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) { } void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { - btVector3 actualVelocity = _rigidBody->getLinearVelocity(); - btScalar actualSpeed = actualVelocity.length(); - - btVector3 desiredVelocity = _walkVelocity; - btScalar desiredSpeed = desiredVelocity.length(); - - const btScalar MIN_UP_PUSH = 0.1f; - if (desiredVelocity.dot(_currentUp) < MIN_UP_PUSH) { - _isPushingUp = false; - } const btScalar MIN_SPEED = 0.001f; - if (_state == State::Hover) { - if (desiredSpeed < MIN_SPEED) { - if (actualSpeed < MIN_SPEED) { - _rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); - } else { - const btScalar HOVER_BRAKING_TIMESCALE = 0.1f; - btScalar tau = glm::max(dt / HOVER_BRAKING_TIMESCALE, 1.0f); - _rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity); - } - } else { - const btScalar HOVER_ACCELERATION_TIMESCALE = 0.1f; - btScalar tau = dt / HOVER_ACCELERATION_TIMESCALE; - _rigidBody->setLinearVelocity(actualVelocity - tau * (actualVelocity - desiredVelocity)); + + btVector3 actualVelocity = _rigidBody->getLinearVelocity(); + if (actualVelocity.length() < MIN_SPEED) { + actualVelocity = btVector3(0.0f, 0.0f, 0.0f); + } + + btVector3 desiredVelocity = _walkVelocity; + if (desiredVelocity.length() < MIN_SPEED) { + desiredVelocity = btVector3(0.0f, 0.0f, 0.0f); + } + + // decompose into horizontal and vertical components. + btVector3 actualVertVelocity = actualVelocity.dot(_currentUp) * _currentUp; + btVector3 actualHorizVelocity = actualVelocity - actualVertVelocity; + btVector3 desiredVertVelocity = desiredVelocity.dot(_currentUp) * _currentUp; + btVector3 desiredHorizVelocity = desiredVelocity - desiredVertVelocity; + + btVector3 finalVelocity; + + switch (_state) { + case State::Ground: + case State::Takeoff: + { + // horizontal ground control + const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f; + btScalar tau = dt / WALK_ACCELERATION_TIMESCALE; + finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity; } - } else { - if (onGround()) { - // walking on ground - if (desiredSpeed < MIN_SPEED) { - if (actualSpeed < MIN_SPEED) { - _rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); - } else { - const btScalar HOVER_BRAKING_TIMESCALE = 0.1f; - btScalar tau = dt / HOVER_BRAKING_TIMESCALE; - _rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity); - } - } else { - // TODO: modify desiredVelocity using floor normal - const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f; - btScalar tau = dt / WALK_ACCELERATION_TIMESCALE; - btVector3 velocityCorrection = tau * (desiredVelocity - actualVelocity); - // subtract vertical component - velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp; - _rigidBody->setLinearVelocity(actualVelocity + velocityCorrection); - } - } else { - // transitioning to flying - btVector3 velocityCorrection = desiredVelocity - actualVelocity; + break; + case State::InAir: + { + // horizontal air control + const btScalar IN_AIR_ACCELERATION_TIMESCALE = 2.0f; + btScalar tau = dt / IN_AIR_ACCELERATION_TIMESCALE; + finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity; + } + break; + case State::Hover: + { + // vertical and horizontal air control const btScalar FLY_ACCELERATION_TIMESCALE = 0.2f; btScalar tau = dt / FLY_ACCELERATION_TIMESCALE; - if (!_isPushingUp) { - // actually falling --> compute a different velocity attenuation factor - const btScalar FALL_ACCELERATION_TIMESCALE = 2.0f; - tau = dt / FALL_ACCELERATION_TIMESCALE; - // zero vertical component - velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp; - } - _rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection); + finalVelocity = tau * desiredVelocity + (1.0f - tau) * actualVelocity; } + break; } + _rigidBody->setLinearVelocity(finalVelocity); + // Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform. // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). @@ -259,24 +249,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { } void CharacterController::jump() { - // check for case where user is holding down "jump" key... - // we'll eventually transition to "hover" - if (_state != State::Takeoff) { - if (_state == State::InAir) { - quint64 now = usecTimestampNow(); - if (!_isPushingUp) { - _isPushingUp = true; - _jumpToHoverStart = now; - } - const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; - if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { - setState(State::Hover); - } - } else { - _pendingFlags |= PENDING_FLAG_JUMP; - } - - } + _pendingFlags |= PENDING_FLAG_JUMP; } bool CharacterController::onGround() const { @@ -441,6 +414,9 @@ void CharacterController::preSimulation() { _rigidBody->setWorldTransform(_characterBodyTransform); btVector3 velocity = _rigidBody->getLinearVelocity(); + btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp; + btVector3 actualHorizVelocity = velocity - actualVertVelocity; + // scan for distant floor // rayStart is at center of bottom sphere btVector3 rayStart = _characterBodyTransform.getOrigin() - _halfHeight * _currentUp; @@ -454,41 +430,74 @@ void CharacterController::preSimulation() { _dynamicsWorld->rayTest(rayStart, rayEnd, rayCallback); if (rayCallback.hasHit()) { _floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius; - const btScalar MIN_HOVER_HEIGHT = 3.0f; - if (_state == State::Hover && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) { - setState(State::InAir); - } - // TODO: use collision events rather than ray-trace test to disable jumping - const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_state != State::Takeoff && (velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { - setState(State::Ground); - } - } else if (!_hasSupport) { + } else { _floorDistance = FLT_MAX; - setState(State::Hover); } + const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; + const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; + const btScalar MIN_HOVER_HEIGHT = 2.5f; + const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; + const btScalar UPWARD_VELOCITY_THRESHOLD = 0.05f; + const btScalar MAX_FLYING_SPEED = 30.0f; + quint64 now = usecTimestampNow(); - if (_pendingFlags & PENDING_FLAG_JUMP) { - _pendingFlags &= ~ PENDING_FLAG_JUMP; - if (onGround()) { - setState(State::Takeoff); - _takeoffToInAirStart = now; + // record a time stamp when the jump button was first pressed. + if ((_previousFlags & PENDING_FLAG_JUMP) != (_pendingFlags & PENDING_FLAG_JUMP)) { + if (_pendingFlags & PENDING_FLAG_JUMP) { + _jumpButtonDownStart = now; + _jumpButtonDownCount++; } } - const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; - if (_state == State::Takeoff && (now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { - setState(State::InAir); + bool jumpButtonHeld = _pendingFlags & PENDING_FLAG_JUMP; + bool wantsToGoUp = !jumpButtonHeld && _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD; + bool tooFast = actualHorizVelocity.length() > (MAX_FLYING_SPEED / 2.0f); - _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; - velocity += _jumpSpeed * _currentUp; - _rigidBody->setLinearVelocity(velocity); + switch (_state) { + case State::Ground: + if (!rayCallback.hasHit() && !_hasSupport) { + setState(State::Hover); + } else if (_pendingFlags & PENDING_FLAG_JUMP) { + _takeOffJumpButtonID = _jumpButtonDownCount; + setState(State::Takeoff); + } + break; + case State::Takeoff: + if (!rayCallback.hasHit() && !_hasSupport) { + setState(State::Hover); + } else if ((now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { + setState(State::InAir); + _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; + velocity += _jumpSpeed * _currentUp; + _rigidBody->setLinearVelocity(velocity); + } + break; + case State::InAir: { + if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { + setState(State::Ground); + } else if ((jumpButtonHeld && ((_takeOffJumpButtonID != _jumpButtonDownCount) || (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD)) || wantsToGoUp) { + setState(State::Hover); + } + break; + } + case State::Hover: + if (!jumpButtonHeld && !wantsToGoUp && _floorDistance < MIN_HOVER_HEIGHT && !tooFast) { + setState(State::InAir); + } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !tooFast) { + setState(State::Ground); + } + break; } } - _followTime = 0.0f; + /// _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD + + _previousFlags = _pendingFlags; + _pendingFlags &= ~PENDING_FLAG_JUMP; + + _followTime = 0.0f; _followLinearDisplacement = btVector3(0, 0, 0); _followAngularDisplacement = btQuaternion::getIdentity(); } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 5470104a1a..97bda5c5d5 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -109,7 +109,9 @@ protected: glm::vec3 _boxScale; // used to compute capsule shape quint64 _takeoffToInAirStart; - quint64 _jumpToHoverStart; + quint64 _jumpButtonDownStart; + quint32 _jumpButtonDownCount; + quint32 _takeOffJumpButtonID; btScalar _halfHeight; btScalar _radius; @@ -131,7 +133,7 @@ protected: btDynamicsWorld* _dynamicsWorld { nullptr }; btRigidBody* _rigidBody { nullptr }; uint32_t _pendingFlags { 0 }; - + uint32_t _previousFlags { 0 }; }; #endif // hifi_CharacterControllerInterface_h From c4e1509aa214948bbe2428714d71c9f5133f5186 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 2 Feb 2016 11:19:17 -0800 Subject: [PATCH 6/9] CharacterController: better debug support of internal state machine Head is no longer visible when flying fast, in first-person HMD mode. --- interface/src/avatar/MyAvatar.cpp | 12 +++-- libraries/physics/src/CharacterController.cpp | 46 +++++++++++-------- libraries/physics/src/CharacterController.h | 6 +++ 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0aadaed150..4253091533 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1311,21 +1311,23 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { _prevShouldDrawHead = shouldDrawHead; } -const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; +const float RENDER_HEAD_CUTOFF_DISTANCE = 0.5f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); + return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { - return ((renderArgs->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) || - (qApp->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || - !cameraInsideHead()); + bool defaultMode = renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE; + bool firstPerson = qApp->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON; + bool insideHead = cameraInsideHead(); + return !defaultMode || !firstPerson || !insideHead; } void MyAvatar::updateOrientation(float deltaTime) { + // Smoothly rotate body with arrow keys float targetSpeed = _driveKeys[YAW] * _yawSpeed; if (targetSpeed != 0.0f) { diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f241be8b35..160b227127 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -21,7 +21,11 @@ const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; -#define DEBUG_STATE_CHANGE +#ifdef DEBUG_STATE_CHANGE +#define SET_STATE(desiredState, reason) setState(desiredState, reason) +#else +#define SET_STATE(desiredState, reason) setState(desiredState) +#endif // helper class for simple ray-traces from character class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { @@ -65,7 +69,6 @@ CharacterController::CharacterController() { _hasSupport = false; _pendingFlags = PENDING_FLAG_UPDATE_SHAPE; - } bool CharacterController::needsRemoval() const { @@ -274,10 +277,14 @@ static const char* stateToStr(CharacterController::State state) { } #endif // #ifdef DEBUG_STATE_CHANGE +#ifdef DEBUG_STATE_CHANGE +void CharacterController::setState(State desiredState, const char* reason) { +#else void CharacterController::setState(State desiredState) { +#endif if (desiredState != _state) { #ifdef DEBUG_STATE_CHANGE - qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "<-" << stateToStr(_state); + qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason; #endif if (desiredState == State::Hover && _state != State::Hover) { // hover enter @@ -339,7 +346,7 @@ void CharacterController::setEnabled(bool enabled) { } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; } - setState(State::Hover); + SET_STATE(State::Hover, "setEnabled"); _enabled = enabled; } } @@ -438,8 +445,8 @@ void CharacterController::preSimulation() { const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; - const btScalar UPWARD_VELOCITY_THRESHOLD = 0.05f; - const btScalar MAX_FLYING_SPEED = 30.0f; + const btScalar UPWARD_VELOCITY_THRESHOLD = 0.1f; + const btScalar MAX_WALKING_SPEED = 2.5f; quint64 now = usecTimestampNow(); @@ -452,23 +459,22 @@ void CharacterController::preSimulation() { } bool jumpButtonHeld = _pendingFlags & PENDING_FLAG_JUMP; - bool wantsToGoUp = !jumpButtonHeld && _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD; - bool tooFast = actualHorizVelocity.length() > (MAX_FLYING_SPEED / 2.0f); + bool flyingFast = _state == State::Hover && actualHorizVelocity.length() > (MAX_WALKING_SPEED * 0.75f); switch (_state) { case State::Ground: if (!rayCallback.hasHit() && !_hasSupport) { - setState(State::Hover); + SET_STATE(State::Hover, "no ground"); } else if (_pendingFlags & PENDING_FLAG_JUMP) { _takeOffJumpButtonID = _jumpButtonDownCount; - setState(State::Takeoff); + SET_STATE(State::Takeoff, "jump pressed"); } break; case State::Takeoff: if (!rayCallback.hasHit() && !_hasSupport) { - setState(State::Hover); + SET_STATE(State::Hover, "no ground"); } else if ((now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { - setState(State::InAir); + SET_STATE(State::InAir, "takeoff done"); _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; velocity += _jumpSpeed * _currentUp; _rigidBody->setLinearVelocity(velocity); @@ -476,17 +482,19 @@ void CharacterController::preSimulation() { break; case State::InAir: { if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { - setState(State::Ground); - } else if ((jumpButtonHeld && ((_takeOffJumpButtonID != _jumpButtonDownCount) || (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD)) || wantsToGoUp) { - setState(State::Hover); + SET_STATE(State::Ground, "hit ground"); + } else if (jumpButtonHeld && (_takeOffJumpButtonID != _jumpButtonDownCount)) { + SET_STATE(State::Hover, "double jump button"); + } else if (jumpButtonHeld && (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD) { + SET_STATE(State::Hover, "jump button held"); } break; } case State::Hover: - if (!jumpButtonHeld && !wantsToGoUp && _floorDistance < MIN_HOVER_HEIGHT && !tooFast) { - setState(State::InAir); - } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !tooFast) { - setState(State::Ground); + if ((_floorDistance < MIN_HOVER_HEIGHT) && !jumpButtonHeld && !flyingFast) { + SET_STATE(State::InAir, "near ground"); + } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !flyingFast) { + SET_STATE(State::Ground, "touching ground"); } break; } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 97bda5c5d5..bb4a135ca3 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -31,6 +31,8 @@ class btRigidBody; class btCollisionWorld; class btDynamicsWorld; +//#define DEBUG_STATE_CHANGE + class CharacterController : public btCharacterControllerInterface { public: CharacterController(); @@ -92,7 +94,11 @@ public: bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); protected: +#ifdef DEBUG_STATE_CHANGE + void setState(State state, const char* reason); +#else void setState(State state); +#endif void updateUpAxis(const glm::quat& rotation); bool checkForSupport(btCollisionWorld* collisionWorld) const; From 656608e2ffaff0f21effbe461b8f36437addd6d1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 2 Feb 2016 12:08:52 -0800 Subject: [PATCH 7/9] Fixes for away.js --- .../meshes/defaultAvatar_full/avatar-animation.json | 1 + libraries/animation/src/Rig.cpp | 11 +++++++---- libraries/animation/src/Rig.h | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 37da0c37cc..a4e39969b4 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -377,6 +377,7 @@ "interpTarget": 30, "interpDuration": 30, "transitions": [ + { "var": "isNotAway", "state": "awayOutro" }, { "var": "awayIntroOnDone", "state": "away"} ] }, diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 64935691c8..2ea9d782d5 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -784,11 +784,14 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos t += deltaTime; - if (_enableInverseKinematics) { - _animVars.set("ikOverlayAlpha", 1.0f); - } else { - _animVars.set("ikOverlayAlpha", 0.0f); + if (_enableInverseKinematics != _lastEnableInverseKinematics) { + if (_enableInverseKinematics) { + _animVars.set("ikOverlayAlpha", 1.0f); + } else { + _animVars.set("ikOverlayAlpha", 0.0f); + } } + _lastEnableInverseKinematics = _enableInverseKinematics; } _lastFront = front; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index e12af16e41..a360140b16 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -301,6 +301,7 @@ public: std::map _origRoleAnimations; std::vector _prefetchedAnimations; + bool _lastEnableInverseKinematics { false }; bool _enableInverseKinematics { true }; private: From 6cc3b2b47f82022ea00925887fa6ffbb9029e200 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 2 Feb 2016 15:04:28 -0800 Subject: [PATCH 8/9] Fixed unused variable warnings on OSX and Linux --- interface/src/avatar/MyAvatar.cpp | 1 - libraries/physics/src/CharacterController.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4253091533..b99430cae3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1314,7 +1314,6 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { const float RENDER_HEAD_CUTOFF_DISTANCE = 0.5f; bool MyAvatar::cameraInsideHead() const { - const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 160b227127..941428f03a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -445,7 +445,6 @@ void CharacterController::preSimulation() { const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; - const btScalar UPWARD_VELOCITY_THRESHOLD = 0.1f; const btScalar MAX_WALKING_SPEED = 2.5f; quint64 now = usecTimestampNow(); From fff603e4e2f5a48567f7fb390cebdcb0c07a019d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 3 Feb 2016 10:21:27 -0800 Subject: [PATCH 9/9] Removed comment --- libraries/physics/src/CharacterController.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 941428f03a..d16c406658 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -499,8 +499,6 @@ void CharacterController::preSimulation() { } } - /// _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD - _previousFlags = _pendingFlags; _pendingFlags &= ~PENDING_FLAG_JUMP;