Fix for incorrect hand offset when backing into collision.

We know properly account for the offset of the head due to clamping from a small maxHipsOffset.
This means the hands should look more natural when you are out-of-body and are moving your hand controllers.
This commit is contained in:
Anthony J. Thibault 2016-09-23 11:44:36 -07:00
parent 0f60abdf4e
commit b68dbab994
6 changed files with 32 additions and 10 deletions

View file

@ -1378,7 +1378,7 @@ void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) {
hipsPosition.z *= -1.0f;
maxHipsOffsetRadius = _characterController.measureMaxHipsOffsetRadius(hipsPosition, maxHipsOffsetRadius);
}
_rig->setMaxHipsOffsetLength(maxHipsOffsetRadius);
_rig->updateMaxHipsOffsetLength(maxHipsOffsetRadius, deltaTime);
glm::vec3 position = getPosition();
glm::quat orientation = getOrientation();

View file

@ -149,6 +149,17 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->updateFromHeadParameters(headParams, deltaTime);
// OUTOFBODY_HACK: clamp horizontal component of head by maxHipsOffset.
// This is to prevent the hands from being incorrect relative to the head because
// the hips are being constrained by a small maxHipsOffset due to collision.
if (myAvatar->isOutOfBody()) {
float headOffsetLength2D = glm::length(glm::vec2(truncatedHMDPositionInRigSpace.x, truncatedHMDPositionInRigSpace.z));
if (headOffsetLength2D > _rig->getMaxHipsOffsetLength()) {
truncatedHMDPositionInRigSpace.x *= _rig->getMaxHipsOffsetLength() / headOffsetLength2D;
truncatedHMDPositionInRigSpace.z *= _rig->getMaxHipsOffsetLength() / headOffsetLength2D;
}
}
Rig::HandParameters handParams;
auto leftPose = myAvatar->getLeftHandControllerPoseInAvatarFrame();

View file

@ -392,10 +392,6 @@ 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 {
@ -585,7 +581,7 @@ void AnimInverseKinematics::clearIKJointLimitHistory() {
void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) {
// OUTOFBODY_HACK: manually adjust scale here
const float METERS_TO_CENTIMETERS = 100.0f;
_desiredMaxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength;
_maxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength;
}
RotationConstraint* AnimInverseKinematics::getConstraint(int index) {

View file

@ -85,7 +85,6 @@ 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 };

View file

@ -307,18 +307,30 @@ void Rig::clearIKJointLimitHistory() {
}
}
void Rig::setMaxHipsOffsetLength(float maxLength) {
void Rig::updateMaxHipsOffsetLength(float maxLength, float deltaTime) {
_desiredMaxHipsOffsetLength = maxLength;
// OUTOFBODY_HACK: smoothly update update _hipsOffsetLength, otherwise we risk introducing oscillation in the hips offset.
const float MAX_HIPS_OFFSET_TIMESCALE = 0.33f;
float tau = deltaTime / MAX_HIPS_OFFSET_TIMESCALE;
_maxHipsOffsetLength = (1.0f - tau) * _maxHipsOffsetLength + tau * _desiredMaxHipsOffsetLength;
if (_animNode) {
_animNode->traverse([&](AnimNode::Pointer node) {
auto ikNode = std::dynamic_pointer_cast<AnimInverseKinematics>(node);
if (ikNode) {
ikNode->setMaxHipsOffsetLength(maxLength);
ikNode->setMaxHipsOffsetLength(_maxHipsOffsetLength);
}
return true;
});
}
}
float Rig::getMaxHipsOffsetLength() const {
return _maxHipsOffsetLength;
}
void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
if (isIndexValid(index)) {
if (valid) {

View file

@ -104,7 +104,8 @@ public:
void clearJointAnimationPriority(int index);
void clearIKJointLimitHistory();
void setMaxHipsOffsetLength(float maxLength);
void updateMaxHipsOffsetLength(float maxLength, float deltaTime);
float getMaxHipsOffsetLength() const;
// geometry space
void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
@ -319,6 +320,9 @@ protected:
bool _truncateIKTargets { false };
bool _enableDebugDrawIKTargets { false };
float _maxHipsOffsetLength { 1.0f };
float _desiredMaxHipsOffsetLength { 1.0f };
private:
QMap<int, StateHandler> _stateHandlers;
int _nextStateHandlerId { 0 };