Merge pull request #14221 from hyperlogic/feature/disable-hands-if-too-far-or-at-rest

Disable user hand controllers if they are too far away or not moving.
This commit is contained in:
Anthony Thibault 2018-10-19 14:02:32 -07:00 committed by GitHub
commit 6cc7c861d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 26 deletions

View file

@ -122,7 +122,6 @@ MyAvatar::MyAvatar(QThread* thread) :
_goToOrientation(),
_prevShouldDrawHead(true),
_audioListenerMode(FROM_HEAD),
_hmdAtRestDetector(glm::vec3(0), glm::quat()),
_dominantHandSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "dominantHand", DOMINANT_RIGHT_HAND),
_headPitchSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "", 0.0f),
_scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale),
@ -702,6 +701,46 @@ void MyAvatar::simulate(float deltaTime) {
// before we perform rig animations and IK.
updateSensorToWorldMatrix();
// if we detect the hand controller is at rest, i.e. lying on the table, or the hand is too far away from the hmd
// disable the associated hand controller input.
{
// NOTE: all poses are in sensor space.
auto leftHandIter = _controllerPoseMap.find(controller::Action::LEFT_HAND);
if (leftHandIter != _controllerPoseMap.end() && leftHandIter->second.isValid()) {
_leftHandAtRestDetector.update(leftHandIter->second.getTranslation(), leftHandIter->second.getRotation());
if (_leftHandAtRestDetector.isAtRest()) {
leftHandIter->second.valid = false;
}
} else {
_leftHandAtRestDetector.invalidate();
}
auto rightHandIter = _controllerPoseMap.find(controller::Action::RIGHT_HAND);
if (rightHandIter != _controllerPoseMap.end() && rightHandIter->second.isValid()) {
_rightHandAtRestDetector.update(rightHandIter->second.getTranslation(), rightHandIter->second.getRotation());
if (_rightHandAtRestDetector.isAtRest()) {
rightHandIter->second.valid = false;
}
} else {
_rightHandAtRestDetector.invalidate();
}
auto headIter = _controllerPoseMap.find(controller::Action::HEAD);
// The 99th percentile man has a spine to fingertip to height ratio of 0.45. Lets increase that by about 10% to 0.5
// then measure the distance the center of the eyes to the finger tips. To come up with this ratio.
// From "The Measure of Man and Woman: Human Factors in Design, Revised Edition" by Alvin R. Tilley, Henry Dreyfuss Associates
const float MAX_HEAD_TO_HAND_DISTANCE_RATIO = 0.52f;
float maxHeadHandDistance = getUserHeight() * MAX_HEAD_TO_HAND_DISTANCE_RATIO;
if (glm::length(headIter->second.getTranslation() - leftHandIter->second.getTranslation()) > maxHeadHandDistance) {
leftHandIter->second.valid = false;
}
if (glm::length(headIter->second.getTranslation() - rightHandIter->second.getTranslation()) > maxHeadHandDistance) {
rightHandIter->second.valid = false;
}
}
{
PerformanceTimer perfTimer("skeleton");

View file

@ -1764,8 +1764,8 @@ private:
glm::vec3 _customListenPosition;
glm::quat _customListenOrientation;
AtRestDetector _hmdAtRestDetector;
bool _lastIsMoving { false };
AtRestDetector _leftHandAtRestDetector;
AtRestDetector _rightHandAtRestDetector;
// all poses are in sensor-frame
std::map<controller::Action, controller::Pose> _controllerPoseMap;

View file

@ -30,7 +30,9 @@ void AtRestDetector::reset(const glm::vec3& startPosition, const glm::quat& star
_isAtRest = false;
}
bool AtRestDetector::update(const glm::vec3& position, const glm::quat& rotation) {
void AtRestDetector::update(const glm::vec3& position, const glm::quat& rotation) {
_lastIsAtRest = _isAtRest;
if (_isValid) {
uint64_t now = usecTimestampNow();
float dt = (float)(now - _lastUpdateTime) / (float)USECS_PER_SECOND;
_lastUpdateTime = now;
@ -57,5 +59,8 @@ bool AtRestDetector::update(const glm::vec3& position, const glm::quat& rotation
const float QUAT_LOG_VARIANCE_THRESHOLD = 0.00002f;
_isAtRest = _positionVariance < POSITION_VARIANCE_THRESHOLD && _quatLogVariance < QUAT_LOG_VARIANCE_THRESHOLD;
return _isAtRest;
} else {
reset(position, rotation);
_isValid = true;
}
}

View file

@ -17,21 +17,27 @@
class AtRestDetector {
public:
AtRestDetector() {};
AtRestDetector(const glm::vec3& startPosition, const glm::quat& startRotation);
void reset(const glm::vec3& startPosition, const glm::quat& startRotation);
// returns true if object is at rest, dt in assumed to be seconds.
bool update(const glm::vec3& position, const glm::quat& startRotation);
void update(const glm::vec3& position, const glm::quat& startRotation);
void invalidate() { _isValid = false; }
bool isAtRest() const { return _isAtRest; }
bool onRest() const { return !_lastIsAtRest && _isAtRest; }
bool onWake() const { return _lastIsAtRest && !_isAtRest; }
protected:
bool _isValid { false };
glm::vec3 _positionAverage;
glm::vec3 _quatLogAverage;
uint64_t _lastUpdateTime { 0 };
float _positionVariance { 0.0f };
float _quatLogVariance { 0.0f };
bool _isAtRest { false };
bool _lastIsAtRest { false };
};
#endif