mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 18:13:05 +02:00
Merge pull request #7238 from hyperlogic/tony/hmd-follow-work
MyAvatar: Improved body recentering for room scale
This commit is contained in:
commit
ee3e0fcc38
2 changed files with 109 additions and 32 deletions
|
@ -1097,7 +1097,8 @@ void MyAvatar::prepareForPhysicsSimulation() {
|
||||||
_characterController.setTargetVelocity(getTargetVelocity());
|
_characterController.setTargetVelocity(getTargetVelocity());
|
||||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||||
if (qApp->isHMDMode()) {
|
if (qApp->isHMDMode()) {
|
||||||
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix);
|
bool hasDriveInput = fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
|
||||||
|
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput);
|
||||||
} else {
|
} else {
|
||||||
_follow.deactivate();
|
_follow.deactivate();
|
||||||
}
|
}
|
||||||
|
@ -1339,11 +1340,11 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||||
_prevShouldDrawHead = shouldDrawHead;
|
_prevShouldDrawHead = shouldDrawHead;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.6f;
|
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f;
|
||||||
|
|
||||||
bool MyAvatar::cameraInsideHead() const {
|
bool MyAvatar::cameraInsideHead() const {
|
||||||
const glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
|
const glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
|
||||||
return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale());
|
return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||||
|
@ -1884,58 +1885,119 @@ void MyAvatar::lateUpdatePalms() {
|
||||||
|
|
||||||
static const float FOLLOW_TIME = 0.5f;
|
static const float FOLLOW_TIME = 0.5f;
|
||||||
|
|
||||||
void MyAvatar::FollowHelper::deactivate() {
|
MyAvatar::FollowHelper::FollowHelper() {
|
||||||
_timeRemaining = 0.0f;
|
deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::FollowHelper::activate() {
|
void MyAvatar::FollowHelper::deactivate() {
|
||||||
|
for (int i = 0; i < NumFollowTypes; i++) {
|
||||||
|
deactivate((FollowType)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::FollowHelper::deactivate(FollowType type) {
|
||||||
|
assert(type >= 0 && type < NumFollowTypes);
|
||||||
|
_timeRemaining[(int)type] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::FollowHelper::activate(FollowType type) {
|
||||||
|
assert(type >= 0 && type < NumFollowTypes);
|
||||||
// TODO: Perhaps, the follow time should be proportional to the displacement.
|
// TODO: Perhaps, the follow time should be proportional to the displacement.
|
||||||
_timeRemaining = FOLLOW_TIME;
|
_timeRemaining[(int)type] = FOLLOW_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyAvatar::FollowHelper::isActive(FollowType type) const {
|
||||||
|
assert(type >= 0 && type < NumFollowTypes);
|
||||||
|
return _timeRemaining[(int)type] > 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::isActive() const {
|
bool MyAvatar::FollowHelper::isActive() const {
|
||||||
return _timeRemaining > 0.0f;
|
for (int i = 0; i < NumFollowTypes; i++) {
|
||||||
|
if (isActive((FollowType)i)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
float MyAvatar::FollowHelper::getMaxTimeRemaining() const {
|
||||||
|
float max = 0.0f;
|
||||||
const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 4.0f);
|
for (int i = 0; i < NumFollowTypes; i++) {
|
||||||
|
if (_timeRemaining[i] > max) {
|
||||||
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
max = _timeRemaining[i];
|
||||||
if (glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD) {
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
const float CYLINDER_TOP = 0.1f;
|
void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) {
|
||||||
const float CYLINDER_BOTTOM = -0.5f;
|
for (int i = 0; i < NumFollowTypes; i++) {
|
||||||
const float CYLINDER_RADIUS = 0.15f;
|
_timeRemaining[i] -= dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
||||||
|
return glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
|
|
||||||
|
const float CYLINDER_RADIUS = 0.3f;
|
||||||
|
|
||||||
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
|
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
|
||||||
glm::vec3 radialOffset(offset.x, 0.0f, offset.z);
|
glm::vec3 radialOffset(offset.x, 0.0f, offset.z);
|
||||||
float radialDistance = glm::length(radialOffset);
|
float radialDistance = glm::length(radialOffset);
|
||||||
|
|
||||||
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (radialDistance > CYLINDER_RADIUS);
|
return radialDistance > CYLINDER_RADIUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) {
|
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
|
|
||||||
|
const float CYLINDER_TOP = 0.1f;
|
||||||
|
const float CYLINDER_BOTTOM = -1.5f;
|
||||||
|
|
||||||
|
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
|
||||||
|
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) {
|
||||||
_desiredBodyMatrix = desiredBodyMatrix;
|
_desiredBodyMatrix = desiredBodyMatrix;
|
||||||
if (!isActive() && shouldActivate(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
|
if (!isActive(Rotation) && shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
|
||||||
activate();
|
activate(Rotation);
|
||||||
|
}
|
||||||
|
if (!isActive(Horizontal) && shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {
|
||||||
|
activate(Horizontal);
|
||||||
|
}
|
||||||
|
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||||
|
activate(Vertical);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isActive()) {
|
glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix;
|
||||||
glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix;
|
glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;
|
||||||
myAvatar.getCharacterController()->setFollowParameters(desiredWorldMatrix, _timeRemaining);
|
|
||||||
} else {
|
AnimPose followWorldPose(currentWorldMatrix);
|
||||||
glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;
|
if (isActive(Rotation)) {
|
||||||
myAvatar.getCharacterController()->setFollowParameters(currentWorldMatrix, 0.0f);
|
followWorldPose.rot = glmExtractRotation(desiredWorldMatrix);
|
||||||
}
|
}
|
||||||
|
if (isActive(Horizontal)) {
|
||||||
|
glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix);
|
||||||
|
followWorldPose.trans.x = desiredTranslation.x;
|
||||||
|
followWorldPose.trans.z = desiredTranslation.z;
|
||||||
|
}
|
||||||
|
if (isActive(Vertical)) {
|
||||||
|
glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix);
|
||||||
|
followWorldPose.trans.y = desiredTranslation.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining());
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
|
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
|
||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
float dt = myAvatar.getCharacterController()->getFollowTime();
|
float dt = myAvatar.getCharacterController()->getFollowTime();
|
||||||
_timeRemaining -= dt;
|
decrementTimeRemaining(dt);
|
||||||
|
|
||||||
// apply follow displacement to the body matrix.
|
// apply follow displacement to the body matrix.
|
||||||
glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();
|
glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();
|
||||||
|
|
|
@ -392,14 +392,29 @@ private:
|
||||||
glm::mat4 _sensorToWorldMatrix;
|
glm::mat4 _sensorToWorldMatrix;
|
||||||
|
|
||||||
struct FollowHelper {
|
struct FollowHelper {
|
||||||
|
FollowHelper();
|
||||||
|
|
||||||
|
enum FollowType {
|
||||||
|
Rotation = 0,
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
NumFollowTypes
|
||||||
|
};
|
||||||
glm::mat4 _desiredBodyMatrix;
|
glm::mat4 _desiredBodyMatrix;
|
||||||
float _timeRemaining { 0.0f };
|
float _timeRemaining[NumFollowTypes];
|
||||||
|
|
||||||
void deactivate();
|
void deactivate();
|
||||||
|
void deactivate(FollowType type);
|
||||||
void activate();
|
void activate();
|
||||||
|
void activate(FollowType type);
|
||||||
bool isActive() const;
|
bool isActive() const;
|
||||||
bool shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
|
bool isActive(FollowType followType) const;
|
||||||
void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix);
|
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 shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) 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(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
|
||||||
};
|
};
|
||||||
FollowHelper _follow;
|
FollowHelper _follow;
|
||||||
|
|
Loading…
Reference in a new issue