From 1f7dc25f12967a6a4a6d42caba89dfe55229a8fd Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 21 Sep 2016 11:48:54 -0700 Subject: [PATCH 1/2] MyAvatar.addThrust() works again. --- interface/src/avatar/MyAvatar.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 99e84d5348..dc0262e9f0 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1336,8 +1336,7 @@ void MyAvatar::updateMotors() { // legacy support for 'MyAvatar::applyThrust()', which has always been implemented as a // short-lived linearAcceleration - _characterController.setLinearAcceleration(_thrust); - _thrust = Vectors::ZERO; + _characterController.setLinearAcceleration(glm::vec3(0.0f, _thrust.y, 0.0f)); } void MyAvatar::prepareForPhysicsSimulation() { @@ -1867,9 +1866,15 @@ void MyAvatar::updatePosition(float deltaTime) { worldVelocity = motorRotation * _scriptedMotorVelocity; applyVelocityToSensorToWorldMatrix(worldVelocity, deltaTime); } + + // OUTOFBODY_HACK: apply scaling factor to _thrust, to get the same behavior as an periodically applied motor. + const float THRUST_DAMPING_FACTOR = 0.25f; + applyVelocityToSensorToWorldMatrix(THRUST_DAMPING_FACTOR * _thrust, deltaTime); } } + _thrust = Vectors::ZERO; + // capture the head rotation, in sensor space, when the user first indicates they would like to move/fly. if (!_hoverReferenceCameraFacingIsCaptured && (fabs(_driveKeys[TRANSLATE_Z]) > 0.1f || fabs(_driveKeys[TRANSLATE_X]) > 0.1f)) { _hoverReferenceCameraFacingIsCaptured = true; From 9fa8fc11c965469c209e6c81264b68fe9fe6845e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 21 Sep 2016 18:20:35 -0700 Subject: [PATCH 2/2] More stability in hips offset calculation. --- .../animation/src/AnimInverseKinematics.cpp | 32 +++++++++++-------- .../animation/src/AnimInverseKinematics.h | 1 + libraries/physics/src/CharacterController.cpp | 3 ++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index b58813a214..a16506a2ff 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -392,6 +392,10 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars dt = MAX_OVERLAY_DT; } + // OUTOFBODY_HACK: smoothly update update _hipsOffsetLength, otherwise we risk introducing oscillation in the hips offset. + float tau = dt / 0.5f; + _maxHipsOffsetLength = (1.0f - tau) * _maxHipsOffsetLength + tau * _desiredMaxHipsOffsetLength; + if (_relativePoses.size() != underPoses.size()) { loadPoses(underPoses); } else { @@ -516,7 +520,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars float OTHER_WEIGHT = 1.0f; float totalWeight = 0.0f; - glm::vec3 newHipsOffset = Vectors::ZERO; + glm::vec3 additionalHipsOffset = Vectors::ZERO; for (auto& target: targets) { int targetIndex = target.getIndex(); if (targetIndex == _headIndex && _headIndex != -1) { @@ -527,43 +531,45 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans; glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - newHipsOffset += (OTHER_WEIGHT * HEAD_OFFSET_SLAVE_FACTOR) * (actual - under); + additionalHipsOffset += (OTHER_WEIGHT * HEAD_OFFSET_SLAVE_FACTOR) * (actual - under); totalWeight += OTHER_WEIGHT; } else if (target.getType() == IKTarget::Type::HmdHead) { glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; glm::vec3 thisOffset = target.getTranslation() - actual; glm::vec3 futureHipsOffset = _hipsOffset + thisOffset; - if (glm::length(futureHipsOffset) < _maxHipsOffsetLength) { + if (glm::length(glm::vec2(futureHipsOffset.x, futureHipsOffset.z)) < _maxHipsOffsetLength) { // it is imperative to shift the hips and bring the head to its designated position // so we slam newHipsOffset here and ignore all other targets - newHipsOffset = futureHipsOffset; + additionalHipsOffset = futureHipsOffset - _hipsOffset; totalWeight = 0.0f; break; } else { - newHipsOffset += HMD_WEIGHT * (target.getTranslation() - actual); + additionalHipsOffset += HMD_WEIGHT * (target.getTranslation() - actual); totalWeight += HMD_WEIGHT; } } } else if (target.getType() == IKTarget::Type::RotationAndPosition) { glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans; glm::vec3 targetPosition = target.getTranslation(); - newHipsOffset += OTHER_WEIGHT * (targetPosition - actualPosition); + additionalHipsOffset += OTHER_WEIGHT * (targetPosition - actualPosition); totalWeight += OTHER_WEIGHT; } } if (totalWeight > 1.0f) { - newHipsOffset /= totalWeight; + additionalHipsOffset /= totalWeight; } // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f; float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; - float newOffsetLength = glm::length(newHipsOffset); - if (newOffsetLength > _maxHipsOffsetLength) { - // clamp the hips offset - newHipsOffset *= _maxHipsOffsetLength / newOffsetLength; + _hipsOffset += additionalHipsOffset * tau; + + // clamp the horizontal component of the hips offset + float hipsOffsetLength2D = glm::length(glm::vec2(_hipsOffset.x, _hipsOffset.z)); + if (hipsOffsetLength2D > _maxHipsOffsetLength) { + _hipsOffset.x *= _maxHipsOffsetLength / hipsOffsetLength2D; + _hipsOffset.z *= _maxHipsOffsetLength / hipsOffsetLength2D; } - _hipsOffset += (newHipsOffset - _hipsOffset) * tau; } } } @@ -579,7 +585,7 @@ void AnimInverseKinematics::clearIKJointLimitHistory() { void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) { // OUTOFBODY_HACK: manually adjust scale here const float METERS_TO_CENTIMETERS = 100.0f; - _maxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength; + _desiredMaxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength; } RotationConstraint* AnimInverseKinematics::getConstraint(int index) { diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index b61343a97b..4c8d29c7ed 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -85,6 +85,7 @@ protected: // experimental data for moving hips during IK glm::vec3 _hipsOffset { Vectors::ZERO }; + float _desiredMaxHipsOffsetLength { 1.0f }; float _maxHipsOffsetLength { 1.0f }; int _headIndex { -1 }; int _hipsIndex { -1 }; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index aa119689f7..514e8a4f8f 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -733,6 +733,9 @@ float CharacterController::measureMaxHipsOffsetRadius(const glm::vec3& currentHi startTransform.setOrigin(startPos); btVector3 endPos = startPos + rotation * ((maxSweepDistance / hipsOffsetLength) * hipsOffset); + // ensure sweep is horizontal. + startPos.setY(endPos.getY()); + // sweep test a sphere btSphereShape sphere(_radius); CharacterSweepResult result(&_ghost);