mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 23:40:11 +02:00
Merge pull request #13528 from amantley/integratedStepping
Step Detection From Head and Hands Tracking
This commit is contained in:
commit
1d33f51ca4
4 changed files with 247 additions and 12 deletions
|
@ -566,7 +566,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "idleToWalkFwd",
|
"id": "idleToWalkFwd",
|
||||||
"interpTarget": 3,
|
"interpTarget": 10,
|
||||||
"interpDuration": 3,
|
"interpDuration": 3,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "idleToWalkFwdOnDone", "state": "walkFwd" },
|
{ "var": "idleToWalkFwdOnDone", "state": "walkFwd" },
|
||||||
|
@ -603,8 +603,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkBwd",
|
"id": "walkBwd",
|
||||||
"interpTarget": 6,
|
"interpTarget": 8,
|
||||||
"interpDuration": 6,
|
"interpDuration": 2,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idle" },
|
{ "var": "isNotMoving", "state": "idle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||||
|
@ -621,8 +621,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeRight",
|
"id": "strafeRight",
|
||||||
"interpTarget": 6,
|
"interpTarget": 20,
|
||||||
"interpDuration": 6,
|
"interpDuration": 1,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idle" },
|
{ "var": "isNotMoving", "state": "idle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||||
|
@ -639,8 +639,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "strafeLeft",
|
"id": "strafeLeft",
|
||||||
"interpTarget": 6,
|
"interpTarget": 20,
|
||||||
"interpDuration": 6,
|
"interpDuration": 1,
|
||||||
"transitions": [
|
"transitions": [
|
||||||
{ "var": "isNotMoving", "state": "idle" },
|
{ "var": "isNotMoving", "state": "idle" },
|
||||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||||
|
|
|
@ -88,6 +88,10 @@ const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||||
const float MyAvatar::ZOOM_MAX = 25.0f;
|
const float MyAvatar::ZOOM_MAX = 25.0f;
|
||||||
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||||
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
||||||
|
const int MODE_READINGS_RING_BUFFER_SIZE = 500;
|
||||||
|
const float CENTIMETERS_PER_METER = 100.0f;
|
||||||
|
|
||||||
|
//#define DEBUG_DRAW_HMD_MOVING_AVERAGE
|
||||||
|
|
||||||
MyAvatar::MyAvatar(QThread* thread) :
|
MyAvatar::MyAvatar(QThread* thread) :
|
||||||
Avatar(thread),
|
Avatar(thread),
|
||||||
|
@ -108,6 +112,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
_hmdSensorMatrix(),
|
_hmdSensorMatrix(),
|
||||||
_hmdSensorOrientation(),
|
_hmdSensorOrientation(),
|
||||||
_hmdSensorPosition(),
|
_hmdSensorPosition(),
|
||||||
|
_recentModeReadings(MODE_READINGS_RING_BUFFER_SIZE),
|
||||||
_bodySensorMatrix(),
|
_bodySensorMatrix(),
|
||||||
_goToPending(false),
|
_goToPending(false),
|
||||||
_goToPosition(),
|
_goToPosition(),
|
||||||
|
@ -414,7 +419,8 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
||||||
void MyAvatar::update(float deltaTime) {
|
void MyAvatar::update(float deltaTime) {
|
||||||
|
|
||||||
// update moving average of HMD facing in xz plane.
|
// update moving average of HMD facing in xz plane.
|
||||||
const float HMD_FACING_TIMESCALE = 4.0f; // very slow average
|
const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength();
|
||||||
|
|
||||||
float tau = deltaTime / HMD_FACING_TIMESCALE;
|
float tau = deltaTime / HMD_FACING_TIMESCALE;
|
||||||
_headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau);
|
_headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau);
|
||||||
|
|
||||||
|
@ -423,6 +429,12 @@ void MyAvatar::update(float deltaTime) {
|
||||||
_smoothOrientationTimer += deltaTime;
|
_smoothOrientationTimer += deltaTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float newHeightReading = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y;
|
||||||
|
int newHeightReadingInCentimeters = glm::floor(newHeightReading * CENTIMETERS_PER_METER);
|
||||||
|
_recentModeReadings.insert(newHeightReadingInCentimeters);
|
||||||
|
setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
|
||||||
|
setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
|
||||||
|
|
||||||
#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE
|
#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE
|
||||||
auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||||
glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation());
|
glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation());
|
||||||
|
@ -2182,6 +2194,15 @@ void MyAvatar::setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement)
|
||||||
_headData->setHasAudioEnabledFaceMovement(hasAudioEnabledFaceMovement);
|
_headData->setHasAudioEnabledFaceMovement(hasAudioEnabledFaceMovement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setRotationRecenterFilterLength(float length) {
|
||||||
|
const float MINIMUM_ROTATION_RECENTER_FILTER_LENGTH = 0.01f;
|
||||||
|
_rotationRecenterFilterLength = std::max(MINIMUM_ROTATION_RECENTER_FILTER_LENGTH, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setRotationThreshold(float angleRadians) {
|
||||||
|
_rotationThreshold = angleRadians;
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::updateOrientation(float deltaTime) {
|
void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
||||||
// Smoothly rotate body with arrow keys
|
// Smoothly rotate body with arrow keys
|
||||||
|
@ -3146,6 +3167,148 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
||||||
return worldToSensorMat * avatarToWorldMat * avatarHipsMat;
|
return worldToSensorMat * avatarToWorldMat * avatarHipsMat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isInsideLine(const glm::vec3& a, const glm::vec3& b, const glm::vec3& c) {
|
||||||
|
return (((b.x - a.x) * (c.z - a.z) - (b.z - a.z) * (c.x - a.x)) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool withinBaseOfSupport(const controller::Pose& head) {
|
||||||
|
float userScale = 1.0f;
|
||||||
|
|
||||||
|
glm::vec3 frontLeft(-DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, -DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD);
|
||||||
|
glm::vec3 frontRight(DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, -DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD);
|
||||||
|
glm::vec3 backLeft(-DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD);
|
||||||
|
glm::vec3 backRight(DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD);
|
||||||
|
|
||||||
|
bool isWithinSupport = false;
|
||||||
|
if (head.isValid()) {
|
||||||
|
bool withinFrontBase = isInsideLine(userScale * frontLeft, userScale * frontRight, head.getTranslation());
|
||||||
|
bool withinBackBase = isInsideLine(userScale * backRight, userScale * backLeft, head.getTranslation());
|
||||||
|
bool withinLateralBase = (isInsideLine(userScale * frontRight, userScale * backRight, head.getTranslation()) &&
|
||||||
|
isInsideLine(userScale * backLeft, userScale * frontLeft, head.getTranslation()));
|
||||||
|
isWithinSupport = (withinFrontBase && withinBackBase && withinLateralBase);
|
||||||
|
}
|
||||||
|
return isWithinSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool headAngularVelocityBelowThreshold(const controller::Pose& head) {
|
||||||
|
glm::vec3 xzPlaneAngularVelocity(0.0f, 0.0f, 0.0f);
|
||||||
|
if (head.isValid()) {
|
||||||
|
xzPlaneAngularVelocity.x = head.getAngularVelocity().x;
|
||||||
|
xzPlaneAngularVelocity.z = head.getAngularVelocity().z;
|
||||||
|
}
|
||||||
|
float magnitudeAngularVelocity = glm::length(xzPlaneAngularVelocity);
|
||||||
|
bool isBelowThreshold = (magnitudeAngularVelocity < DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD);
|
||||||
|
|
||||||
|
return isBelowThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isWithinThresholdHeightMode(const controller::Pose& head,const float& newMode) {
|
||||||
|
bool isWithinThreshold = true;
|
||||||
|
if (head.isValid()) {
|
||||||
|
isWithinThreshold = (head.getTranslation().y - newMode) > DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD;
|
||||||
|
}
|
||||||
|
return isWithinThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
float MyAvatar::computeStandingHeightMode(const controller::Pose& head) {
|
||||||
|
const float MODE_CORRECTION_FACTOR = 0.02f;
|
||||||
|
int greatestFrequency = 0;
|
||||||
|
int mode = 0;
|
||||||
|
// init mode in meters to the current mode
|
||||||
|
float modeInMeters = getCurrentStandingHeight();
|
||||||
|
if (head.isValid()) {
|
||||||
|
std::map<int, int> freq;
|
||||||
|
for(auto recentModeReadingsIterator = _recentModeReadings.begin(); recentModeReadingsIterator != _recentModeReadings.end(); ++recentModeReadingsIterator) {
|
||||||
|
freq[*recentModeReadingsIterator] += 1;
|
||||||
|
if (freq[*recentModeReadingsIterator] > greatestFrequency) {
|
||||||
|
greatestFrequency = freq[*recentModeReadingsIterator];
|
||||||
|
mode = *recentModeReadingsIterator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modeInMeters = ((float)mode) / CENTIMETERS_PER_METER;
|
||||||
|
if (!(modeInMeters > getCurrentStandingHeight())) {
|
||||||
|
// if not greater check for a reset
|
||||||
|
if (getResetMode() && qApp->isHMDMode()) {
|
||||||
|
setResetMode(false);
|
||||||
|
float resetModeInCentimeters = glm::floor((head.getTranslation().y - MODE_CORRECTION_FACTOR)*CENTIMETERS_PER_METER);
|
||||||
|
modeInMeters = (resetModeInCentimeters / CENTIMETERS_PER_METER);
|
||||||
|
_recentModeReadings.clear();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// if not greater and no reset, keep the mode as it is
|
||||||
|
modeInMeters = getCurrentStandingHeight();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modeInMeters;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handDirectionMatchesHeadDirection(const controller::Pose& leftHand, const controller::Pose& rightHand, const controller::Pose& head) {
|
||||||
|
const float VELOCITY_EPSILON = 0.02f;
|
||||||
|
bool leftHandDirectionMatchesHead = true;
|
||||||
|
bool rightHandDirectionMatchesHead = true;
|
||||||
|
glm::vec3 xzHeadVelocity(head.velocity.x, 0.0f, head.velocity.z);
|
||||||
|
if (leftHand.isValid() && head.isValid()) {
|
||||||
|
glm::vec3 xzLeftHandVelocity(leftHand.velocity.x, 0.0f, leftHand.velocity.z);
|
||||||
|
if ((glm::length(xzLeftHandVelocity) > VELOCITY_EPSILON) && (glm::length(xzHeadVelocity) > VELOCITY_EPSILON)) {
|
||||||
|
float handDotHeadLeft = glm::dot(glm::normalize(xzLeftHandVelocity), glm::normalize(xzHeadVelocity));
|
||||||
|
leftHandDirectionMatchesHead = ((handDotHeadLeft > DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD));
|
||||||
|
} else {
|
||||||
|
leftHandDirectionMatchesHead = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rightHand.isValid() && head.isValid()) {
|
||||||
|
glm::vec3 xzRightHandVelocity(rightHand.velocity.x, 0.0f, rightHand.velocity.z);
|
||||||
|
if ((glm::length(xzRightHandVelocity) > VELOCITY_EPSILON) && (glm::length(xzHeadVelocity) > VELOCITY_EPSILON)) {
|
||||||
|
float handDotHeadRight = glm::dot(glm::normalize(xzRightHandVelocity), glm::normalize(xzHeadVelocity));
|
||||||
|
rightHandDirectionMatchesHead = (handDotHeadRight > DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD);
|
||||||
|
} else {
|
||||||
|
rightHandDirectionMatchesHead = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leftHandDirectionMatchesHead && rightHandDirectionMatchesHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handAngularVelocityBelowThreshold(const controller::Pose& leftHand, const controller::Pose& rightHand) {
|
||||||
|
float leftHandXZAngularVelocity = 0.0f;
|
||||||
|
float rightHandXZAngularVelocity = 0.0f;
|
||||||
|
if (leftHand.isValid()) {
|
||||||
|
glm::vec3 xzLeftHandAngularVelocity(leftHand.angularVelocity.x, 0.0f, leftHand.angularVelocity.z);
|
||||||
|
leftHandXZAngularVelocity = glm::length(xzLeftHandAngularVelocity);
|
||||||
|
}
|
||||||
|
if (rightHand.isValid()) {
|
||||||
|
glm::vec3 xzRightHandAngularVelocity(rightHand.angularVelocity.x, 0.0f, rightHand.angularVelocity.z);
|
||||||
|
rightHandXZAngularVelocity = glm::length(xzRightHandAngularVelocity);
|
||||||
|
}
|
||||||
|
return ((leftHandXZAngularVelocity < DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD) &&
|
||||||
|
(rightHandXZAngularVelocity < DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool headVelocityGreaterThanThreshold(const controller::Pose& head) {
|
||||||
|
float headVelocityMagnitude = 0.0f;
|
||||||
|
if (head.isValid()) {
|
||||||
|
headVelocityMagnitude = glm::length(head.getVelocity());
|
||||||
|
}
|
||||||
|
return headVelocityMagnitude > DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat MyAvatar::computeAverageHeadRotation(const controller::Pose& head) {
|
||||||
|
const float AVERAGING_RATE = 0.03f;
|
||||||
|
return safeLerp(_averageHeadRotation, head.getRotation(), AVERAGING_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isHeadLevel(const controller::Pose& head, const glm::quat& averageHeadRotation) {
|
||||||
|
glm::vec3 diffFromAverageEulers(0.0f, 0.0f, 0.0f);
|
||||||
|
if (head.isValid()) {
|
||||||
|
glm::vec3 averageHeadEulers = glm::degrees(safeEulerAngles(averageHeadRotation));
|
||||||
|
glm::vec3 currentHeadEulers = glm::degrees(safeEulerAngles(head.getRotation()));
|
||||||
|
diffFromAverageEulers = averageHeadEulers - currentHeadEulers;
|
||||||
|
}
|
||||||
|
return ((fabs(diffFromAverageEulers.x) < DEFAULT_HEAD_PITCH_STEPPING_TOLERANCE) && (fabs(diffFromAverageEulers.z) < DEFAULT_HEAD_ROLL_STEPPING_TOLERANCE));
|
||||||
|
}
|
||||||
|
|
||||||
float MyAvatar::getUserHeight() const {
|
float MyAvatar::getUserHeight() const {
|
||||||
return _userHeight.get();
|
return _userHeight.get();
|
||||||
}
|
}
|
||||||
|
@ -3312,7 +3475,7 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees
|
const float FOLLOW_ROTATION_THRESHOLD = cosf(myAvatar.getRotationThreshold());
|
||||||
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
||||||
return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
|
return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
@ -3339,7 +3502,37 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
||||||
}
|
}
|
||||||
|
|
||||||
return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
|
return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const {
|
||||||
|
|
||||||
|
// get the current readings
|
||||||
|
controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||||
|
controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
|
||||||
|
controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
|
||||||
|
|
||||||
|
bool stepDetected = false;
|
||||||
|
if (!withinBaseOfSupport(currentHeadPose) &&
|
||||||
|
headAngularVelocityBelowThreshold(currentHeadPose) &&
|
||||||
|
isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight()) &&
|
||||||
|
handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) &&
|
||||||
|
handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) &&
|
||||||
|
headVelocityGreaterThanThreshold(currentHeadPose) &&
|
||||||
|
isHeadLevel(currentHeadPose, myAvatar.getAverageHeadRotation())) {
|
||||||
|
// a step is detected
|
||||||
|
stepDetected = true;
|
||||||
|
} else {
|
||||||
|
glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips"));
|
||||||
|
glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head"));
|
||||||
|
glm::vec3 currentHeadPosition = currentHeadPose.getTranslation();
|
||||||
|
float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition);
|
||||||
|
if (!isActive(Horizontal) &&
|
||||||
|
(glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + DEFAULT_AVATAR_SPINE_STRETCH_LIMIT))) {
|
||||||
|
myAvatar.setResetMode(true);
|
||||||
|
stepDetected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stepDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
|
@ -3359,9 +3552,16 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
||||||
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||||
activate(Rotation);
|
activate(Rotation);
|
||||||
}
|
}
|
||||||
if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
if (myAvatar.getCenterOfGravityModelEnabled()) {
|
||||||
activate(Horizontal);
|
if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) {
|
||||||
|
activate(Horizontal);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||||
|
activate(Horizontal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||||
activate(Vertical);
|
activate(Vertical);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "AtRestDetector.h"
|
#include "AtRestDetector.h"
|
||||||
#include "MyCharacterController.h"
|
#include "MyCharacterController.h"
|
||||||
|
#include "RingBufferHistory.h"
|
||||||
#include <ThreadSafeValueCache.h>
|
#include <ThreadSafeValueCache.h>
|
||||||
|
|
||||||
class AvatarActionHold;
|
class AvatarActionHold;
|
||||||
|
@ -195,6 +196,8 @@ class MyAvatar : public Avatar {
|
||||||
Q_PROPERTY(bool hasProceduralBlinkFaceMovement READ getHasProceduralBlinkFaceMovement WRITE setHasProceduralBlinkFaceMovement)
|
Q_PROPERTY(bool hasProceduralBlinkFaceMovement READ getHasProceduralBlinkFaceMovement WRITE setHasProceduralBlinkFaceMovement)
|
||||||
Q_PROPERTY(bool hasProceduralEyeFaceMovement READ getHasProceduralEyeFaceMovement WRITE setHasProceduralEyeFaceMovement)
|
Q_PROPERTY(bool hasProceduralEyeFaceMovement READ getHasProceduralEyeFaceMovement WRITE setHasProceduralEyeFaceMovement)
|
||||||
Q_PROPERTY(bool hasAudioEnabledFaceMovement READ getHasAudioEnabledFaceMovement WRITE setHasAudioEnabledFaceMovement)
|
Q_PROPERTY(bool hasAudioEnabledFaceMovement READ getHasAudioEnabledFaceMovement WRITE setHasAudioEnabledFaceMovement)
|
||||||
|
Q_PROPERTY(float rotationRecenterFilterLength READ getRotationRecenterFilterLength WRITE setRotationRecenterFilterLength)
|
||||||
|
Q_PROPERTY(float rotationThreshold READ getRotationThreshold WRITE setRotationThreshold)
|
||||||
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
|
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
|
||||||
|
|
||||||
Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition)
|
Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition)
|
||||||
|
@ -880,6 +883,12 @@ public:
|
||||||
virtual void rebuildCollisionShape() override;
|
virtual void rebuildCollisionShape() override;
|
||||||
|
|
||||||
const glm::vec2& getHeadControllerFacingMovingAverage() const { return _headControllerFacingMovingAverage; }
|
const glm::vec2& getHeadControllerFacingMovingAverage() const { return _headControllerFacingMovingAverage; }
|
||||||
|
float getCurrentStandingHeight() const { return _currentStandingHeight; }
|
||||||
|
void setCurrentStandingHeight(float newMode) { _currentStandingHeight = newMode; }
|
||||||
|
const glm::quat getAverageHeadRotation() const { return _averageHeadRotation; }
|
||||||
|
void setAverageHeadRotation(glm::quat rotation) { _averageHeadRotation = rotation; }
|
||||||
|
bool getResetMode() const { return _resetMode; }
|
||||||
|
void setResetMode(bool hasBeenReset) { _resetMode = hasBeenReset; }
|
||||||
|
|
||||||
void setControllerPoseInSensorFrame(controller::Action action, const controller::Pose& pose);
|
void setControllerPoseInSensorFrame(controller::Action action, const controller::Pose& pose);
|
||||||
controller::Pose getControllerPoseInSensorFrame(controller::Action action) const;
|
controller::Pose getControllerPoseInSensorFrame(controller::Action action) const;
|
||||||
|
@ -1020,6 +1029,9 @@ public:
|
||||||
|
|
||||||
bool isReadyForPhysics() const;
|
bool isReadyForPhysics() const;
|
||||||
|
|
||||||
|
float computeStandingHeightMode(const controller::Pose& head);
|
||||||
|
glm::quat computeAverageHeadRotation(const controller::Pose& head);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -1408,6 +1420,10 @@ private:
|
||||||
bool getHasProceduralEyeFaceMovement() const override { return _headData->getHasProceduralEyeFaceMovement(); }
|
bool getHasProceduralEyeFaceMovement() const override { return _headData->getHasProceduralEyeFaceMovement(); }
|
||||||
void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement);
|
void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement);
|
||||||
bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); }
|
bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); }
|
||||||
|
void setRotationRecenterFilterLength(float length);
|
||||||
|
float getRotationRecenterFilterLength() const { return _rotationRecenterFilterLength; }
|
||||||
|
void setRotationThreshold(float angleRadians);
|
||||||
|
float getRotationThreshold() const { return _rotationThreshold; }
|
||||||
bool isMyAvatar() const override { return true; }
|
bool isMyAvatar() const override { return true; }
|
||||||
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
|
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
|
||||||
virtual glm::vec3 getSkeletonPosition() const override;
|
virtual glm::vec3 getSkeletonPosition() const override;
|
||||||
|
@ -1516,6 +1532,8 @@ private:
|
||||||
float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT };
|
float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT };
|
||||||
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
||||||
std::atomic<bool> _hasScriptedBlendShapes { false };
|
std::atomic<bool> _hasScriptedBlendShapes { false };
|
||||||
|
std::atomic<float> _rotationRecenterFilterLength { 4.0f };
|
||||||
|
std::atomic<float> _rotationThreshold { 0.5235f }; // 30 degrees in radians
|
||||||
|
|
||||||
// working copy -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
// working copy -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||||
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
||||||
|
@ -1527,6 +1545,11 @@ private:
|
||||||
// cache head controller pose in sensor space
|
// cache head controller pose in sensor space
|
||||||
glm::vec2 _headControllerFacing; // facing vector in xz plane (sensor space)
|
glm::vec2 _headControllerFacing; // facing vector in xz plane (sensor space)
|
||||||
glm::vec2 _headControllerFacingMovingAverage { 0.0f, 0.0f }; // facing vector in xz plane (sensor space)
|
glm::vec2 _headControllerFacingMovingAverage { 0.0f, 0.0f }; // facing vector in xz plane (sensor space)
|
||||||
|
glm::quat _averageHeadRotation { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
|
||||||
|
float _currentStandingHeight { 0.0f };
|
||||||
|
bool _resetMode { true };
|
||||||
|
RingBufferHistory<int> _recentModeReadings;
|
||||||
|
|
||||||
// cache of the current body position and orientation of the avatar's body,
|
// cache of the current body position and orientation of the avatar's body,
|
||||||
// in sensor space.
|
// in sensor space.
|
||||||
|
@ -1554,6 +1577,7 @@ private:
|
||||||
bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
||||||
bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
||||||
bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
||||||
|
bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const;
|
||||||
void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput);
|
void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput);
|
||||||
glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
|
glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
|
||||||
bool getForceActivateRotation() const;
|
bool getForceActivateRotation() const;
|
||||||
|
@ -1642,7 +1666,7 @@ private:
|
||||||
// load avatar scripts once when rig is ready
|
// load avatar scripts once when rig is ready
|
||||||
bool _shouldLoadScripts { false };
|
bool _shouldLoadScripts { false };
|
||||||
|
|
||||||
bool _haveReceivedHeightLimitsFromDomain = { false };
|
bool _haveReceivedHeightLimitsFromDomain { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||||
|
|
|
@ -24,6 +24,17 @@ const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f;
|
||||||
const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f;
|
const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f;
|
||||||
const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f;
|
const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f;
|
||||||
const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.10f;
|
const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.10f;
|
||||||
|
const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.10f;
|
||||||
|
const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.04f;
|
||||||
|
const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.07f;
|
||||||
|
const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.3f;
|
||||||
|
const float DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD = -0.02f;
|
||||||
|
const float DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD = 0.4f;
|
||||||
|
const float DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 3.3f;
|
||||||
|
const float DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD = 0.18f;
|
||||||
|
const float DEFAULT_HEAD_PITCH_STEPPING_TOLERANCE = 7.0f;
|
||||||
|
const float DEFAULT_HEAD_ROLL_STEPPING_TOLERANCE = 7.0f;
|
||||||
|
const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.07f;
|
||||||
const float DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR = 0.5f;
|
const float DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR = 0.5f;
|
||||||
const float DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR = 2.0f;
|
const float DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR = 2.0f;
|
||||||
const float DEFAULT_AVATAR_HIPS_MASS = 40.0f;
|
const float DEFAULT_AVATAR_HIPS_MASS = 40.0f;
|
||||||
|
|
Loading…
Reference in a new issue