From 429a258df031ff8ba1d4a68db9965217ca9f6652 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 25 Mar 2015 14:38:27 -0700 Subject: [PATCH 01/12] enable hover when far above floor --- libraries/physics/src/CharacterController.cpp | 65 ++++++++++++++++--- libraries/physics/src/CharacterController.h | 2 + 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index e84df7d644..84dcf25212 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -40,6 +40,24 @@ static btVector3 getNormalizedVector(const btVector3& v) { return n; } +class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { +public: + btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : + btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { + m_me = me; + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { + if (rayResult.m_collisionObject == m_me) { + return 1.0; + } + return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); + } +protected: + btCollisionObject* m_me; +}; + + class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) @@ -215,6 +233,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _jumpSpeed = 7.0f; _wasOnGround = false; _wasJumping = false; + _isHovering = true; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; _pendingFlags = 0; @@ -325,6 +344,27 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl return penetration; } +void CharacterController::scanDown(btCollisionWorld* world) { + // we test with downward raycast and if we don't find floor close enough then turn on "hover" + btKinematicClosestNotMeRayResultCallback callback(_ghostObject); + callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; + callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; + + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + btVector3 start = _currentPosition; + const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight; // closest possible floor for disabling hover + const btScalar MIN_HOVER_HEIGHT = 2.0f + _halfHeight; // distance to floor for enabling hover + btVector3 end = start - MAX_SCAN_HEIGHT * up; + + world->rayTest(start, end, callback); + bool wasHovering = _isHovering; + if (!callback.hasHit()) { + _isHovering = true; + } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { + _isHovering = false; + } +} + void CharacterController::stepUp(btCollisionWorld* world) { // phase 1: up @@ -495,7 +535,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; _currentPosition = _targetPosition; - btVector3 oldPosition = _currentPosition; step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; @@ -510,7 +549,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - _currentPosition = oldPosition - _lastStepUp * up; + //_currentPosition = oldPosition; _lastStepUp = 0.0f; } } else { @@ -581,14 +620,19 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar return; // no motion } - _wasOnGround = onGround(); - // Update fall velocity. - _verticalVelocity -= _gravity * dt; - if (_verticalVelocity > _jumpSpeed) { - _verticalVelocity = _jumpSpeed; - } else if (_verticalVelocity < -_maxFallSpeed) { - _verticalVelocity = -_maxFallSpeed; + if (_isHovering) { + _wasOnGround = false; + const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f; + _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE); + } else { + _wasOnGround = onGround(); + _verticalVelocity -= _gravity * dt; + if (_verticalVelocity > _jumpSpeed) { + _verticalVelocity = _jumpSpeed; + } else if (_verticalVelocity < -_maxFallSpeed) { + _verticalVelocity = -_maxFallSpeed; + } } _verticalOffset = _verticalVelocity * dt; @@ -600,6 +644,8 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // (2) step the character forward // (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started + scanDown(collisionWorld); + stepUp(collisionWorld); // compute substep and decrement total interval @@ -711,6 +757,7 @@ void CharacterController::setEnabled(bool enabled) { // Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit. // Setting the ADD bit here works for all cases so we don't even bother checking other bits. _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; + _isHovering = true; } else { // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case // it was previously set by something else (e.g. an UPDATE_SHAPE event). diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 323529b1cd..f604e60c31 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -82,6 +82,7 @@ protected: bool _enabled; bool _wasOnGround; bool _wasJumping; + bool _isHovering; btScalar _velocityTimeInterval; uint32_t _pendingFlags; @@ -95,6 +96,7 @@ protected: btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal); bool recoverFromPenetration(btCollisionWorld* collisionWorld); + void scanDown(btCollisionWorld* collisionWorld); void stepUp(btCollisionWorld* collisionWorld); void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove); From 858dbeb674445c9f1530bec5f84dd5482ea932f7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 13:23:15 -0700 Subject: [PATCH 02/12] remove one line of cruft --- libraries/physics/src/CharacterController.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..fb2457083a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { From 0ef4022e9400abbdb3b06d49b01937259007c8b7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 15:14:46 -0700 Subject: [PATCH 03/12] tweak gravity and step heights of controller --- libraries/physics/src/CharacterController.cpp | 25 ++++++++----------- libraries/physics/src/CharacterController.h | 3 ++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..f243deffaa 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -228,9 +228,9 @@ CharacterController::CharacterController(AvatarData* avatarData) { _velocityTimeInterval = 0.0f; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _gravity = 9.8f; + _gravity = 5.0f; // slower than Earth's _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. - _jumpSpeed = 7.0f; + _jumpSpeed = 5.0f; _wasOnGround = false; _wasJumping = false; _isHovering = true; @@ -352,8 +352,8 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); btVector3 start = _currentPosition; - const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight; // closest possible floor for disabling hover - const btScalar MIN_HOVER_HEIGHT = 2.0f + _halfHeight; // distance to floor for enabling hover + const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight + _radius; // closest possible floor for disabling hover + const btScalar MIN_HOVER_HEIGHT = 3.0f + _halfHeight + _radius; // distance to floor for enabling hover btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); @@ -374,7 +374,7 @@ void CharacterController::stepUp(btCollisionWorld* world) { btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin)); - _targetPosition = _currentPosition + up * _stepHeight; + _targetPosition = _currentPosition + up * _stepUpHeight; end.setIdentity(); end.setOrigin(_targetPosition); @@ -392,15 +392,15 @@ void CharacterController::stepUp(btCollisionWorld* world) { // Only modify the position if the hit was a slope and not a wall or ceiling. if (callback.m_hitNormalWorld.dot(up) > 0.0f) { - _lastStepUp = _stepHeight * callback.m_closestHitFraction; + _lastStepUp = _stepUpHeight * callback.m_closestHitFraction; _currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction); } else { - _lastStepUp = _stepHeight; + _lastStepUp = _stepUpHeight; _currentPosition = _targetPosition; } } else { _currentPosition = _targetPosition; - _lastStepUp = _stepHeight; + _lastStepUp = _stepUpHeight; } } @@ -524,6 +524,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else if (!_wasJumping) { // sweep again for floor within downStep threshold + step = -_stepDownHeight * up; StepDownConvexResultCallback callback2 (_ghostObject, up, _currentPosition, step, @@ -535,7 +536,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; _currentPosition = _targetPosition; - step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; start.setOrigin(_currentPosition); @@ -549,7 +549,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - //_currentPosition = oldPosition; _lastStepUp = 0.0f; } } else { @@ -819,10 +818,8 @@ void CharacterController::updateShapeIfNecessary() { _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm - // (the function is approximately 2*_stepHeight) - _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + _stepUpHeight = _radius + 0.25f * _halfHeight + 0.1f; + _stepDownHeight = _radius; // create new shape _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index f604e60c31..b31c4855ea 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -59,7 +59,8 @@ protected: btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization) btScalar _gravity; - btScalar _stepHeight; // height of stepUp prior to stepForward + btScalar _stepUpHeight; // height of stepUp prior to stepForward + btScalar _stepDownHeight; // height of stepDown btScalar _addedMargin;//@todo: remove this and fix the code From 8a951e0dd3fc8bba4dc08c078c53743a31226dfb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 15:16:57 -0700 Subject: [PATCH 04/12] minor cleanup --- libraries/physics/src/CharacterController.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f243deffaa..34c2f51b03 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -43,18 +43,18 @@ static btVector3 getNormalizedVector(const btVector3& v) { class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : - btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { - m_me = me; + btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) { + _me = me; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { - if (rayResult.m_collisionObject == m_me) { - return 1.0; + if (rayResult.m_collisionObject == _me) { + return 1.0f; } return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); } protected: - btCollisionObject* m_me; + btCollisionObject* _me; }; @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { From 821ac605f5dc8cd93cf8460f456defe05b099041 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 19:48:52 -0700 Subject: [PATCH 05/12] smoother motion on steps faster motion when "flying" cleanup of MyAvatar::updatePosition() --- interface/src/avatar/MyAvatar.cpp | 136 +++--------------- interface/src/avatar/MyAvatar.h | 1 - libraries/physics/src/CharacterController.cpp | 55 ++++--- libraries/physics/src/CharacterController.h | 6 +- 4 files changed, 63 insertions(+), 135 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2f42544f28..aa36748f0c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -174,11 +174,7 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - if (isPhysicsEnabled()) { - updatePositionWithPhysics(deltaTime); - } else { - updatePosition(deltaTime); - } + updatePosition(deltaTime); } { @@ -1258,128 +1254,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe return localVelocity + motorEfficiency * deltaVelocity; } -const float NEARBY_FLOOR_THRESHOLD = 5.0f; - void MyAvatar::updatePosition(float deltaTime) { - - // check for floor by casting a ray straight down from avatar's position - float heightAboveFloor = FLT_MAX; - bool hasFloor = false; - const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); - const float maxFloorDistance = boundingShape.getBoundingRadius() * NEARBY_FLOOR_THRESHOLD; - - RayIntersectionInfo intersection; - // NOTE: avatar is center of PhysicsSimulation, so rayStart is the origin for the purposes of the raycast - intersection._rayStart = glm::vec3(0.0f); - intersection._rayDirection = - _worldUpDirection; - intersection._rayLength = 4.0f * boundingShape.getBoundingRadius(); - - // velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc - glm::vec3 velocity = _velocity; - - bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; - if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { - const float MAX_SPEED_UNDER_GRAVITY = 2.0f * _scale * MAX_WALKING_SPEED; - if (pushingUp || glm::length2(velocity) > MAX_SPEED_UNDER_GRAVITY * MAX_SPEED_UNDER_GRAVITY) { - // we're pushing up or moving quickly, so disable gravity - setLocalGravity(glm::vec3(0.0f)); - hasFloor = false; - } else { - if (heightAboveFloor > maxFloorDistance) { - // disable local gravity when floor is too far away - setLocalGravity(glm::vec3(0.0f)); - hasFloor = false; - } else { - // enable gravity - setLocalGravity(-_worldUpDirection); - } - } - } - - bool zeroDownwardVelocity = false; - bool gravityEnabled = (glm::length2(_gravity) > EPSILON); - if (gravityEnabled) { - const float SLOP = 0.002f; - if (heightAboveFloor < SLOP) { - if (heightAboveFloor < 0.0) { - // Gravity is in effect so we assume that the avatar is colliding against the world and we need - // to lift avatar out of floor, but we don't want to do it too fast (keep it smooth). - float distanceToLift = glm::min(-heightAboveFloor, MAX_WALKING_SPEED * deltaTime); - - // We don't use applyPositionDelta() for this lift distance because we don't want the avatar - // to come flying out of the floor. Instead we update position directly, and set a boolean - // that will remind us later to zero any downward component of the velocity. - _position += distanceToLift * _worldUpDirection; - } - zeroDownwardVelocity = true; - } - if (!zeroDownwardVelocity) { - velocity += (deltaTime * GRAVITY_EARTH) * _gravity; - } - } - - // rotate velocity into camera frame - glm::quat rotation = getHead()->getCameraOrientation(); - glm::vec3 localVelocity = glm::inverse(rotation) * velocity; - - // apply motors in camera frame - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); - newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - - // rotate back into world-frame - velocity = rotation * newLocalVelocity; - - // apply thrust - velocity += _thrust * deltaTime; - _thrust = glm::vec3(0.0f); - - // remove downward velocity so we don't push into floor - if (zeroDownwardVelocity) { - float verticalSpeed = glm::dot(velocity, _worldUpDirection); - if (verticalSpeed < 0.0f || !pushingUp) { - velocity -= verticalSpeed * _worldUpDirection; - } - } - - // cap avatar speed - float speed = glm::length(velocity); - if (speed > MAX_AVATAR_SPEED) { - velocity *= MAX_AVATAR_SPEED / speed; - speed = MAX_AVATAR_SPEED; - } - - // update position - if (speed > MIN_AVATAR_SPEED) { - applyPositionDelta(deltaTime * velocity); - } - - // update _moving flag based on speed - const float MOVING_SPEED_THRESHOLD = 0.01f; - _moving = speed > MOVING_SPEED_THRESHOLD; - - measureMotionDerivatives(deltaTime); -} - -void MyAvatar::updatePositionWithPhysics(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; - bool hasFloor = false; - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); + bool isOnGround = _characterController.onGround(); + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - // cap avatar speed - float speed = glm::length(newLocalVelocity); - if (speed > MAX_WALKING_SPEED) { - newLocalVelocity *= MAX_WALKING_SPEED / speed; - } - // rotate back into world-frame _velocity = rotation * newLocalVelocity; _velocity += _thrust * deltaTime; _thrust = glm::vec3(0.0f); + + // cap avatar speed + float speed = glm::length(_velocity); + if (speed > MAX_AVATAR_SPEED) { + _velocity *= MAX_AVATAR_SPEED / speed; + speed = MAX_AVATAR_SPEED; + } + + if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) { + // update position ourselves + applyPositionDelta(deltaTime * _velocity); + measureMotionDerivatives(deltaTime); + } // else physics will move avatar later + + // update _moving flag based on speed + const float MOVING_SPEED_THRESHOLD = 0.01f; + _moving = speed > MOVING_SPEED_THRESHOLD; + } void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a37d1c6a30..320a3179bc 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -234,7 +234,6 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); - void updatePositionWithPhysics(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 34c2f51b03..aa0d109732 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -231,8 +231,8 @@ CharacterController::CharacterController(AvatarData* avatarData) { _gravity = 5.0f; // slower than Earth's _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. _jumpSpeed = 5.0f; - _wasOnGround = false; - _wasJumping = false; + _isOnGround = false; + _isJumping = false; _isHovering = true; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; @@ -450,12 +450,12 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt btScalar margin = _convexShape->getMargin(); _convexShape->setMargin(margin + _addedMargin); - const btScalar MIN_STEP_DISTANCE = 0.0001f; + const btScalar MIN_STEP_DISTANCE_SQUARED = 1.0e-6f; btVector3 step = _targetPosition - _currentPosition; btScalar stepLength2 = step.length2(); int maxIter = 10; - while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) { + while (stepLength2 > MIN_STEP_DISTANCE_SQUARED && maxIter-- > 0) { start.setOrigin(_currentPosition); end.setOrigin(_targetPosition); @@ -516,12 +516,14 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt end.setOrigin(_targetPosition); _ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + _isOnGround = false; if (callback.hasHit()) { _currentPosition += callback.m_closestHitFraction * step; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _wasJumping = false; - } else if (!_wasJumping) { + _isJumping = false; + _isOnGround = true; + } else if (!_isJumping) { // sweep again for floor within downStep threshold step = -_stepDownHeight * up; StepDownConvexResultCallback callback2 (_ghostObject, @@ -545,9 +547,10 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _currentPosition += callback2.m_closestHitFraction * step; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _wasJumping = false; + _isJumping = false; + _isOnGround = true; } else { - // nothing to step down on, so remove the stepUp effect + // nothing to step down on _lastStepUp = 0.0f; } } else { @@ -571,8 +574,8 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, void CharacterController::reset(btCollisionWorld* collisionWorld) { _verticalVelocity = 0.0; _verticalOffset = 0.0; - _wasOnGround = false; - _wasJumping = false; + _isOnGround = false; + _isJumping = false; _walkDirection.setValue(0,0,0); _velocityTimeInterval = 0.0; @@ -620,11 +623,9 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // Update fall velocity. if (_isHovering) { - _wasOnGround = false; const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f; _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE); } else { - _wasOnGround = onGround(); _verticalVelocity -= _gravity * dt; if (_verticalVelocity > _jumpSpeed) { _verticalVelocity = _jumpSpeed; @@ -649,6 +650,7 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // compute substep and decrement total interval btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval; _velocityTimeInterval -= dt; + _stepDt += dt; // stepForward substep btVector3 move = _walkDirection * dtMoving; @@ -673,7 +675,7 @@ void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) { } bool CharacterController::canJump() const { - return onGround(); + return _isOnGround; } void CharacterController::jump() { @@ -698,7 +700,7 @@ btScalar CharacterController::getMaxSlope() const { } bool CharacterController::onGround() const { - return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f; + return _isOnGround; } void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { @@ -761,6 +763,7 @@ void CharacterController::setEnabled(bool enabled) { // it was previously set by something else (e.g. an UPDATE_SHAPE event). _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + _isOnGround = false; } _enabled = enabled; } @@ -842,9 +845,12 @@ void CharacterController::preSimulation(btScalar timeStep) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (canJump()) { _verticalVelocity = _jumpSpeed; - _wasJumping = true; + _isJumping = true; } } + // remember last position so we can throttle the total motion from the next step + _lastPosition = position; + _stepDt = 0.0f; } } @@ -852,9 +858,24 @@ void CharacterController::postSimulation() { if (_enabled) { const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); - glm::vec3 offset = rotation * _shapeLocalOffset; + glm::vec3 position = bulletToGLM(avatarTransform.getOrigin()); + + // cap the velocity of the step so that the character doesn't POP! so hard on steps + glm::vec3 finalStep = position - _lastPosition; + btVector3 finalVelocity = _walkDirection; + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + finalVelocity += _verticalVelocity * up; + const btScalar MAX_RESOLUTION_SPEED = 5.0f; // m/sec + btScalar maxStepLength = glm::max(MAX_RESOLUTION_SPEED, 2.0f * finalVelocity.length()) * _stepDt; + btScalar stepLength = glm::length(finalStep); + if (stepLength > maxStepLength) { + position = _lastPosition + (maxStepLength / stepLength) * finalStep; + // NOTE: we don't need to move ghostObject to throttled position unless + // we want to support do async ray-traces/collision-queries against character + } + _avatarData->setOrientation(rotation); - _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + _avatarData->setPosition(position - rotation * _shapeLocalOffset); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index b31c4855ea..ec7d9426f4 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -72,6 +72,7 @@ protected: btVector3 _currentPosition; btQuaternion _currentRotation; btVector3 _targetPosition; + glm::vec3 _lastPosition; btScalar _lastStepUp; ///keep track of the contact manifolds @@ -81,10 +82,11 @@ protected: btVector3 _floorNormal; // points from object to character bool _enabled; - bool _wasOnGround; - bool _wasJumping; + bool _isOnGround; + bool _isJumping; bool _isHovering; btScalar _velocityTimeInterval; + btScalar _stepDt; uint32_t _pendingFlags; glm::vec3 _shapeLocalOffset; From b9b2c30bba5f78cad7fb3a38eb9a46a3e4108005 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Mar 2015 09:01:44 -0700 Subject: [PATCH 06/12] use QObject::deleteLater() not explicit delete --- libraries/networking/src/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 5858c0926d..46c6418c63 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -282,7 +282,7 @@ void AccountManager::processReply() { } else { passErrorToCallback(requestReply); } - delete requestReply; + requestReply->deleteLater(); } void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { From be5fdbf2175afc894166c1d12d1a559706519f94 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Mar 2015 13:36:20 -0700 Subject: [PATCH 07/12] enable avatar collisions by default also remove old gravity features --- interface/src/Application.cpp | 11 ---- interface/src/Menu.cpp | 4 +- interface/src/Menu.h | 3 +- interface/src/avatar/MyAvatar.cpp | 50 ++----------------- interface/src/avatar/MyAvatar.h | 11 +--- libraries/avatars/src/AvatarData.h | 12 +---- libraries/physics/src/CharacterController.cpp | 30 ++++++----- libraries/physics/src/CharacterController.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 4 -- 9 files changed, 27 insertions(+), 99 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8cd36b501f..99777d22bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -987,12 +987,6 @@ void Application::keyPressEvent(QKeyEvent* event) { resetSensors(); break; - case Qt::Key_G: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::ObeyEnvironmentalGravity); - } - break; - case Qt::Key_A: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); @@ -1165,10 +1159,6 @@ void Application::keyPressEvent(QKeyEvent* event) { break; } - case Qt::Key_Comma: { - _myAvatar->togglePhysicsEnabled(); - } - default: event->ignore(); break; @@ -2192,7 +2182,6 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); - _myAvatar->preSimulation(); _physicsEngine.stepSimulation(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2ec5c12ca0..5867dd29e2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -201,9 +201,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, - avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::StandOnNearbyFloors, 0, true, + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, avatar, SLOT(updateMotionBehavior())); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, avatar, SLOT(updateMotionBehavior())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b3d2d548df..a4e644f20f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -153,6 +153,7 @@ namespace MenuOption { const QString EchoServerAudio = "Echo Server Audio"; const QString EditEntitiesHelp = "Edit Entities Help..."; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString EnableCharacterController = "Enable avatar collisions"; const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; const QString EnableVRMode = "Enable VR Mode"; const QString Entities = "Entities"; @@ -185,7 +186,6 @@ namespace MenuOption { const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString NoFaceTracking = "None"; - const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity"; const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; @@ -236,7 +236,6 @@ namespace MenuOption { const QString SixenseEnabled = "Enable Hydra Support"; const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString SixenseLasers = "Enable Sixense UI Lasers"; - const QString StandOnNearbyFloors = "Stand on nearby floors"; const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; const QString Stars = "Stars"; const QString Stats = "Stats"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index aa36748f0c..26b777b35b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -81,7 +81,6 @@ MyAvatar::MyAvatar() : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), - _enablePhysics(false), _characterController(this), _lookAtTargetAvatar(), _shouldRender(true), @@ -101,6 +100,7 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); + _characterController.setEnabled(true); } MyAvatar::~MyAvatar() { @@ -147,10 +147,6 @@ void MyAvatar::update(float deltaTime) { head->setAudioLoudness(audio->getLastInputLoudness()); head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); - if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) { - setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition())); - } - simulate(deltaTime); if (_feetTouchFloor) { _skeletonModel.updateStandingFoot(); @@ -480,26 +476,6 @@ void MyAvatar::loadLastRecording() { _player->loadRecording(_recorder->getRecording()); } -void MyAvatar::setLocalGravity(glm::vec3 gravity) { - _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; - // Environmental and Local gravities are incompatible. Since Local is being set here - // the environmental setting must be removed. - _motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - setGravity(gravity); -} - -void MyAvatar::setGravity(const glm::vec3& gravity) { - _gravity = gravity; - - // use the gravity to determine the new world up direction, if possible - float gravityLength = glm::length(gravity); - if (gravityLength > EPSILON) { - _worldUpDirection = _gravity / -gravityLength; - } - // NOTE: the else case here it to leave _worldUpDirection unchanged - // so it continues to point opposite to the previous gravity setting. -} - AnimationHandlePointer MyAvatar::addAnimationHandle() { AnimationHandlePointer handle = _skeletonModel.createAnimationHandle(); _animationHandles.append(handle); @@ -1276,7 +1252,7 @@ void MyAvatar::updatePosition(float deltaTime) { speed = MAX_AVATAR_SPEED; } - if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) { + if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { // update position ourselves applyPositionDelta(deltaTime * _velocity); measureMotionDerivatives(deltaTime); @@ -1402,23 +1378,6 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, void MyAvatar::updateMotionBehavior() { Menu* menu = Menu::getInstance(); - if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) { - _motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - // Environmental and Local gravities are incompatible. Environmental setting trumps local. - _motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY; - } else { - _motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - } - if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) { - setGravity(glm::vec3(0.0f)); - } - if (menu->isOptionChecked(MenuOption::StandOnNearbyFloors)) { - _motionBehaviors |= AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - // standing on floors requires collision with voxels - // TODO: determine what to do with this now that voxels are gone - } else { - _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - } if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) { _motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED; } else { @@ -1429,6 +1388,7 @@ void MyAvatar::updateMotionBehavior() { } else { _motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; } + _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController)); _feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations); } @@ -1487,10 +1447,6 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { return palm->getPosition(); } -void MyAvatar::preSimulation() { - _characterController.setEnabled(_enablePhysics); -} - void MyAvatar::clearDriveKeys() { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { _driveKeys[i] = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 320a3179bc..99c0bdb5df 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -25,7 +25,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale) Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame) - Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setLocalGravity) + //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) public: MyAvatar(); @@ -44,13 +44,11 @@ public: // setters void setLeanScale(float scale) { _leanScale = scale; } - void setLocalGravity(glm::vec3 gravity); void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); } // getters float getLeanScale() const { return _leanScale; } - glm::vec3 getGravity() const { return _gravity; } Q_INVOKABLE glm::vec3 getDefaultEyePosition() const; bool getShouldRenderLocally() const { return _shouldRender; } float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } @@ -148,11 +146,6 @@ public: const RecorderPointer getRecorder() const { return _recorder; } const PlayerPointer getPlayer() const { return _player; } - - void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } - bool isPhysicsEnabled() { return _enablePhysics; } - void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } - void preSimulation(); public slots: void increaseSize(); @@ -209,7 +202,6 @@ private: int _scriptedMotorFrame; quint32 _motionBehaviors; - bool _enablePhysics; CharacterController _characterController; QWeakPointer _lookAtTargetAvatar; @@ -236,7 +228,6 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); - void setGravity(const glm::vec3& gravity); }; #endif // hifi_MyAvatar_h diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a2feb98798..2bbd2ee386 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -61,21 +61,13 @@ typedef unsigned long long quint64; const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0; const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1; -const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 2; -const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 3; -const quint32 AVATAR_MOTION_STAND_ON_NEARBY_FLOORS = 1U << 4; - const quint32 AVATAR_MOTION_DEFAULTS = AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED | - AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED | - AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; // these bits will be expanded as features are exposed const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = - AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED | - AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | - AVATAR_MOTION_OBEY_LOCAL_GRAVITY | - AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; // Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index aa0d109732..40b9076a6a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -217,9 +217,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { assert(avatarData); _avatarData = avatarData; - // cache the "PhysicsEnabled" state of _avatarData _enabled = false; - _ghostObject = NULL; _convexShape = NULL; @@ -730,10 +728,12 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do } else { - // we always need to: REMOVE when UPDATE_SHAPE, to avoid deleting shapes out from under the PhysicsEngine - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION - | PENDING_FLAG_UPDATE_SHAPE; - // but only need to ADD back when we happen to be enabled + if (_dynamicsWorld) { + // must REMOVE from world prior to shape update + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + } + _pendingFlags |= PENDING_FLAG_UPDATE_SHAPE; + // only need to ADD back when we happen to be enabled if (_enabled) { _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; } @@ -759,9 +759,9 @@ void CharacterController::setEnabled(bool enabled) { _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; _isHovering = true; } else { - // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case - // it was previously set by something else (e.g. an UPDATE_SHAPE event). - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + if (_dynamicsWorld) { + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; _isOnGround = false; } @@ -777,17 +777,23 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } _dynamicsWorld = world; if (_dynamicsWorld) { - _pendingFlags &= ~ (PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_JUMP); + _pendingFlags &= ~ PENDING_FLAG_JUMP; _dynamicsWorld->addCollisionObject(getGhostObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); _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_REMOVE_FROM_SIMULATION; + _pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION; } } else { - _pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION); + _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index ec7d9426f4..6751277c83 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -166,6 +166,7 @@ public: bool needsRemoval() const; bool needsAddition() const; void setEnabled(bool enabled); + bool isEnabled() const { return _enabled; } void setDynamicsWorld(btDynamicsWorld* world); void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 716af1d188..831db73a0a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -360,10 +360,6 @@ void ScriptEngine::init() { globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS))); - - globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); - globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); - } QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { From bee8c0e2377f5e3a9a06f538cb894084a2ccf189 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Mar 2015 13:56:03 -0700 Subject: [PATCH 08/12] "hover" if the "jump" key is held down long enough --- libraries/physics/src/CharacterController.cpp | 15 +++++++++++++++ libraries/physics/src/CharacterController.h | 1 + 2 files changed, 16 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 40b9076a6a..09c6b5599f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -232,6 +232,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _isOnGround = false; _isJumping = false; _isHovering = true; + _jumpToHoverStart = 0; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; _pendingFlags = 0; @@ -678,6 +679,20 @@ bool CharacterController::canJump() const { void CharacterController::jump() { _pendingFlags |= PENDING_FLAG_JUMP; + + // check for case where user is holding down "jump" key... + // we'll eventually tansition to "hover" + if (!_isHovering) { + if (!_isJumping) { + _jumpToHoverStart = usecTimestampNow(); + } else { + quint64 now = usecTimestampNow(); + const quint64 JUMP_TO_HOVER_PERIOD = USECS_PER_SECOND; + if (now - _jumpToHoverStart < JUMP_TO_HOVER_PERIOD) { + _isHovering = true; + } + } + } } void CharacterController::setGravity(btScalar gravity) { diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 6751277c83..eeaa5836dd 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -85,6 +85,7 @@ protected: bool _isOnGround; bool _isJumping; bool _isHovering; + quint64 _jumpToHoverStart; btScalar _velocityTimeInterval; btScalar _stepDt; uint32_t _pendingFlags; From 1ee797efa4f1258b4567b81a6b7ec8b90fed03ac Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 27 Mar 2015 13:59:52 -0700 Subject: [PATCH 09/12] Fix authorization of API calls in XMLHttpRequest --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 8755527860..f408e2001d 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -207,7 +207,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(33) == "https://metaverse.highfidelity.com/api/") { + if (url.toLower().left(39) == "https://metaverse.highfidelity.com/api/") { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) { From 0fd17b3303865a587b2f251ec20594e03eb59040 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Fri, 27 Mar 2015 14:40:16 -0700 Subject: [PATCH 10/12] editEntities.js --> edit.js --- interface/resources/html/interface-welcome.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/html/interface-welcome.html b/interface/resources/html/interface-welcome.html index ed905eb392..26ae6ff5c0 100644 --- a/interface/resources/html/interface-welcome.html +++ b/interface/resources/html/interface-welcome.html @@ -138,7 +138,7 @@

Import models

- Use the editEntitles.js script to
+ Use the edit.js script to
add FBX models in-world. You
can use grids and fine tune
placement-related parameters
From 1821683453f8bab2f83850aa71154ba062af0c1c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 27 Mar 2015 14:44:35 -0700 Subject: [PATCH 11/12] fix bug in default avatars --- libraries/avatars/src/AvatarData.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a2feb98798..20366e590f 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -365,8 +365,8 @@ protected: HeadData* _headData; HandData* _handData; - QUrl _faceModelURL = DEFAULT_HEAD_MODEL_URL; - QUrl _skeletonModelURL = DEFAULT_BODY_MODEL_URL; + QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit + QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit QVector _attachmentData; QString _displayName; From c45676041941ae3e2c6985f10f895a3df5155ff6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 27 Mar 2015 15:24:55 -0700 Subject: [PATCH 12/12] Extract API URL into a const --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index f408e2001d..3054472a3c 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -22,6 +22,8 @@ #include "XMLHttpRequestClass.h" #include "ScriptEngine.h" +const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/"; + Q_DECLARE_METATYPE(QByteArray*) XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : @@ -207,7 +209,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(39) == "https://metaverse.highfidelity.com/api/") { + if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) {