mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
Use eye-height to match user and avatar scales, follow fixes
Fix postPhysicsUpdate to properly transform follow displacement into sensor frame.
This commit is contained in:
parent
80b660b258
commit
963ddce7bc
7 changed files with 59 additions and 36 deletions
|
@ -2385,7 +2385,7 @@ void Application::paintGL() {
|
|||
if (isHMDMode()) {
|
||||
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||
_myCamera.setPosition(extractTranslation(camMat));
|
||||
_myCamera.setOrientation(glm::quat_cast(camMat));
|
||||
_myCamera.setOrientation(glmExtractRotation(camMat));
|
||||
} else {
|
||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
||||
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
||||
|
@ -2393,7 +2393,7 @@ void Application::paintGL() {
|
|||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
if (isHMDMode()) {
|
||||
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
|
||||
_myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat)));
|
||||
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
||||
myAvatar->getOrientation() * boomOffset);
|
||||
} else {
|
||||
|
@ -2501,6 +2501,10 @@ void Application::paintGL() {
|
|||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||
float IPDScale = hmdInterface->getIPDScale();
|
||||
|
||||
// scale IPD by height ratio, to make the world seem larger or smaller accordingly.
|
||||
float heightRatio = getMyAvatar()->getEyeHeight() / getMyAvatar()->getUserEyeHeight();
|
||||
IPDScale *= heightRatio;
|
||||
|
||||
// FIXME we probably don't need to set the projection matrix every frame,
|
||||
// only when the display plugin changes (or in non-HMD modes when the user
|
||||
// changes the FOV manually, which right now I don't think they can.
|
||||
|
|
|
@ -321,7 +321,7 @@ void MyAvatar::centerBody() {
|
|||
// transform this body into world space
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
auto worldBodyRot = glmExtractRotation(worldBodyMatrix);
|
||||
|
||||
if (_characterController.getState() == CharacterController::State::Ground) {
|
||||
// the avatar's physical aspect thinks it is standing on something
|
||||
|
@ -374,7 +374,7 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
|||
// transform this body into world space
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
auto worldBodyRot = glmExtractRotation(worldBodyMatrix);
|
||||
|
||||
// this will become our new position.
|
||||
setPosition(worldBodyPos);
|
||||
|
@ -640,7 +640,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
}
|
||||
|
||||
_hmdSensorPosition = newHmdSensorPosition;
|
||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
||||
_hmdSensorOrientation = glmExtractRotation(hmdSensorMatrix);
|
||||
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
if (headPose.isValid()) {
|
||||
_headControllerFacing = getFacingDir2D(headPose.rotation);
|
||||
|
@ -664,9 +664,11 @@ void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeV
|
|||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
void MyAvatar::updateSensorToWorldMatrix() {
|
||||
|
||||
// update the sensor mat so that the body position will end up in the desired
|
||||
// position when driven from the head.
|
||||
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
|
||||
float heightRatio = getEyeHeight() / getUserEyeHeight();
|
||||
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(heightRatio), getOrientation(), getPosition());
|
||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||
|
||||
lateUpdatePalms();
|
||||
|
@ -2615,7 +2617,9 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
|||
// Y_180 is necessary because rig is z forward and hmdOrientation is -z forward
|
||||
glm::vec3 headToNeck = headOrientation * Quaternions::Y_180 * (localNeck - localHead);
|
||||
glm::vec3 neckToRoot = headOrientationYawOnly * Quaternions::Y_180 * -localNeck;
|
||||
glm::vec3 bodyPos = headPosition + headToNeck + neckToRoot;
|
||||
|
||||
float invHeightRatio = getUserEyeHeight() / getEyeHeight();
|
||||
glm::vec3 bodyPos = headPosition + invHeightRatio * (headToNeck + neckToRoot);
|
||||
|
||||
return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos);
|
||||
}
|
||||
|
@ -2628,6 +2632,12 @@ void MyAvatar::setUserHeight(float value) {
|
|||
_userHeight.set(value);
|
||||
}
|
||||
|
||||
float MyAvatar::getUserEyeHeight() const {
|
||||
float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||
float userHeight = _userHeight.get();
|
||||
return userHeight - userHeight * ratio;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getPositionForAudio() {
|
||||
switch (_audioListenerMode) {
|
||||
case AudioListenerMode::FROM_HEAD:
|
||||
|
@ -2798,6 +2808,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;
|
||||
|
||||
AnimPose followWorldPose(currentWorldMatrix);
|
||||
|
||||
// remove scale present from sensorToWorldMatrix
|
||||
followWorldPose.scale() = glm::vec3(1.0f);
|
||||
|
||||
if (isActive(Rotation)) {
|
||||
followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix);
|
||||
}
|
||||
|
@ -2822,11 +2836,12 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
|
|||
// apply follow displacement to the body matrix.
|
||||
glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();
|
||||
glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement();
|
||||
glm::quat sensorToWorld = glmExtractRotation(myAvatar.getSensorToWorldMatrix());
|
||||
glm::quat worldToSensor = glm::inverse(sensorToWorld);
|
||||
|
||||
glm::vec3 sensorLinearDisplacement = worldToSensor * worldLinearDisplacement;
|
||||
glm::quat sensorAngularDisplacement = worldToSensor * worldAngularDisplacement * sensorToWorld;
|
||||
glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix();
|
||||
glm::mat4 worldToSensorMatrix = glm::inverse(sensorToWorldMatrix);
|
||||
|
||||
glm::vec3 sensorLinearDisplacement = transformVectorFast(worldToSensorMatrix, worldLinearDisplacement);
|
||||
glm::quat sensorAngularDisplacement = glmExtractRotation(worldToSensorMatrix) * worldAngularDisplacement * glmExtractRotation(sensorToWorldMatrix);
|
||||
|
||||
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
|
||||
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
||||
|
|
|
@ -527,6 +527,7 @@ public:
|
|||
|
||||
float getUserHeight() const;
|
||||
void setUserHeight(float value);
|
||||
float getUserEyeHeight() const;
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
|
|
|
@ -151,7 +151,7 @@ glm::vec3 HMDScriptingInterface::getPosition() const {
|
|||
|
||||
glm::quat HMDScriptingInterface::getOrientation() const {
|
||||
if (qApp->getActiveDisplayPlugin()->isHmd()) {
|
||||
return glm::normalize(glm::quat_cast(getWorldHMDMatrix()));
|
||||
return glmExtractRotation(getWorldHMDMatrix());
|
||||
}
|
||||
return glm::quat();
|
||||
}
|
||||
|
|
|
@ -1550,47 +1550,48 @@ void Avatar::ensureInScene(AvatarSharedPointer self, const render::ScenePointer&
|
|||
}
|
||||
}
|
||||
|
||||
// returns the avatar height, in meters, includes avatar scale factor.
|
||||
float Avatar::getHeight() const {
|
||||
float Avatar::getEyeHeight() const {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
float result = DEFAULT_AVATAR_HEIGHT;
|
||||
float result = DEFAULT_AVATAR_EYE_HEIGHT;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getHeight", Q_RETURN_ARG(float, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime.
|
||||
// AJT: TODO: I don't know what scale is to use here... getDomainLimitedScale?
|
||||
float avatarScale = getTargetScale();
|
||||
float avatarScale = getUniformScale();
|
||||
if (_skeletonModel) {
|
||||
auto& rig = _skeletonModel->getRig();
|
||||
int headTopJoint = rig.indexOfJoint("HeadTop_End");
|
||||
int headJoint = rig.indexOfJoint("Head");
|
||||
int eyeJoint = rig.indexOfJoint("LeftEye") != -1 ? rig.indexOfJoint("LeftEye") : rig.indexOfJoint("RightEye");
|
||||
int toeJoint = rig.indexOfJoint("LeftToeBase") != -1 ? rig.indexOfJoint("LeftToeBase") : rig.indexOfJoint("RightToeBase");
|
||||
if (headTopJoint >= 0 && toeJoint >= 0) {
|
||||
// measure toe to top of head. Note: default poses already include avatar scale factor
|
||||
float height = rig.getAbsoluteDefaultPose(headTopJoint).trans().y - rig.getAbsoluteDefaultPose(toeJoint).trans().y;
|
||||
return height;
|
||||
} else if (eyeJoint >= 0 && toeJoint >= 0) {
|
||||
// measure from eyes to toes + the average eye to top of head distance.
|
||||
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||
if (eyeJoint >= 0 && toeJoint >= 0) {
|
||||
// measure from eyes to toes.
|
||||
float eyeHeight = rig.getAbsoluteDefaultPose(eyeJoint).trans().y - rig.getAbsoluteDefaultPose(toeJoint).trans().y;
|
||||
return eyeHeight + eyeHeight * ratio;
|
||||
} else if (headTopJoint >= 0) {
|
||||
return rig.getAbsoluteDefaultPose(headTopJoint).trans().y;
|
||||
return eyeHeight;
|
||||
} else if (eyeJoint >= 0) {
|
||||
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||
// measure eyes to y = 0 plane.
|
||||
float eyeHeight = rig.getAbsoluteDefaultPose(eyeJoint).trans().y;
|
||||
return eyeHeight + eyeHeight * ratio;
|
||||
return eyeHeight;
|
||||
} else if (headTopJoint >= 0 && toeJoint >= 0) {
|
||||
// measure toe to top of head. Note: default poses already include avatar scale factor
|
||||
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||
float height = rig.getAbsoluteDefaultPose(headTopJoint).trans().y - rig.getAbsoluteDefaultPose(toeJoint).trans().y;
|
||||
return height - height * ratio;
|
||||
} else if (headTopJoint >= 0) {
|
||||
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||
float height = rig.getAbsoluteDefaultPose(headTopJoint).trans().y;
|
||||
return height - height * ratio;
|
||||
} else if (headJoint >= 0) {
|
||||
const float ratio = DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||
const float DEFAULT_AVATAR_NECK_TO_EYE = DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD;
|
||||
const float ratio = DEFAULT_AVATAR_NECK_TO_EYE / DEFAULT_AVATAR_NECK_HEIGHT;
|
||||
float neckHeight = rig.getAbsoluteDefaultPose(headJoint).trans().y;
|
||||
return neckHeight + neckHeight * ratio;
|
||||
} else {
|
||||
return avatarScale * DEFAULT_AVATAR_HEIGHT;
|
||||
return avatarScale * DEFAULT_AVATAR_EYE_HEIGHT;
|
||||
}
|
||||
} else {
|
||||
return avatarScale * DEFAULT_AVATAR_HEIGHT;
|
||||
return avatarScale * DEFAULT_AVATAR_EYE_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,11 +252,11 @@ public:
|
|||
void updateFadingStatus(render::ScenePointer scene);
|
||||
|
||||
/**jsdoc
|
||||
* Provides read only access to the current height of the avatar in world space.
|
||||
* @function Avatar.getHeight
|
||||
* @returns {number} height of avatar in meters
|
||||
* Provides read only access to the current eye height of the avatar.
|
||||
* @function Avatar.getEyeHeight
|
||||
* @returns {number} eye height of avatar in meters
|
||||
*/
|
||||
Q_INVOKABLE float getHeight() const;
|
||||
Q_INVOKABLE float getEyeHeight() const;
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
const float DEFAULT_AVATAR_HEIGHT = 1.755f; // meters
|
||||
const float DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD = 0.11f; // meters
|
||||
const float DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD = 0.185f; // meters
|
||||
const float DEFAULT_AVATAR_NECK_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD;
|
||||
const float DEFAULT_AVATAR_EYE_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD;
|
||||
|
||||
// Used when avatar is missing joints... (avatar space)
|
||||
static const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
|
||||
|
|
Loading…
Reference in a new issue