mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge remote-tracking branch 'origin/squattyPottyFix' into squattyPottyFix
This commit is contained in:
commit
ab7a70acba
9 changed files with 338 additions and 31 deletions
|
@ -252,6 +252,8 @@ Rectangle {
|
|||
var avatarSettings = {
|
||||
dominantHand : settings.dominantHandIsLeft ? 'left' : 'right',
|
||||
collisionsEnabled : settings.avatarCollisionsOn,
|
||||
sittingEnabled : settings.avatarSittingOn,
|
||||
lockStateEnabled : settings.avatarLockSitStandStateOn,
|
||||
animGraphOverrideUrl : settings.avatarAnimationOverrideJSON,
|
||||
collisionSoundUrl : settings.avatarCollisionSoundUrl
|
||||
};
|
||||
|
|
|
@ -20,6 +20,8 @@ Rectangle {
|
|||
property real scaleValue: scaleSlider.value / 10
|
||||
property alias dominantHandIsLeft: leftHandRadioButton.checked
|
||||
property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked
|
||||
property alias avatarSittingOn: sitRadiobutton.checked
|
||||
property alias avatarLockSitStandStateOn: lockSitStandStateCheckbox.checked
|
||||
property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text
|
||||
property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText
|
||||
property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text
|
||||
|
@ -45,6 +47,18 @@ Rectangle {
|
|||
collisionsDisabledRadioButton.checked = true;
|
||||
}
|
||||
|
||||
if (settings.sittingEnabled) {
|
||||
sitRadiobutton.checked = true;
|
||||
} else {
|
||||
standRadioButton.checked = true;
|
||||
}
|
||||
|
||||
if (settings.lockStateEnabled) {
|
||||
lockSitStandStateCheckbox.checked = true;
|
||||
} else {
|
||||
lockSitStandStateCheckbox.checked = false;
|
||||
}
|
||||
|
||||
avatarAnimationJSON = settings.animGraphUrl;
|
||||
avatarAnimationOverrideJSON = settings.animGraphOverrideUrl;
|
||||
avatarCollisionSoundUrl = settings.collisionSoundUrl;
|
||||
|
@ -289,6 +303,65 @@ Rectangle {
|
|||
text: "OFF"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
// TextStyle9
|
||||
|
||||
RalewaySemiBold {
|
||||
size: 17;
|
||||
Layout.row: 2
|
||||
Layout.column: 0
|
||||
|
||||
text: "Sitting State"
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: sitStand
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: sitRadiobutton
|
||||
|
||||
Layout.row: 2
|
||||
Layout.column: 1
|
||||
Layout.leftMargin: -40
|
||||
|
||||
ButtonGroup.group: sitStand
|
||||
checked: true
|
||||
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
fontSize: 17
|
||||
letterSpacing: 1.4
|
||||
text: "Sit"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: standRadioButton
|
||||
|
||||
Layout.row: 2
|
||||
Layout.column: 2
|
||||
Layout.rightMargin: 20
|
||||
|
||||
ButtonGroup.group: sitStand
|
||||
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
fontSize: 17
|
||||
letterSpacing: 1.4
|
||||
text: "Stand"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
// "Lock State" Checkbox
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: lockSitStandStateCheckbox;
|
||||
visible: activeTab == "nearbyTab";
|
||||
anchors.right: reloadNearbyContainer.left;
|
||||
anchors.rightMargin: 20;
|
||||
checked: settings.lockStateEnabled;
|
||||
text: "lock";
|
||||
boxSize: 24;
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
|
|
@ -468,6 +468,11 @@ void MyAvatar::update(float deltaTime) {
|
|||
// update moving average of HMD facing in xz plane.
|
||||
const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength();
|
||||
const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders
|
||||
const float STANDING_HEIGHT_MULTIPLE = 1.2f;
|
||||
const float SITTING_HEIGHT_MULTIPLE = 0.833f;
|
||||
const float COSINE_TEN_DEGREES = 0.98f;
|
||||
const int SITTING_COUNT_THRESHOLD = 300;
|
||||
const int SQUATTY_COUNT_THRESHOLD = 600;
|
||||
|
||||
float tau = deltaTime / HMD_FACING_TIMESCALE;
|
||||
setHipToHandController(computeHandAzimuth());
|
||||
|
@ -494,11 +499,90 @@ void MyAvatar::update(float 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)));
|
||||
controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
if (newHeightReading.isValid()) {
|
||||
int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER);
|
||||
_sumUserHeightSensorSpace += newHeightReading.getTranslation().y;
|
||||
_averageUserHeightCount++;
|
||||
_recentModeReadings.insert(newHeightReadingInCentimeters);
|
||||
setCurrentStandingHeight(computeStandingHeightMode(newHeightReading));
|
||||
setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
|
||||
}
|
||||
|
||||
// if the spine is straight and the head is below the default position by 5 cm then increment squatty count.
|
||||
const float SQUAT_THRESHOLD = 0.05f;
|
||||
glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head"));
|
||||
glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2"));
|
||||
glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
if (glm::length(upSpine2) > 0.0f) {
|
||||
upSpine2 = glm::normalize(upSpine2);
|
||||
}
|
||||
float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) {
|
||||
_squatCount++;
|
||||
} else {
|
||||
_squatCount = 0;
|
||||
}
|
||||
|
||||
float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount;
|
||||
|
||||
glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips"));
|
||||
glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips);
|
||||
glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips);
|
||||
|
||||
// put update sit stand state counts here
|
||||
if (getIsSitStandStateLocked()) {
|
||||
if (getIsInSittingState()) {
|
||||
if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) {
|
||||
// if we recenter upwards then no longer in sitting state
|
||||
_sitStandStateCount++;
|
||||
if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) {
|
||||
_sitStandStateCount = 0;
|
||||
_squatCount = 0;
|
||||
if (newHeightReading.isValid()) {
|
||||
_sumUserHeightSensorSpace = newHeightReading.getTranslation().y;
|
||||
_tippingPoint = newHeightReading.getTranslation().y;
|
||||
}
|
||||
_averageUserHeightCount = 1;
|
||||
setResetMode(true);
|
||||
setIsInSittingState(false);
|
||||
setCenterOfGravityModelEnabled(true);
|
||||
setSitStandStateChange(true);
|
||||
}
|
||||
qCDebug(interfaceapp) << "going to stand state";
|
||||
} else {
|
||||
_sitStandStateCount = 0;
|
||||
// tipping point is average height when sitting.
|
||||
_tippingPoint = averageSensorSpaceHeight;
|
||||
}
|
||||
} else {
|
||||
// in the standing state
|
||||
if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) {
|
||||
_sitStandStateCount++;
|
||||
if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) {
|
||||
_sitStandStateCount = 0;
|
||||
_squatCount = 0;
|
||||
if (newHeightReading.isValid()) {
|
||||
_sumUserHeightSensorSpace = newHeightReading.getTranslation().y;
|
||||
_tippingPoint = newHeightReading.getTranslation().y;
|
||||
}
|
||||
_averageUserHeightCount = 1;
|
||||
setResetMode(true);
|
||||
setIsInSittingState(true);
|
||||
setCenterOfGravityModelEnabled(false);
|
||||
|
||||
setSitStandStateChange(true);
|
||||
}
|
||||
qCDebug(interfaceapp) << "going to sit state";
|
||||
} else {
|
||||
// returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
||||
// use the mode height for the tipping point when we are standing.
|
||||
_tippingPoint = getCurrentStandingHeight();
|
||||
_sitStandStateCount = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (_drawAverageFacingEnabled) {
|
||||
auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
|
@ -510,7 +594,7 @@ void MyAvatar::update(float deltaTime) {
|
|||
|
||||
// draw hand azimuth vector
|
||||
glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y));
|
||||
DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f));
|
||||
DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
if (_goToPending) {
|
||||
|
@ -852,6 +936,13 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
// Find the vector halfway between the hip to hand azimuth vectors
|
||||
// This midpoint hand azimuth is in Avatar space
|
||||
glm::vec2 MyAvatar::computeHandAzimuth() const {
|
||||
int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2");
|
||||
glm::vec3 azimuthOrigin(0.0f,0.0f,0.0f);
|
||||
if (!(spine2Index < 0)) {
|
||||
// use the spine for the azimuth origin.
|
||||
azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index);
|
||||
}
|
||||
|
||||
controller::Pose leftHandPoseAvatarSpace = getLeftHandPose();
|
||||
controller::Pose rightHandPoseAvatarSpace = getRightHandPose();
|
||||
controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||
|
@ -859,11 +950,13 @@ glm::vec2 MyAvatar::computeHandAzimuth() const {
|
|||
glm::vec2 latestHipToHandController = _hipToHandController;
|
||||
|
||||
if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) {
|
||||
glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - azimuthOrigin;
|
||||
glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - azimuthOrigin;
|
||||
// we need the old azimuth reading to prevent flipping the facing direction 180
|
||||
// in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart.
|
||||
glm::vec2 oldAzimuthReading = _hipToHandController;
|
||||
if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) {
|
||||
latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY);
|
||||
if ((glm::length(glm::vec2(rightHandOffset.x, rightHandOffset.z)) > 0.0f) && (glm::length(glm::vec2(leftHandOffset.x, leftHandOffset.z)) > 0.0f)) {
|
||||
latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandOffset.x, rightHandOffset.z)), glm::normalize(glm::vec2(leftHandOffset.x, leftHandOffset.z)), HALFWAY);
|
||||
} else {
|
||||
latestHipToHandController = glm::vec2(0.0f, -1.0f);
|
||||
}
|
||||
|
@ -3535,10 +3628,6 @@ glm::vec3 MyAvatar::computeCounterBalance() {
|
|||
if (counterBalancedCg.y > (tposeHips.y + 0.05f)) {
|
||||
// if the height is higher than default hips, clamp to default hips
|
||||
counterBalancedCg.y = tposeHips.y + 0.05f;
|
||||
} else if (counterBalancedCg.y < sitSquatThreshold) {
|
||||
//do a height reset
|
||||
setResetMode(true);
|
||||
_follow.activate(FollowHelper::Vertical);
|
||||
}
|
||||
return counterBalancedCg;
|
||||
}
|
||||
|
@ -3779,6 +3868,14 @@ bool MyAvatar::getIsInWalkingState() const {
|
|||
return _isInWalkingState;
|
||||
}
|
||||
|
||||
bool MyAvatar::getIsInSittingState() const {
|
||||
return _isInSittingState.get();
|
||||
}
|
||||
|
||||
bool MyAvatar::getIsSitStandStateLocked() const {
|
||||
return _lockSitStandState.get();
|
||||
}
|
||||
|
||||
float MyAvatar::getWalkSpeed() const {
|
||||
return _walkSpeed.get() * _walkSpeedScalar;
|
||||
}
|
||||
|
@ -3799,6 +3896,16 @@ void MyAvatar::setIsInWalkingState(bool isWalking) {
|
|||
_isInWalkingState = isWalking;
|
||||
}
|
||||
|
||||
void MyAvatar::setIsInSittingState(bool isSitting) {
|
||||
_isInSittingState.set(isSitting);
|
||||
emit sittingEnabledChanged(isSitting);
|
||||
}
|
||||
|
||||
void MyAvatar::setIsSitStandStateLocked(bool isLocked) {
|
||||
_lockSitStandState.set(isLocked);
|
||||
emit sitStandStateLockEnabledChanged(isLocked);
|
||||
}
|
||||
|
||||
void MyAvatar::setWalkSpeed(float value) {
|
||||
_walkSpeed.set(value);
|
||||
}
|
||||
|
@ -3815,6 +3922,14 @@ float MyAvatar::getSprintSpeed() const {
|
|||
return _sprintSpeed.get();
|
||||
}
|
||||
|
||||
void MyAvatar::setSitStandStateChange(bool stateChanged) {
|
||||
_sitStandStateChange = stateChanged;
|
||||
}
|
||||
|
||||
float MyAvatar::getSitStandStateChange() const {
|
||||
return _sitStandStateChange;
|
||||
}
|
||||
|
||||
QVector<QString> MyAvatar::getScriptUrls() {
|
||||
QVector<QString> scripts = _skeletonModel->isLoaded() ? _skeletonModel->getFBXGeometry().scripts : QVector<QString>();
|
||||
return scripts;
|
||||
|
@ -3958,6 +4073,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
|||
// x axis of currentBodyMatrix in world space.
|
||||
glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0]));
|
||||
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
|
||||
controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||
|
||||
float forwardLeanAmount = glm::dot(forward, offset);
|
||||
float lateralLeanAmount = glm::dot(right, offset);
|
||||
|
@ -3966,14 +4082,19 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
|||
const float MAX_FORWARD_LEAN = 0.15f;
|
||||
const float MAX_BACKWARD_LEAN = 0.1f;
|
||||
|
||||
|
||||
if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
|
||||
return true;
|
||||
bool stepDetected = false;
|
||||
if (myAvatar.getIsInSittingState()) {
|
||||
if (!withinBaseOfSupport(currentHeadPose)) {
|
||||
stepDetected = true;
|
||||
}
|
||||
} else if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
|
||||
stepDetected = true;
|
||||
} else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) {
|
||||
return true;
|
||||
stepDetected = true;
|
||||
} else {
|
||||
stepDetected = fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
|
||||
}
|
||||
|
||||
return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
|
||||
return stepDetected;
|
||||
}
|
||||
|
||||
bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const {
|
||||
|
@ -3982,6 +4103,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
|
|||
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);
|
||||
controller::Pose currentHeadSensorPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
|
||||
bool stepDetected = false;
|
||||
float myScale = myAvatar.getAvatarScale();
|
||||
|
@ -3991,7 +4113,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
|
|||
} else {
|
||||
if (!withinBaseOfSupport(currentHeadPose) &&
|
||||
headAngularVelocityBelowThreshold(currentHeadPose) &&
|
||||
isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight(), myScale) &&
|
||||
isWithinThresholdHeightMode(currentHeadSensorPose, myAvatar.getCurrentStandingHeight(), myScale) &&
|
||||
handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) &&
|
||||
handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) &&
|
||||
headVelocityGreaterThanThreshold(currentHeadPose) &&
|
||||
|
@ -4007,6 +4129,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
|
|||
glm::vec3 currentHeadPosition = currentHeadPose.getTranslation();
|
||||
float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition);
|
||||
if (!isActive(Horizontal) &&
|
||||
(!isActive(Vertical)) &&
|
||||
(glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) {
|
||||
myAvatar.setResetMode(true);
|
||||
stepDetected = true;
|
||||
|
@ -4019,13 +4142,39 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
|
|||
return stepDetected;
|
||||
}
|
||||
|
||||
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||
bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||
const float CYLINDER_TOP = 0.1f;
|
||||
const float CYLINDER_BOTTOM = -1.5f;
|
||||
const float SITTING_BOTTOM = -0.02f;
|
||||
const int SQUATTY_COUNT_THRESHOLD = 600;
|
||||
|
||||
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
|
||||
|
||||
bool returnValue = false;
|
||||
returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
||||
|
||||
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
||||
if (myAvatar.getSitStandStateChange()) {
|
||||
qCDebug(interfaceapp) << "sit state change";
|
||||
returnValue = true;
|
||||
}
|
||||
if (myAvatar.getIsInSittingState()) {
|
||||
if (offset.y < SITTING_BOTTOM) {
|
||||
// we recenter when sitting.
|
||||
qCDebug(interfaceapp) << "lean back sitting ";
|
||||
returnValue = true;
|
||||
}
|
||||
} else {
|
||||
// in the standing state
|
||||
if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) {
|
||||
myAvatar._squatCount = 0;
|
||||
qCDebug(interfaceapp) << "squatting ";
|
||||
// returnValue = true;
|
||||
}
|
||||
if (returnValue == true) {
|
||||
qCDebug(interfaceapp) << "above or below capsule in standing";
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix,
|
||||
|
@ -4033,6 +4182,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
|
||||
if (myAvatar.getHMDLeanRecenterEnabled() &&
|
||||
qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
|
||||
|
||||
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||
activate(Rotation);
|
||||
myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
|
||||
|
@ -4046,6 +4196,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// center of gravity model is not enabled
|
||||
if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||
activate(Horizontal);
|
||||
if (myAvatar.getEnableStepResetRotation()) {
|
||||
|
@ -4054,9 +4205,18 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||
activate(Vertical);
|
||||
|
||||
if (_velocityCount > 60) {
|
||||
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||
activate(Vertical);
|
||||
}
|
||||
} else {
|
||||
if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) {
|
||||
_velocityCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
if (!isActive(Rotation) && getForceActivateRotation()) {
|
||||
activate(Rotation);
|
||||
|
@ -4105,7 +4265,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining());
|
||||
}
|
||||
|
||||
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
|
||||
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
|
||||
if (isActive()) {
|
||||
float dt = myAvatar.getCharacterController()->getFollowTime();
|
||||
decrementTimeRemaining(dt);
|
||||
|
@ -4122,6 +4282,11 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
|
|||
|
||||
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
|
||||
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
||||
if (myAvatar.getSitStandStateChange()) {
|
||||
myAvatar.setSitStandStateChange(false);
|
||||
deactivate(Vertical);
|
||||
setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor()));
|
||||
}
|
||||
return newBodyMat;
|
||||
} else {
|
||||
return currentBodyMatrix;
|
||||
|
|
|
@ -142,6 +142,7 @@ class MyAvatar : public Avatar {
|
|||
* @property {number} walkSpeed
|
||||
* @property {number} walkBackwardSpeed
|
||||
* @property {number} sprintSpeed
|
||||
* @property {number} isInSittingState
|
||||
*
|
||||
* @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the
|
||||
* registration point of the 3D model.
|
||||
|
@ -242,6 +243,8 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(float walkSpeed READ getWalkSpeed WRITE setWalkSpeed);
|
||||
Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed);
|
||||
Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed);
|
||||
Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState);
|
||||
Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked);
|
||||
|
||||
const QString DOMINANT_LEFT_HAND = "left";
|
||||
const QString DOMINANT_RIGHT_HAND = "right";
|
||||
|
@ -1101,12 +1104,18 @@ public:
|
|||
|
||||
void setIsInWalkingState(bool isWalking);
|
||||
bool getIsInWalkingState() const;
|
||||
void setIsInSittingState(bool isSitting);
|
||||
bool getIsInSittingState() const;
|
||||
void setIsSitStandStateLocked(bool isLocked);
|
||||
bool getIsSitStandStateLocked() const;
|
||||
void setWalkSpeed(float value);
|
||||
float getWalkSpeed() const;
|
||||
void setWalkBackwardSpeed(float value);
|
||||
float getWalkBackwardSpeed() const;
|
||||
void setSprintSpeed(float value);
|
||||
float getSprintSpeed() const;
|
||||
void setSitStandStateChange(bool stateChanged);
|
||||
float getSitStandStateChange() const;
|
||||
|
||||
QVector<QString> getScriptUrls();
|
||||
|
||||
|
@ -1512,6 +1521,22 @@ signals:
|
|||
*/
|
||||
void disableHandTouchForIDChanged(const QUuid& entityID, bool disable);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the sit state is enabled or disabled
|
||||
* @function MyAvatar.sittingEnabledChanged
|
||||
* @param {boolean} enabled
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void sittingEnabledChanged(bool enabled);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the sit state is enabled or disabled
|
||||
* @function MyAvatar.sitStandStateLockEnabledChanged
|
||||
* @param {boolean} enabled
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void sitStandStateLockEnabledChanged(bool enabled);
|
||||
|
||||
private slots:
|
||||
void leaveDomain();
|
||||
void updateCollisionCapsuleCache();
|
||||
|
@ -1718,11 +1743,11 @@ private:
|
|||
float getMaxTimeRemaining() const;
|
||||
void decrementTimeRemaining(float dt);
|
||||
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(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);
|
||||
glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
|
||||
glm::mat4 postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
|
||||
bool getForceActivateRotation() const;
|
||||
void setForceActivateRotation(bool val);
|
||||
bool getForceActivateVertical() const;
|
||||
|
@ -1735,6 +1760,7 @@ private:
|
|||
std::atomic<bool> _forceActivateVertical { false };
|
||||
std::atomic<bool> _forceActivateHorizontal { false };
|
||||
std::atomic<bool> _toggleHipsFollowing { true };
|
||||
int _velocityCount { 0 };
|
||||
};
|
||||
FollowHelper _follow;
|
||||
|
||||
|
@ -1800,17 +1826,27 @@ private:
|
|||
std::mutex _pinnedJointsMutex;
|
||||
std::vector<int> _pinnedJoints;
|
||||
|
||||
// height of user in sensor space, when standing erect.
|
||||
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
|
||||
|
||||
void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize);
|
||||
|
||||
const float DEFAULT_FLOOR_HEIGHT = 0.0f;
|
||||
|
||||
// height of user in sensor space, when standing erect.
|
||||
ThreadSafeValueCache<float> _userHeight{ DEFAULT_AVATAR_HEIGHT };
|
||||
float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT };
|
||||
int _averageUserHeightCount{ 1 };
|
||||
bool _sitStandStateChange{ false };
|
||||
ThreadSafeValueCache<bool> _lockSitStandState { true };
|
||||
|
||||
// max unscaled forward movement speed
|
||||
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
|
||||
ThreadSafeValueCache<float> _walkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED };
|
||||
ThreadSafeValueCache<float> _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR };
|
||||
float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR };
|
||||
bool _isInWalkingState { false };
|
||||
ThreadSafeValueCache<bool> _isInSittingState { false };
|
||||
int _sitStandStateCount { 0 };
|
||||
int _squatCount { 0 };
|
||||
float _tippingPoint { DEFAULT_FLOOR_HEIGHT };
|
||||
|
||||
// load avatar scripts once when rig is ready
|
||||
bool _shouldLoadScripts { false };
|
||||
|
|
|
@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
|||
}
|
||||
|
||||
glm::mat4 hipsMat;
|
||||
if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) {
|
||||
if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState())) {
|
||||
// then we use center of gravity model
|
||||
hipsMat = myAvatar->deriveBodyUsingCgModel();
|
||||
} else {
|
||||
|
@ -250,6 +250,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
bool headExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Head"), currentHeadPose);
|
||||
bool hipsExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Hips"), currentHipsPose);
|
||||
if (spine2Exists && headExists && hipsExists) {
|
||||
|
||||
AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace());
|
||||
glm::vec3 u, v, w;
|
||||
glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
|
|
|
@ -1717,6 +1717,7 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) {
|
|||
|
||||
glm::vec3 Avatar::getWorldFeetPosition() {
|
||||
ShapeInfo shapeInfo;
|
||||
|
||||
computeShapeInfo(shapeInfo);
|
||||
glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight
|
||||
glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y - halfExtents.x, 0.0f);
|
||||
|
|
|
@ -85,6 +85,11 @@ private:
|
|||
if (!OVR_SUCCESS(ovr_Create(&session, &luid))) {
|
||||
qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError();
|
||||
return;
|
||||
} else {
|
||||
ovrResult setFloorLevelOrigin = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel);
|
||||
if (!OVR_SUCCESS(setFloorLevelOrigin)) {
|
||||
qCWarning(oculusLog) << "Failed to set the Oculus tracking origin to floor level" << ovr::getError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -463,7 +463,7 @@ bool OpenVrDisplayPlugin::internalActivate() {
|
|||
auto chaperone = vr::VRChaperone();
|
||||
if (chaperone) {
|
||||
float const UI_RADIUS = 1.0f;
|
||||
float const UI_HEIGHT = 1.6f;
|
||||
float const UI_HEIGHT = 0.0f;
|
||||
float const UI_Z_OFFSET = 0.5;
|
||||
|
||||
float xSize, zSize;
|
||||
|
|
|
@ -64,6 +64,8 @@ function getMyAvatarSettings() {
|
|||
return {
|
||||
dominantHand: MyAvatar.getDominantHand(),
|
||||
collisionsEnabled : MyAvatar.getCollisionsEnabled(),
|
||||
sittingEnabled: MyAvatar.isInSittingState,
|
||||
lockStateEnabled: MyAvatar.isSitStandStateLocked,
|
||||
collisionSoundUrl : MyAvatar.collisionSoundURL,
|
||||
animGraphUrl: MyAvatar.getAnimGraphUrl(),
|
||||
animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(),
|
||||
|
@ -136,6 +138,22 @@ function onCollisionsEnabledChanged(enabled) {
|
|||
}
|
||||
}
|
||||
|
||||
function onSittingEnabledChanged(isSitting) {
|
||||
if (currentAvatarSettings.sittingEnabled !== isSitting) {
|
||||
currentAvatarSettings.sittingEnabled = isSitting;
|
||||
print("emit sitting changed");
|
||||
sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting })
|
||||
}
|
||||
}
|
||||
|
||||
function onSitStandStateLockedEnabledChanged(isLocked) {
|
||||
if (currentAvatarSettings.lockStateEnabled !== isLocked) {
|
||||
currentAvatarSettings.lockStateEnabled = isLocked;
|
||||
print("emit lock sit stand state changed");
|
||||
sendToQml({ 'method': 'settingChanged', 'name': 'lockStateEnabled', 'value': isLocked })
|
||||
}
|
||||
}
|
||||
|
||||
function onNewCollisionSoundUrl(url) {
|
||||
if(currentAvatarSettings.collisionSoundUrl !== url) {
|
||||
currentAvatarSettings.collisionSoundUrl = url;
|
||||
|
@ -314,6 +332,8 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
|||
|
||||
MyAvatar.setDominantHand(message.settings.dominantHand);
|
||||
MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled);
|
||||
MyAvatar.isInSittingState = message.settings.sittingEnabled;
|
||||
MyAvatar.isSitStandStateLocked = message.settings.lockStateEnabled;
|
||||
MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl;
|
||||
MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl);
|
||||
|
||||
|
@ -507,6 +527,8 @@ function off() {
|
|||
MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged);
|
||||
MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged);
|
||||
MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged);
|
||||
MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged);
|
||||
MyAvatar.sitStandStateLockEnabledChanged.disconnect(onSitStandStateLockedEnabledChanged);
|
||||
MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl);
|
||||
MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged);
|
||||
MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged);
|
||||
|
@ -521,6 +543,8 @@ function on() {
|
|||
MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged);
|
||||
MyAvatar.dominantHandChanged.connect(onDominantHandChanged);
|
||||
MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged);
|
||||
MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged);
|
||||
MyAvatar.sitStandStateLockEnabledChanged.connect(onSitStandStateLockedEnabledChanged);
|
||||
MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl);
|
||||
MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged);
|
||||
MyAvatar.targetScaleChanged.connect(onTargetScaleChanged);
|
||||
|
|
Loading…
Reference in a new issue