mirror of
https://github.com/overte-org/overte.git
synced 2025-07-29 01:00:35 +02:00
added the first pass at mode computation
This commit is contained in:
parent
7b49ae4950
commit
61a935dbb5
2 changed files with 271 additions and 261 deletions
|
@ -82,7 +82,8 @@ const int SCRIPTED_MOTOR_AVATAR_FRAME = 1;
|
||||||
const int SCRIPTED_MOTOR_WORLD_FRAME = 2;
|
const int SCRIPTED_MOTOR_WORLD_FRAME = 2;
|
||||||
const int SCRIPTED_MOTOR_SIMPLE_MODE = 0;
|
const int SCRIPTED_MOTOR_SIMPLE_MODE = 0;
|
||||||
const int SCRIPTED_MOTOR_DYNAMIC_MODE = 1;
|
const int SCRIPTED_MOTOR_DYNAMIC_MODE = 1;
|
||||||
const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/Body_Hits_Impact.wav";
|
const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL =
|
||||||
|
"https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/Body_Hits_Impact.wav";
|
||||||
|
|
||||||
const float MyAvatar::ZOOM_MIN = 0.5f;
|
const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||||
const float MyAvatar::ZOOM_MAX = 25.0f;
|
const float MyAvatar::ZOOM_MAX = 25.0f;
|
||||||
|
@ -90,33 +91,15 @@ const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||||
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
||||||
|
|
||||||
MyAvatar::MyAvatar(QThread* thread) :
|
MyAvatar::MyAvatar(QThread* thread) :
|
||||||
Avatar(thread),
|
Avatar(thread), _yawSpeed(YAW_SPEED_DEFAULT), _pitchSpeed(PITCH_SPEED_DEFAULT),
|
||||||
_yawSpeed(YAW_SPEED_DEFAULT),
|
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
||||||
_pitchSpeed(PITCH_SPEED_DEFAULT),
|
_scriptedMotorMode(SCRIPTED_MOTOR_SIMPLE_MODE), _motionBehaviors(AVATAR_MOTION_DEFAULTS), _characterController(this),
|
||||||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
_eyeContactTarget(LEFT_EYE), _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
|
||||||
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
|
||||||
_scriptedMotorMode(SCRIPTED_MOTOR_SIMPLE_MODE),
|
|
||||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
|
||||||
_characterController(this),
|
|
||||||
_eyeContactTarget(LEFT_EYE),
|
|
||||||
_realWorldFieldOfView("realWorldFieldOfView",
|
|
||||||
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
|
|
||||||
_useAdvancedMovementControls("advancedMovementForHandControllersIsChecked", false),
|
_useAdvancedMovementControls("advancedMovementForHandControllersIsChecked", false),
|
||||||
_smoothOrientationTimer(std::numeric_limits<float>::max()),
|
_smoothOrientationTimer(std::numeric_limits<float>::max()), _smoothOrientationInitial(), _smoothOrientationTarget(),
|
||||||
_smoothOrientationInitial(),
|
_hmdSensorMatrix(), _hmdSensorOrientation(), _hmdSensorPosition(), _bodySensorMatrix(), _goToPending(false),
|
||||||
_smoothOrientationTarget(),
|
_goToPosition(), _goToOrientation(), _prevShouldDrawHead(true), _audioListenerMode(FROM_HEAD),
|
||||||
_hmdSensorMatrix(),
|
_hmdAtRestDetector(glm::vec3(0), glm::quat()) {
|
||||||
_hmdSensorOrientation(),
|
|
||||||
_hmdSensorPosition(),
|
|
||||||
_bodySensorMatrix(),
|
|
||||||
_goToPending(false),
|
|
||||||
_goToPosition(),
|
|
||||||
_goToOrientation(),
|
|
||||||
_prevShouldDrawHead(true),
|
|
||||||
_audioListenerMode(FROM_HEAD),
|
|
||||||
_hmdAtRestDetector(glm::vec3(0), glm::quat())
|
|
||||||
{
|
|
||||||
|
|
||||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||||
_headData = new MyHead(this);
|
_headData = new MyHead(this);
|
||||||
|
|
||||||
|
@ -148,8 +131,8 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
using SlotType = void (MyAvatar::*)(const glm::vec3&, bool, const glm::quat&, bool);
|
using SlotType = void (MyAvatar::*)(const glm::vec3&, bool, const glm::quat&, bool);
|
||||||
|
|
||||||
// connect to AddressManager signal for location jumps
|
// connect to AddressManager signal for location jumps
|
||||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired, this,
|
||||||
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||||
|
|
||||||
// handle scale constraints imposed on us by the domain-server
|
// handle scale constraints imposed on us by the domain-server
|
||||||
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||||
|
@ -211,7 +194,6 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
|
|
||||||
if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&
|
if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&
|
||||||
(dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {
|
(dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {
|
||||||
|
|
||||||
setSkeletonModelURL(dummyAvatar.getSkeletonModelURL());
|
setSkeletonModelURL(dummyAvatar.getSkeletonModelURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +240,8 @@ void MyAvatar::setDominantHand(const QString& hand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) {
|
void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) {
|
||||||
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership,
|
||||||
|
QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
||||||
engine->globalObject().setProperty("MyAvatar", value);
|
engine->globalObject().setProperty("MyAvatar", value);
|
||||||
|
|
||||||
QScriptValue driveKeys = engine->newObject();
|
QScriptValue driveKeys = engine->newObject();
|
||||||
|
@ -371,7 +354,6 @@ void MyAvatar::clearIKJointLimitHistory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
||||||
|
|
||||||
assert(QThread::currentThread() == thread());
|
assert(QThread::currentThread() == thread());
|
||||||
|
|
||||||
// Reset dynamic state.
|
// Reset dynamic state.
|
||||||
|
@ -412,7 +394,6 @@ 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 = 4.0f; // very slow average
|
||||||
float tau = deltaTime / HMD_FACING_TIMESCALE;
|
float tau = deltaTime / HMD_FACING_TIMESCALE;
|
||||||
|
@ -426,8 +407,11 @@ void MyAvatar::update(float deltaTime) {
|
||||||
#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());
|
||||||
glm::vec3 worldFacingAverage = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
|
glm::vec3 worldFacingAverage =
|
||||||
glm::vec3 worldFacing = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacing.x, 0.0f, _headControllerFacing.y));
|
transformVectorFast(getSensorToWorldMatrix(),
|
||||||
|
glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
|
||||||
|
glm::vec3 worldFacing =
|
||||||
|
transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacing.x, 0.0f, _headControllerFacing.y));
|
||||||
DebugDraw::getInstance().drawRay(worldHeadPos, worldHeadPos + worldFacing, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
DebugDraw::getInstance().drawRay(worldHeadPos, worldHeadPos + worldFacing, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||||
DebugDraw::getInstance().drawRay(worldHeadPos, worldHeadPos + worldFacingAverage, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
DebugDraw::getInstance().drawRay(worldHeadPos, worldHeadPos + worldFacingAverage, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||||
#endif
|
#endif
|
||||||
|
@ -464,7 +448,8 @@ void MyAvatar::update(float deltaTime) {
|
||||||
setAudioLoudness(audio->getLastInputLoudness());
|
setAudioLoudness(audio->getLastInputLoudness());
|
||||||
setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
||||||
|
|
||||||
glm::vec3 halfBoundingBoxDimensions(_characterController.getCapsuleRadius(), _characterController.getCapsuleHalfHeight(), _characterController.getCapsuleRadius());
|
glm::vec3 halfBoundingBoxDimensions(_characterController.getCapsuleRadius(), _characterController.getCapsuleHalfHeight(),
|
||||||
|
_characterController.getCapsuleRadius());
|
||||||
// This might not be right! Isn't the capsule local offset in avatar space? -HRS 5/26/17
|
// This might not be right! Isn't the capsule local offset in avatar space? -HRS 5/26/17
|
||||||
halfBoundingBoxDimensions += _characterController.getCapsuleLocalOffset();
|
halfBoundingBoxDimensions += _characterController.getCapsuleLocalOffset();
|
||||||
QMetaObject::invokeMethod(audio.data(), "setAvatarBoundingBoxParameters",
|
QMetaObject::invokeMethod(audio.data(), "setAvatarBoundingBoxParameters",
|
||||||
|
@ -491,13 +476,10 @@ void MyAvatar::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateEyeContactTarget(float deltaTime) {
|
void MyAvatar::updateEyeContactTarget(float deltaTime) {
|
||||||
|
|
||||||
_eyeContactTargetTimer -= deltaTime;
|
_eyeContactTargetTimer -= deltaTime;
|
||||||
if (_eyeContactTargetTimer < 0.0f) {
|
if (_eyeContactTargetTimer < 0.0f) {
|
||||||
|
|
||||||
const float CHANCE_OF_CHANGING_TARGET = 0.01f;
|
const float CHANCE_OF_CHANGING_TARGET = 0.01f;
|
||||||
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
|
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
|
||||||
|
|
||||||
float const FIFTY_FIFTY_CHANCE = 0.5f;
|
float const FIFTY_FIFTY_CHANCE = 0.5f;
|
||||||
float const EYE_TO_MOUTH_CHANCE = 0.25f;
|
float const EYE_TO_MOUTH_CHANCE = 0.25f;
|
||||||
switch (_eyeContactTarget) {
|
switch (_eyeContactTarget) {
|
||||||
|
@ -550,9 +532,7 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
|
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
|
||||||
if (isChildOfHead) {
|
if (isChildOfHead) {
|
||||||
updateChildCauterization(object);
|
updateChildCauterization(object);
|
||||||
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
object->forEachDescendant([&](SpatiallyNestablePointer descendant) { updateChildCauterization(descendant); });
|
||||||
updateChildCauterization(descendant);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_cauterizationNeedsUpdate = false;
|
_cauterizationNeedsUpdate = false;
|
||||||
|
@ -672,7 +652,8 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
EntityItemProperties descendantProperties;
|
EntityItemProperties descendantProperties;
|
||||||
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
||||||
descendantProperties.setLastEdited(now);
|
descendantProperties.setLastEdited(now);
|
||||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entityDescendant->getID(), descendantProperties);
|
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree,
|
||||||
|
entityDescendant->getID(), descendantProperties);
|
||||||
entityDescendant->setLastBroadcast(now); // for debug/physics status icons
|
entityDescendant->setLastBroadcast(now); // for debug/physics status icons
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -703,8 +684,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||||
_hmdSensorMatrix = hmdSensorMatrix;
|
_hmdSensorMatrix = hmdSensorMatrix;
|
||||||
auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
||||||
|
|
||||||
if (newHmdSensorPosition != getHMDSensorPosition() &&
|
if (newHmdSensorPosition != getHMDSensorPosition() && glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
|
||||||
glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
|
|
||||||
qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition;
|
qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition;
|
||||||
// Ignore unreasonable HMD sensor data
|
// Ignore unreasonable HMD sensor data
|
||||||
return;
|
return;
|
||||||
|
@ -736,11 +716,11 @@ void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeV
|
||||||
// update sensor to world matrix from current body position and hmd sensor.
|
// update sensor to world matrix from current body position and hmd sensor.
|
||||||
// This is so the correct camera can be used for rendering.
|
// This is so the correct camera can be used for rendering.
|
||||||
void MyAvatar::updateSensorToWorldMatrix() {
|
void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
|
|
||||||
// update the sensor mat so that the body position will end up in the desired
|
// update the sensor mat so that the body position will end up in the desired
|
||||||
// position when driven from the head.
|
// position when driven from the head.
|
||||||
float sensorToWorldScale = getEyeHeight() / getUserEyeHeight();
|
float sensorToWorldScale = getEyeHeight() / getUserEyeHeight();
|
||||||
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
glm::mat4 desiredMat =
|
||||||
|
createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
||||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||||
|
|
||||||
bool hasSensorToWorldScaleChanged = false;
|
bool hasSensorToWorldScaleChanged = false;
|
||||||
|
@ -762,7 +742,6 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
if (hasSensorToWorldScaleChanged) {
|
if (hasSensorToWorldScaleChanged) {
|
||||||
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update avatar head rotation with sensor data
|
// Update avatar head rotation with sensor data
|
||||||
|
@ -787,8 +766,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||||
const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
|
const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
|
||||||
const float TRACKER_MIN_YAW_TURN = 15.0f;
|
const float TRACKER_MIN_YAW_TURN = 15.0f;
|
||||||
const float TRACKER_MAX_YAW_TURN = 50.0f;
|
const float TRACKER_MAX_YAW_TURN = 50.0f;
|
||||||
if ( (fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) &&
|
if ((fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) && (fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN)) {
|
||||||
(fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN) ) {
|
|
||||||
if (estimatedRotation.y > 0.0f) {
|
if (estimatedRotation.y > 0.0f) {
|
||||||
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||||
} else {
|
} else {
|
||||||
|
@ -803,7 +781,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||||
// their head only 30 degrees or so, this may correspond to a 90 degree field of view.
|
// their head only 30 degrees or so, this may correspond to a 90 degree field of view.
|
||||||
// Note that roll is magnified by a constant because it is not related to field of view.
|
// Note that roll is magnified by a constant because it is not related to field of view.
|
||||||
|
|
||||||
|
|
||||||
Head* head = getHead();
|
Head* head = getHead();
|
||||||
if (inHmd || playing) {
|
if (inHmd || playing) {
|
||||||
head->setDeltaPitch(estimatedRotation.x);
|
head->setDeltaPitch(estimatedRotation.x);
|
||||||
|
@ -947,8 +924,8 @@ void MyAvatar::render(RenderArgs* renderArgs) {
|
||||||
|
|
||||||
void MyAvatar::overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
void MyAvatar::overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "overrideAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps),
|
QMetaObject::invokeMethod(this, "overrideAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps), Q_ARG(bool, loop),
|
||||||
Q_ARG(bool, loop), Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_skeletonModel->getRig().overrideAnimation(url, fps, loop, firstFrame, lastFrame);
|
_skeletonModel->getRig().overrideAnimation(url, fps, loop, firstFrame, lastFrame);
|
||||||
|
@ -971,8 +948,12 @@ QStringList MyAvatar::getAnimationRoles() {
|
||||||
return _skeletonModel->getRig().getAnimationRoles();
|
return _skeletonModel->getRig().getAnimationRoles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop,
|
void MyAvatar::overrideRoleAnimation(const QString& role,
|
||||||
float firstFrame, float lastFrame) {
|
const QString& url,
|
||||||
|
float fps,
|
||||||
|
bool loop,
|
||||||
|
float firstFrame,
|
||||||
|
float lastFrame) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "overrideRoleAnimation", Q_ARG(const QString&, role), Q_ARG(const QString&, url),
|
QMetaObject::invokeMethod(this, "overrideRoleAnimation", Q_ARG(const QString&, role), Q_ARG(const QString&, url),
|
||||||
Q_ARG(float, fps), Q_ARG(bool, loop), Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
Q_ARG(float, fps), Q_ARG(bool, loop), Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
||||||
|
@ -993,10 +974,9 @@ void MyAvatar::saveAvatarUrl() {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.beginGroup("Avatar");
|
settings.beginGroup("Avatar");
|
||||||
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
|
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
|
||||||
settings.setValue("fullAvatarURL",
|
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl()
|
||||||
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
|
? ""
|
||||||
"" :
|
: _fullAvatarURLFromPreferences.toString());
|
||||||
_fullAvatarURLFromPreferences.toString());
|
|
||||||
}
|
}
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
@ -1017,10 +997,9 @@ void MyAvatar::saveData() {
|
||||||
// (so the overrideURL is not valid), or it was overridden _and_ we specified
|
// (so the overrideURL is not valid), or it was overridden _and_ we specified
|
||||||
// --replaceAvatarURL (so _saveAvatarOverrideUrl is true)
|
// --replaceAvatarURL (so _saveAvatarOverrideUrl is true)
|
||||||
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
|
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
|
||||||
settings.setValue("fullAvatarURL",
|
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl()
|
||||||
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
|
? ""
|
||||||
"" :
|
: _fullAvatarURLFromPreferences.toString());
|
||||||
_fullAvatarURLFromPreferences.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
|
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
|
||||||
|
@ -1332,16 +1311,15 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
||||||
bool isCurrentTarget = avatar->getIsLookAtTarget();
|
bool isCurrentTarget = avatar->getIsLookAtTarget();
|
||||||
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
||||||
avatar->setIsLookAtTarget(false);
|
avatar->setIsLookAtTarget(false);
|
||||||
if (!avatar->isMyAvatar() && avatar->isInitialized() &&
|
if (!avatar->isMyAvatar() && avatar->isInitialized() && (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getModelScale())) {
|
||||||
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getModelScale())) {
|
|
||||||
float radius = glm::length(avatar->getHead()->getEyePosition() - avatar->getHead()->getRightEyePosition());
|
float radius = glm::length(avatar->getHead()->getEyePosition() - avatar->getHead()->getRightEyePosition());
|
||||||
float angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
|
float angleTo =
|
||||||
|
coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
|
||||||
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
|
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
|
||||||
_lookAtTargetAvatar = avatarPointer;
|
_lookAtTargetAvatar = avatarPointer;
|
||||||
_targetAvatarPosition = avatarPointer->getWorldPosition();
|
_targetAvatarPosition = avatarPointer->getWorldPosition();
|
||||||
}
|
}
|
||||||
if (_lookAtSnappingEnabled && avatar->getLookAtSnappingEnabled() && isLookingAtMe(avatar)) {
|
if (_lookAtSnappingEnabled && avatar->getLookAtSnappingEnabled() && isLookingAtMe(avatar)) {
|
||||||
|
|
||||||
// Alter their gaze to look directly at my camera; this looks more natural than looking at my avatar's face.
|
// Alter their gaze to look directly at my camera; this looks more natural than looking at my avatar's face.
|
||||||
glm::vec3 lookAtPosition = avatar->getHead()->getLookAtPosition(); // A position, in world space, on my avatar.
|
glm::vec3 lookAtPosition = avatar->getHead()->getLookAtPosition(); // A position, in world space, on my avatar.
|
||||||
|
|
||||||
|
@ -1498,9 +1476,7 @@ void MyAvatar::clearJointData(const QString& name) {
|
||||||
QMetaObject::invokeMethod(this, "clearJointData", Q_ARG(QString, name));
|
QMetaObject::invokeMethod(this, "clearJointData", Q_ARG(QString, name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
writeLockWithNamedJointIndex(name, [&](int index) {
|
writeLockWithNamedJointIndex(name, [&](int index) { _skeletonModel->getRig().clearJointAnimationPriority(index); });
|
||||||
_skeletonModel->getRig().clearJointAnimationPriority(index);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::clearJointsData() {
|
void MyAvatar::clearJointsData() {
|
||||||
|
@ -1523,9 +1499,9 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
_cauterizationNeedsUpdate = true;
|
_cauterizationNeedsUpdate = true;
|
||||||
|
|
||||||
std::shared_ptr<QMetaObject::Connection> skeletonConnection = std::make_shared<QMetaObject::Connection>();
|
std::shared_ptr<QMetaObject::Connection> skeletonConnection = std::make_shared<QMetaObject::Connection>();
|
||||||
*skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() {
|
*skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded,
|
||||||
|
[this, skeletonModelChangeCount, skeletonConnection]() {
|
||||||
if (skeletonModelChangeCount == _skeletonModelChangeCount) {
|
if (skeletonModelChangeCount == _skeletonModelChangeCount) {
|
||||||
|
|
||||||
if (_fullAvatarModelName.isEmpty()) {
|
if (_fullAvatarModelName.isEmpty()) {
|
||||||
// Store the FST file name into preferences
|
// Store the FST file name into preferences
|
||||||
const auto& mapping = _skeletonModel->getGeometry()->getMapping();
|
const auto& mapping = _skeletonModel->getGeometry()->getMapping();
|
||||||
|
@ -1536,7 +1512,8 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
|
|
||||||
initHeadBones();
|
initHeadBones();
|
||||||
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
|
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
|
||||||
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
|
_fstAnimGraphOverrideUrl =
|
||||||
|
_skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
|
||||||
initAnimGraph();
|
initAnimGraph();
|
||||||
}
|
}
|
||||||
QObject::disconnect(*skeletonConnection);
|
QObject::disconnect(*skeletonConnection);
|
||||||
|
@ -1577,7 +1554,6 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
|
||||||
return avatarEntitiesData;
|
return avatarEntitiesData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MyAvatar::resetFullAvatarURL() {
|
void MyAvatar::resetFullAvatarURL() {
|
||||||
auto lastAvatarURL = getFullAvatarURLFromPreferences();
|
auto lastAvatarURL = getFullAvatarURLFromPreferences();
|
||||||
auto lastAvatarName = getFullAvatarModelName();
|
auto lastAvatarName = getFullAvatarModelName();
|
||||||
|
@ -1586,11 +1562,8 @@ void MyAvatar::resetFullAvatarURL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL",
|
BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL", Q_ARG(const QUrl&, fullAvatarURL), Q_ARG(const QString&, modelName));
|
||||||
Q_ARG(const QUrl&, fullAvatarURL),
|
|
||||||
Q_ARG(const QString&, modelName));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1610,8 +1583,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
||||||
|
|
||||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
|
BLOCKING_INVOKE_METHOD(this, "setAttachmentData", Q_ARG(const QVector<AttachmentData>, attachmentData));
|
||||||
Q_ARG(const QVector<AttachmentData>, attachmentData));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Avatar::setAttachmentData(attachmentData);
|
Avatar::setAttachmentData(attachmentData);
|
||||||
|
@ -1716,7 +1688,8 @@ void MyAvatar::updateMotors() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isPushing || _isBraking || !_isBeingPushed) {
|
if (_isPushing || _isBraking || !_isBeingPushed) {
|
||||||
_characterController.addMotor(_actionMotorVelocity, motorRotation, horizontalMotorTimescale, verticalMotorTimescale);
|
_characterController.addMotor(_actionMotorVelocity, motorRotation, horizontalMotorTimescale,
|
||||||
|
verticalMotorTimescale);
|
||||||
} else {
|
} else {
|
||||||
// _isBeingPushed must be true --> disable action motor by giving it a long timescale,
|
// _isBeingPushed must be true --> disable action motor by giving it a long timescale,
|
||||||
// otherwise it's attempt to "stand in in place" could defeat scripted motor/thrusts
|
// otherwise it's attempt to "stand in in place" could defeat scripted motor/thrusts
|
||||||
|
@ -1736,7 +1709,8 @@ void MyAvatar::updateMotors() {
|
||||||
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, _scriptedMotorTimescale);
|
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, _scriptedMotorTimescale);
|
||||||
} else {
|
} else {
|
||||||
// dynamic mode
|
// dynamic mode
|
||||||
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, horizontalMotorTimescale, verticalMotorTimescale);
|
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, horizontalMotorTimescale,
|
||||||
|
verticalMotorTimescale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1841,8 +1815,7 @@ void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) {
|
||||||
void MyAvatar::setScriptedMotorTimescale(float timescale) {
|
void MyAvatar::setScriptedMotorTimescale(float timescale) {
|
||||||
// we clamp the timescale on the large side (instead of just the low side) to prevent
|
// we clamp the timescale on the large side (instead of just the low side) to prevent
|
||||||
// obnoxiously large values from introducing NaN into avatar's velocity
|
// obnoxiously large values from introducing NaN into avatar's velocity
|
||||||
_scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
|
_scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
|
||||||
DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setScriptedMotorFrame(QString frame) {
|
void MyAvatar::setScriptedMotorFrame(QString frame) {
|
||||||
|
@ -1883,10 +1856,14 @@ SharedSoundPointer MyAvatar::getCollisionSound() {
|
||||||
return _collisionSound;
|
return _collisionSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
void MyAvatar::attach(const QString& modelURL,
|
||||||
const glm::vec3& translation, const glm::quat& rotation,
|
const QString& jointName,
|
||||||
float scale, bool isSoft,
|
const glm::vec3& translation,
|
||||||
bool allowDuplicates, bool useSaved) {
|
const glm::quat& rotation,
|
||||||
|
float scale,
|
||||||
|
bool isSoft,
|
||||||
|
bool allowDuplicates,
|
||||||
|
bool useSaved) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved);
|
Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved);
|
||||||
return;
|
return;
|
||||||
|
@ -1894,10 +1871,8 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
||||||
if (useSaved) {
|
if (useSaved) {
|
||||||
AttachmentData attachment = loadAttachmentData(modelURL, jointName);
|
AttachmentData attachment = loadAttachmentData(modelURL, jointName);
|
||||||
if (attachment.isValid()) {
|
if (attachment.isValid()) {
|
||||||
Avatar::attach(modelURL, attachment.jointName,
|
Avatar::attach(modelURL, attachment.jointName, attachment.translation, attachment.rotation, attachment.scale,
|
||||||
attachment.translation, attachment.rotation,
|
attachment.isSoft, allowDuplicates, useSaved);
|
||||||
attachment.scale, attachment.isSoft,
|
|
||||||
allowDuplicates, useSaved);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1950,7 +1925,6 @@ QUrl MyAvatar::getAnimGraphUrl() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAnimGraphUrl(const QUrl& url) {
|
void MyAvatar::setAnimGraphUrl(const QUrl& url) {
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setAnimGraphUrl", Q_ARG(QUrl, url));
|
QMetaObject::invokeMethod(this, "setAnimGraphUrl", Q_ARG(QUrl, url));
|
||||||
return;
|
return;
|
||||||
|
@ -1995,10 +1969,8 @@ void MyAvatar::animGraphLoaded() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||||
|
|
||||||
Avatar::postUpdate(deltaTime, scene);
|
Avatar::postUpdate(deltaTime, scene);
|
||||||
if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
|
if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
|
||||||
|
|
||||||
auto animSkeleton = _skeletonModel->getRig().getAnimSkeleton();
|
auto animSkeleton = _skeletonModel->getRig().getAnimSkeleton();
|
||||||
|
|
||||||
// the rig is in the skeletonModel frame
|
// the rig is in the skeletonModel frame
|
||||||
|
@ -2006,7 +1978,8 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||||
|
|
||||||
if (_enableDebugDrawDefaultPose && animSkeleton) {
|
if (_enableDebugDrawDefaultPose && animSkeleton) {
|
||||||
glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f);
|
glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f);
|
||||||
AnimDebugDraw::getInstance().addAbsolutePoses("myAvatarDefaultPoses", animSkeleton, _skeletonModel->getRig().getAbsoluteDefaultPoses(), xform, gray);
|
AnimDebugDraw::getInstance().addAbsolutePoses("myAvatarDefaultPoses", animSkeleton,
|
||||||
|
_skeletonModel->getRig().getAbsoluteDefaultPoses(), xform, gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_enableDebugDrawAnimPose && animSkeleton) {
|
if (_enableDebugDrawAnimPose && animSkeleton) {
|
||||||
|
@ -2027,13 +2000,15 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||||
auto rightHandPose = getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND);
|
auto rightHandPose = getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND);
|
||||||
|
|
||||||
if (leftHandPose.isValid()) {
|
if (leftHandPose.isValid()) {
|
||||||
DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1));
|
DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(),
|
||||||
|
glm::vec4(1));
|
||||||
} else {
|
} else {
|
||||||
DebugDraw::getInstance().removeMarker("leftHandController");
|
DebugDraw::getInstance().removeMarker("leftHandController");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightHandPose.isValid()) {
|
if (rightHandPose.isValid()) {
|
||||||
DebugDraw::getInstance().addMarker("rightHandController", rightHandPose.getRotation(), rightHandPose.getTranslation(), glm::vec4(1));
|
DebugDraw::getInstance().addMarker("rightHandController", rightHandPose.getRotation(),
|
||||||
|
rightHandPose.getTranslation(), glm::vec4(1));
|
||||||
} else {
|
} else {
|
||||||
DebugDraw::getInstance().removeMarker("rightHandController");
|
DebugDraw::getInstance().removeMarker("rightHandController");
|
||||||
}
|
}
|
||||||
|
@ -2050,14 +2025,9 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||||
AnimPose rigToWorldPose(glm::vec3(1.0f), getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
|
AnimPose rigToWorldPose(glm::vec3(1.0f), getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
|
||||||
const int NUM_DEBUG_COLORS = 8;
|
const int NUM_DEBUG_COLORS = 8;
|
||||||
const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = {
|
const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = {
|
||||||
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f),
|
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), glm::vec4(1.0f, 0.0f, 0.0f, 1.0f), glm::vec4(0.0f, 1.0f, 0.0f, 1.0f),
|
||||||
glm::vec4(1.0f, 0.0f, 0.0f, 1.0f),
|
glm::vec4(0.25f, 0.25f, 1.0f, 1.0f), glm::vec4(1.0f, 1.0f, 0.0f, 1.0f), glm::vec4(0.25f, 1.0f, 1.0f, 1.0f),
|
||||||
glm::vec4(0.0f, 1.0f, 0.0f, 1.0f),
|
glm::vec4(1.0f, 0.25f, 1.0f, 1.0f), glm::vec4(1.0f, 0.65f, 0.0f, 1.0f) // Orange you glad I added this color?
|
||||||
glm::vec4(0.25f, 0.25f, 1.0f, 1.0f),
|
|
||||||
glm::vec4(1.0f, 1.0f, 0.0f, 1.0f),
|
|
||||||
glm::vec4(0.25f, 1.0f, 1.0f, 1.0f),
|
|
||||||
glm::vec4(1.0f, 0.25f, 1.0f, 1.0f),
|
|
||||||
glm::vec4(1.0f, 0.65f, 0.0f, 1.0f) // Orange you glad I added this color?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_skeletonModel && _skeletonModel->isLoaded()) {
|
if (_skeletonModel && _skeletonModel->isLoaded()) {
|
||||||
|
@ -2079,7 +2049,6 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
|
void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
|
||||||
|
|
||||||
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
|
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
|
||||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||||
|
@ -2144,7 +2113,6 @@ void MyAvatar::setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement)
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateOrientation(float deltaTime) {
|
void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
||||||
// Smoothly rotate body with arrow keys
|
// Smoothly rotate body with arrow keys
|
||||||
float targetSpeed = getDriveKey(YAW) * _yawSpeed;
|
float targetSpeed = getDriveKey(YAW) * _yawSpeed;
|
||||||
if (targetSpeed != 0.0f) {
|
if (targetSpeed != 0.0f) {
|
||||||
|
@ -2171,7 +2139,6 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
||||||
float totalBodyYaw = _bodyYawDelta * deltaTime;
|
float totalBodyYaw = _bodyYawDelta * deltaTime;
|
||||||
|
|
||||||
|
|
||||||
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
|
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
|
||||||
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
|
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
|
||||||
// snap turn every half second.
|
// snap turn every half second.
|
||||||
|
@ -2182,8 +2149,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use head/HMD roll to turn while flying, but not when standing still.
|
// Use head/HMD roll to turn while flying, but not when standing still.
|
||||||
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) {
|
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover &&
|
||||||
|
_hmdRollControlEnabled && hasDriveInput()) {
|
||||||
// Turn with head roll.
|
// Turn with head roll.
|
||||||
const float MIN_CONTROL_SPEED = 2.0f * getSensorToWorldScale(); // meters / sec
|
const float MIN_CONTROL_SPEED = 2.0f * getSensorToWorldScale(); // meters / sec
|
||||||
const glm::vec3 characterForward = getWorldOrientation() * Vectors::UNIT_NEG_Z;
|
const glm::vec3 characterForward = getWorldOrientation() * Vectors::UNIT_NEG_Z;
|
||||||
|
@ -2191,7 +2158,6 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
||||||
// only enable roll-turns if we are moving forward or backward at greater then MIN_CONTROL_SPEED
|
// only enable roll-turns if we are moving forward or backward at greater then MIN_CONTROL_SPEED
|
||||||
if (fabsf(forwardSpeed) >= MIN_CONTROL_SPEED) {
|
if (fabsf(forwardSpeed) >= MIN_CONTROL_SPEED) {
|
||||||
|
|
||||||
float direction = forwardSpeed > 0.0f ? 1.0f : -1.0f;
|
float direction = forwardSpeed > 0.0f ? 1.0f : -1.0f;
|
||||||
float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT)));
|
float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT)));
|
||||||
float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f;
|
float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f;
|
||||||
|
@ -2245,8 +2211,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
||||||
void MyAvatar::updateActionMotor(float deltaTime) {
|
void MyAvatar::updateActionMotor(float deltaTime) {
|
||||||
bool thrustIsPushing = (glm::length2(_thrust) > EPSILON);
|
bool thrustIsPushing = (glm::length2(_thrust) > EPSILON);
|
||||||
bool scriptedMotorIsPushing = (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)
|
bool scriptedMotorIsPushing =
|
||||||
&& _scriptedMotorTimescale < MAX_CHARACTER_MOTOR_TIMESCALE;
|
(_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) && _scriptedMotorTimescale < MAX_CHARACTER_MOTOR_TIMESCALE;
|
||||||
_isBeingPushed = thrustIsPushing || scriptedMotorIsPushing;
|
_isBeingPushed = thrustIsPushing || scriptedMotorIsPushing;
|
||||||
if (_isPushing || _isBeingPushed) {
|
if (_isPushing || _isBeingPushed) {
|
||||||
// we don't want the motor to brake if a script is pushing the avatar around
|
// we don't want the motor to brake if a script is pushing the avatar around
|
||||||
|
@ -2358,8 +2324,13 @@ void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTim
|
||||||
// COLLISION SOUND API in Audio has been removed
|
// COLLISION SOUND API in Audio has been removed
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float heightA,
|
bool findAvatarAvatarPenetration(const glm::vec3 positionA,
|
||||||
const glm::vec3 positionB, float radiusB, float heightB, glm::vec3& penetration) {
|
float radiusA,
|
||||||
|
float heightA,
|
||||||
|
const glm::vec3 positionB,
|
||||||
|
float radiusB,
|
||||||
|
float heightB,
|
||||||
|
glm::vec3& penetration) {
|
||||||
glm::vec3 positionBA = positionB - positionA;
|
glm::vec3 positionBA = positionB - positionA;
|
||||||
float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z);
|
float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z);
|
||||||
if (xzDistance < (radiusA + radiusB)) {
|
if (xzDistance < (radiusA + radiusB)) {
|
||||||
|
@ -2531,9 +2502,9 @@ void MyAvatar::goToLocation(const QVariant& propertiesVar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||||
bool hasOrientation, const glm::quat& newOrientation,
|
bool hasOrientation,
|
||||||
|
const glm::quat& newOrientation,
|
||||||
bool shouldFaceLocation) {
|
bool shouldFaceLocation) {
|
||||||
|
|
||||||
// Most cases of going to a place or user go through this now. Some possible improvements to think about in the future:
|
// Most cases of going to a place or user go through this now. Some possible improvements to think about in the future:
|
||||||
// - It would be nice if this used the same teleport steps and smoothing as in the teleport.js script, as long as it
|
// - It would be nice if this used the same teleport steps and smoothing as in the teleport.js script, as long as it
|
||||||
// still worked if the target is in the air.
|
// still worked if the target is in the air.
|
||||||
|
@ -2547,15 +2518,15 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||||
// compute the position (e.g., so that if I'm on stage, going to me would compute an available seat in the audience rather than
|
// compute the position (e.g., so that if I'm on stage, going to me would compute an available seat in the audience rather than
|
||||||
// being in my face on-stage). Note that this could work for going to an entity as well as to a person.
|
// being in my face on-stage). Note that this could work for going to an entity as well as to a person.
|
||||||
|
|
||||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", "
|
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", " << newPosition.y << ", "
|
||||||
<< newPosition.y << ", " << newPosition.z;
|
<< newPosition.z;
|
||||||
|
|
||||||
_goToPending = true;
|
_goToPending = true;
|
||||||
_goToPosition = newPosition;
|
_goToPosition = newPosition;
|
||||||
_goToOrientation = getWorldOrientation();
|
_goToOrientation = getWorldOrientation();
|
||||||
if (hasOrientation) {
|
if (hasOrientation) {
|
||||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "
|
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " << newOrientation.x << ", "
|
||||||
<< newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
|
<< newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
|
||||||
|
|
||||||
// orient the user to face the target
|
// orient the user to face the target
|
||||||
glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation);
|
glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation);
|
||||||
|
@ -2603,7 +2574,8 @@ bool MyAvatar::safeLanding(const glm::vec3& position) {
|
||||||
} else { // If you try to go while stuck, physics will keep you stuck.
|
} else { // If you try to go while stuck, physics will keep you stuck.
|
||||||
setCollisionsEnabled(false);
|
setCollisionsEnabled(false);
|
||||||
// Don't goToLocation just yet. Yield so that physics can act on the above.
|
// Don't goToLocation just yet. Yield so that physics can act on the above.
|
||||||
QMetaObject::invokeMethod(this, "goToLocationAndEnableCollisions", Qt::QueuedConnection, // The equivalent of javascript nextTick
|
QMetaObject::invokeMethod(this, "goToLocationAndEnableCollisions",
|
||||||
|
Qt::QueuedConnection, // The equivalent of javascript nextTick
|
||||||
Q_ARG(glm::vec3, better));
|
Q_ARG(glm::vec3, better));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -2611,7 +2583,6 @@ bool MyAvatar::safeLanding(const glm::vec3& position) {
|
||||||
|
|
||||||
// If position is not reliably safe from being stuck by physics, answer true and place a candidate better position in betterPositionOut.
|
// If position is not reliably safe from being stuck by physics, answer true and place a candidate better position in betterPositionOut.
|
||||||
bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& betterPositionOut) {
|
bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& betterPositionOut) {
|
||||||
|
|
||||||
// We begin with utilities and tests. The Algorithm in four parts is below.
|
// We begin with utilities and tests. The Algorithm in four parts is below.
|
||||||
// NOTE: we use estimated avatar height here instead of the bullet capsule halfHeight, because
|
// NOTE: we use estimated avatar height here instead of the bullet capsule halfHeight, because
|
||||||
// the domain avatar height limiting might not have taken effect yet on the actual bullet shape.
|
// the domain avatar height limiting might not have taken effect yet on the actual bullet shape.
|
||||||
|
@ -2634,7 +2605,8 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
|
||||||
betterPositionOut = upperIntersection + (up * halfHeight);
|
betterPositionOut = upperIntersection + (up * halfHeight);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
auto findIntersection = [&](const glm::vec3& startPointIn, const glm::vec3& directionIn, glm::vec3& intersectionOut, EntityItemID& entityIdOut, glm::vec3& normalOut) {
|
auto findIntersection = [&](const glm::vec3& startPointIn, const glm::vec3& directionIn, glm::vec3& intersectionOut,
|
||||||
|
EntityItemID& entityIdOut, glm::vec3& normalOut) {
|
||||||
OctreeElementPointer element;
|
OctreeElementPointer element;
|
||||||
float distance;
|
float distance;
|
||||||
BoxFace face;
|
BoxFace face;
|
||||||
|
@ -2648,8 +2620,9 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
|
||||||
bool* accurateResult = NULL;
|
bool* accurateResult = NULL;
|
||||||
|
|
||||||
QVariantMap extraInfo;
|
QVariantMap extraInfo;
|
||||||
EntityItemID entityID = entityTree->findRayIntersection(startPointIn, directionIn, include, ignore, visibleOnly, collidableOnly, precisionPicking,
|
EntityItemID entityID = entityTree->findRayIntersection(startPointIn, directionIn, include, ignore, visibleOnly,
|
||||||
element, distance, face, normalOut, extraInfo, lockType, accurateResult);
|
collidableOnly, precisionPicking, element, distance, face,
|
||||||
|
normalOut, extraInfo, lockType, accurateResult);
|
||||||
if (entityID.isNull()) {
|
if (entityID.isNull()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2677,7 +2650,8 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
|
||||||
// I.e., we are in a clearing between two objects.
|
// I.e., we are in a clearing between two objects.
|
||||||
if (isDown(upperNormal) && isUp(lowerNormal)) {
|
if (isDown(upperNormal) && isUp(lowerNormal)) {
|
||||||
auto spaceBetween = glm::distance(upperIntersection, lowerIntersection);
|
auto spaceBetween = glm::distance(upperIntersection, lowerIntersection);
|
||||||
const float halfHeightFactor = 2.25f; // Until case 5003 is fixed (and maybe after?), we need a fudge factor. Also account for content modelers not being precise.
|
const float halfHeightFactor =
|
||||||
|
2.25f; // Until case 5003 is fixed (and maybe after?), we need a fudge factor. Also account for content modelers not being precise.
|
||||||
if (spaceBetween > (halfHeightFactor * halfHeight)) {
|
if (spaceBetween > (halfHeightFactor * halfHeight)) {
|
||||||
// There is room for us to fit in that clearing. If there wasn't, physics would oscilate us between the objects above and below.
|
// There is room for us to fit in that clearing. If there wasn't, physics would oscilate us between the objects above and below.
|
||||||
// We're now going to iterate upwards through successive upperIntersections, testing to see if we're contained within the top surface of some entity.
|
// We're now going to iterate upwards through successive upperIntersections, testing to see if we're contained within the top surface of some entity.
|
||||||
|
@ -2716,7 +2690,6 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateMotionBehaviorFromMenu() {
|
void MyAvatar::updateMotionBehaviorFromMenu() {
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "updateMotionBehaviorFromMenu");
|
QMetaObject::invokeMethod(this, "updateMotionBehaviorFromMenu");
|
||||||
return;
|
return;
|
||||||
|
@ -2766,7 +2739,6 @@ float MyAvatar::getAvatarScale() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAvatarScale(float val) {
|
void MyAvatar::setAvatarScale(float val) {
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setAvatarScale", Q_ARG(float, val));
|
QMetaObject::invokeMethod(this, "setAvatarScale", Q_ARG(float, val));
|
||||||
return;
|
return;
|
||||||
|
@ -2776,7 +2748,6 @@ void MyAvatar::setAvatarScale(float val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setCollisionsEnabled(bool enabled) {
|
void MyAvatar::setCollisionsEnabled(bool enabled) {
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setCollisionsEnabled", Q_ARG(bool, enabled));
|
QMetaObject::invokeMethod(this, "setCollisionsEnabled", Q_ARG(bool, enabled));
|
||||||
return;
|
return;
|
||||||
|
@ -2983,12 +2954,14 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
||||||
tposeHead = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgHeadMass.name));
|
tposeHead = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgHeadMass.name));
|
||||||
}
|
}
|
||||||
if (_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name) != -1) {
|
if (_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name) != -1) {
|
||||||
cgLeftHandMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name));
|
cgLeftHandMass.position =
|
||||||
|
getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name));
|
||||||
} else {
|
} else {
|
||||||
cgLeftHandMass.position = DEFAULT_AVATAR_LEFTHAND_POS;
|
cgLeftHandMass.position = DEFAULT_AVATAR_LEFTHAND_POS;
|
||||||
}
|
}
|
||||||
if (_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name) != -1) {
|
if (_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name) != -1) {
|
||||||
cgRightHandMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name));
|
cgRightHandMass.position =
|
||||||
|
getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name));
|
||||||
} else {
|
} else {
|
||||||
cgRightHandMass.position = DEFAULT_AVATAR_RIGHTHAND_POS;
|
cgRightHandMass.position = DEFAULT_AVATAR_RIGHTHAND_POS;
|
||||||
}
|
}
|
||||||
|
@ -2997,7 +2970,8 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the current center of gravity position based on head and hand moments
|
// find the current center of gravity position based on head and hand moments
|
||||||
glm::vec3 sumOfMoments = (cgHeadMass.weight * cgHeadMass.position) + (cgLeftHandMass.weight * cgLeftHandMass.position) + (cgRightHandMass.weight * cgRightHandMass.position);
|
glm::vec3 sumOfMoments = (cgHeadMass.weight * cgHeadMass.position) + (cgLeftHandMass.weight * cgLeftHandMass.position) +
|
||||||
|
(cgRightHandMass.weight * cgRightHandMass.position);
|
||||||
float totalMass = cgHeadMass.weight + cgLeftHandMass.weight + cgRightHandMass.weight;
|
float totalMass = cgHeadMass.weight + cgLeftHandMass.weight + cgRightHandMass.weight;
|
||||||
|
|
||||||
glm::vec3 currentCg = (1.0f / totalMass) * sumOfMoments;
|
glm::vec3 currentCg = (1.0f / totalMass) * sumOfMoments;
|
||||||
|
@ -3037,7 +3011,6 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
||||||
// headOrientation, headPosition and hipsPosition are in avatar space
|
// headOrientation, headPosition and hipsPosition are in avatar space
|
||||||
// returns the matrix of the hips in Avatar space
|
// returns the matrix of the hips in Avatar space
|
||||||
static glm::mat4 computeNewHipsMatrix(glm::quat headOrientation, glm::vec3 headPosition, glm::vec3 hipsPosition) {
|
static glm::mat4 computeNewHipsMatrix(glm::quat headOrientation, glm::vec3 headPosition, glm::vec3 hipsPosition) {
|
||||||
|
|
||||||
glm::quat bodyOrientation = computeBodyFacingFromHead(headOrientation, Vectors::UNIT_Y);
|
glm::quat bodyOrientation = computeBodyFacingFromHead(headOrientation, Vectors::UNIT_Y);
|
||||||
|
|
||||||
const float MIX_RATIO = 0.3f;
|
const float MIX_RATIO = 0.3f;
|
||||||
|
@ -3047,10 +3020,7 @@ static glm::mat4 computeNewHipsMatrix(glm::quat headOrientation, glm::vec3 headP
|
||||||
glm::vec3 spineVec = headPosition - hipsPosition;
|
glm::vec3 spineVec = headPosition - hipsPosition;
|
||||||
glm::vec3 u, v, w;
|
glm::vec3 u, v, w;
|
||||||
generateBasisVectors(glm::normalize(spineVec), hipsFacing, u, v, w);
|
generateBasisVectors(glm::normalize(spineVec), hipsFacing, u, v, w);
|
||||||
return glm::mat4(glm::vec4(w, 0.0f),
|
return glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(hipsPosition, 1.0f));
|
||||||
glm::vec4(u, 0.0f),
|
|
||||||
glm::vec4(v, 0.0f),
|
|
||||||
glm::vec4(hipsPosition, 1.0f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avatarToWorld) {
|
static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avatarToWorld) {
|
||||||
|
@ -3091,7 +3061,8 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
||||||
|
|
||||||
if (_enableDebugDrawBaseOfSupport) {
|
if (_enableDebugDrawBaseOfSupport) {
|
||||||
float scaleBaseOfSupport = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT;
|
float scaleBaseOfSupport = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT;
|
||||||
glm::vec3 rightFootPositionLocal = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("RightFoot"));
|
glm::vec3 rightFootPositionLocal =
|
||||||
|
getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("RightFoot"));
|
||||||
drawBaseOfSupport(scaleBaseOfSupport, rightFootPositionLocal.y, avatarToWorldMat);
|
drawBaseOfSupport(scaleBaseOfSupport, rightFootPositionLocal.y, avatarToWorldMat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3099,7 +3070,8 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
||||||
const glm::vec3 cgHipsPosition = computeCounterBalance();
|
const glm::vec3 cgHipsPosition = computeCounterBalance();
|
||||||
|
|
||||||
// find the new hips rotation using the new head-hips axis as the up axis
|
// find the new hips rotation using the new head-hips axis as the up axis
|
||||||
glm::mat4 avatarHipsMat = computeNewHipsMatrix(glmExtractRotation(avatarHeadMat), extractTranslation(avatarHeadMat), cgHipsPosition);
|
glm::mat4 avatarHipsMat =
|
||||||
|
computeNewHipsMatrix(glmExtractRotation(avatarHeadMat), extractTranslation(avatarHeadMat), cgHipsPosition);
|
||||||
|
|
||||||
// convert hips from avatar to sensor space
|
// convert hips from avatar to sensor space
|
||||||
// The Y_180 is to convert from z forward to -z forward.
|
// The Y_180 is to convert from z forward to -z forward.
|
||||||
|
@ -3134,16 +3106,46 @@ static bool headAngularVelocityBelowThreshold(glm::vec3 angularVelocity) {
|
||||||
glm::vec3 xzPlaneAngularVelocity(angularVelocity.x, 0.0f, angularVelocity.z);
|
glm::vec3 xzPlaneAngularVelocity(angularVelocity.x, 0.0f, angularVelocity.z);
|
||||||
float magnitudeAngularVelocity = glm::length(xzPlaneAngularVelocity);
|
float magnitudeAngularVelocity = glm::length(xzPlaneAngularVelocity);
|
||||||
bool isBelowThreshold = (magnitudeAngularVelocity < ANGULAR_VELOCITY_THRESHOLD);
|
bool isBelowThreshold = (magnitudeAngularVelocity < ANGULAR_VELOCITY_THRESHOLD);
|
||||||
qCDebug(interfaceapp) << "magnitude " << magnitudeAngularVelocity << "head velocity below threshold is: " << isBelowThreshold;
|
qCDebug(interfaceapp) << "magnitude " << magnitudeAngularVelocity
|
||||||
qCDebug(interfaceapp) << "ang vel values x: " << angularVelocity.x << " y: " << angularVelocity.y << " z: " << angularVelocity.z;
|
<< "head velocity below threshold is: " << isBelowThreshold;
|
||||||
|
qCDebug(interfaceapp) << "ang vel values x: " << angularVelocity.x << " y: " << angularVelocity.y
|
||||||
|
<< " z: " << angularVelocity.z;
|
||||||
return isBelowThreshold;
|
return isBelowThreshold;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
static bool withinThresholdOfStandingHeightMode(float diffFromMode) {
|
bool MyAvatar::withinThresholdOfStandingHeightMode(float newReading) {
|
||||||
|
const float CENTIMETERS_PER_METER = 100.0f;
|
||||||
|
const float MODE_CORRECTION_FACTOR = 0.02f;
|
||||||
const float MODE_HEIGHT_THRESHOLD = 0.3f;
|
const float MODE_HEIGHT_THRESHOLD = 0.3f;
|
||||||
return (diffFromMode < MODE_HEIGHT_THRESHOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//first add the number to the mode array
|
||||||
|
for (int i = 0; i < (SIZE_OF_MODE_ARRAY - 1); i++) {
|
||||||
|
_heightModeArray[i] = _heightModeArray[i + 1];
|
||||||
|
}
|
||||||
|
_heightModeArray[SIZE_OF_MODE_ARRAY - 1] = (int)(newReading * CENTIMETERS_PER_METER);
|
||||||
|
|
||||||
|
int greatestFrequency = 0;
|
||||||
|
int mode = 0;
|
||||||
|
std::map<int, int> freq;
|
||||||
|
for (int j = 0; j < SIZE_OF_MODE_ARRAY; j++) {
|
||||||
|
freq[_heightModeArray[j]] += 1;
|
||||||
|
if ((freq[_heightModeArray[j]] > greatestFrequency) ||
|
||||||
|
((freq[_heightModeArray[j]] == SIZE_OF_MODE_ARRAY) && (_heightModeArray[j] > _currentMode))) {
|
||||||
|
greatestFrequency = freq[_heightModeArray[j]];
|
||||||
|
mode = _heightModeArray[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode > _currentMode) {
|
||||||
|
return mode;
|
||||||
|
} else {
|
||||||
|
if (!_resetMode && qApp->isHMDMode()) {
|
||||||
|
_resetMode = true;
|
||||||
|
return (newReading - MODE_CORRECTION_FACTOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return (diffFromMode < MODE_HEIGHT_THRESHOLD);
|
||||||
|
}
|
||||||
|
*/
|
||||||
float MyAvatar::getUserHeight() const {
|
float MyAvatar::getUserHeight() const {
|
||||||
return _userHeight.get();
|
return _userHeight.get();
|
||||||
}
|
}
|
||||||
|
@ -3250,12 +3252,10 @@ void driveKeysFromScriptValue(const QScriptValue& object, MyAvatar::DriveKeys& d
|
||||||
driveKeys = static_cast<MyAvatar::DriveKeys>(object.toUInt16());
|
driveKeys = static_cast<MyAvatar::DriveKeys>(object.toUInt16());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MyAvatar::lateUpdatePalms() {
|
void MyAvatar::lateUpdatePalms() {
|
||||||
Avatar::updatePalms();
|
Avatar::updatePalms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const float FOLLOW_TIME = 0.5f;
|
static const float FOLLOW_TIME = 0.5f;
|
||||||
|
|
||||||
MyAvatar::FollowHelper::FollowHelper() {
|
MyAvatar::FollowHelper::FollowHelper() {
|
||||||
|
@ -3309,13 +3309,17 @@ 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(PI / 6.0f); // 30 degrees
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
||||||
|
const glm::mat4& desiredBodyMatrix,
|
||||||
|
const glm::mat4& currentBodyMatrix) const {
|
||||||
// -z axis of currentBodyMatrix in world space.
|
// -z axis of currentBodyMatrix in world space.
|
||||||
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
|
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
|
||||||
// x axis of currentBodyMatrix in world space.
|
// x axis of currentBodyMatrix in world space.
|
||||||
|
@ -3329,7 +3333,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
||||||
const float MAX_FORWARD_LEAN = 0.15f;
|
const float MAX_FORWARD_LEAN = 0.15f;
|
||||||
const float MAX_BACKWARD_LEAN = 0.1f;
|
const float MAX_BACKWARD_LEAN = 0.1f;
|
||||||
|
|
||||||
|
|
||||||
if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
|
if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
|
||||||
return true;
|
return true;
|
||||||
} else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) {
|
} else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) {
|
||||||
|
@ -3337,10 +3340,11 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
||||||
}
|
}
|
||||||
|
|
||||||
return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
|
return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
const float CYLINDER_TOP = 0.1f;
|
const float CYLINDER_TOP = 0.1f;
|
||||||
const float CYLINDER_BOTTOM = -1.5f;
|
const float CYLINDER_BOTTOM = -1.5f;
|
||||||
|
|
||||||
|
@ -3349,11 +3353,11 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co
|
||||||
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix,
|
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar,
|
||||||
const glm::mat4& currentBodyMatrix, bool hasDriveInput) {
|
const glm::mat4& desiredBodyMatrix,
|
||||||
|
const glm::mat4& currentBodyMatrix,
|
||||||
if (myAvatar.getHMDLeanRecenterEnabled() &&
|
bool hasDriveInput) {
|
||||||
qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
|
if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
|
||||||
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||||
activate(Rotation);
|
activate(Rotation);
|
||||||
}
|
}
|
||||||
|
@ -3376,8 +3380,8 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
||||||
|
|
||||||
if (!isActive(Horizontal) && (getForceActivateHorizontal() ||
|
if (!isActive(Horizontal) && (getForceActivateHorizontal() ||
|
||||||
(!withinBaseOfSupport(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation()) &&
|
(!withinBaseOfSupport(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation()) &&
|
||||||
headAngularVelocityBelowThreshold(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getAngularVelocity()))) &&
|
headAngularVelocityBelowThreshold(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getAngularVelocity())))){ //&&
|
||||||
withinThresholdOfStandingHeightMode(0.01f)) {
|
//withinThresholdOfStandingHeightMode(0.01f)))) {
|
||||||
qCDebug(interfaceapp) << "----------------------------------------over the base of support";
|
qCDebug(interfaceapp) << "----------------------------------------over the base of support";
|
||||||
activate(Horizontal);
|
activate(Horizontal);
|
||||||
setForceActivateHorizontal(false);
|
setForceActivateHorizontal(false);
|
||||||
|
@ -3433,7 +3437,8 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
|
||||||
glm::mat4 worldToSensorMatrix = glm::inverse(sensorToWorldMatrix);
|
glm::mat4 worldToSensorMatrix = glm::inverse(sensorToWorldMatrix);
|
||||||
|
|
||||||
glm::vec3 sensorLinearDisplacement = transformVectorFast(worldToSensorMatrix, worldLinearDisplacement);
|
glm::vec3 sensorLinearDisplacement = transformVectorFast(worldToSensorMatrix, worldLinearDisplacement);
|
||||||
glm::quat sensorAngularDisplacement = glmExtractRotation(worldToSensorMatrix) * worldAngularDisplacement * glmExtractRotation(sensorToWorldMatrix);
|
glm::quat sensorAngularDisplacement =
|
||||||
|
glmExtractRotation(worldToSensorMatrix) * worldAngularDisplacement * glmExtractRotation(sensorToWorldMatrix);
|
||||||
|
|
||||||
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
|
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
|
||||||
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
||||||
|
@ -3496,7 +3501,8 @@ bool MyAvatar::didTeleport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::hasDriveInput() const {
|
bool MyAvatar::hasDriveInput() const {
|
||||||
return fabsf(getDriveKey(TRANSLATE_X)) > 0.0f || fabsf(getDriveKey(TRANSLATE_Y)) > 0.0f || fabsf(getDriveKey(TRANSLATE_Z)) > 0.0f;
|
return fabsf(getDriveKey(TRANSLATE_X)) > 0.0f || fabsf(getDriveKey(TRANSLATE_Y)) > 0.0f ||
|
||||||
|
fabsf(getDriveKey(TRANSLATE_Z)) > 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAway(bool value) {
|
void MyAvatar::setAway(bool value) {
|
||||||
|
@ -3512,7 +3518,6 @@ void MyAvatar::setAway(bool value) {
|
||||||
// Specificly, if we are rendering using a third person camera. We would like to render the hand controllers in front of the camera,
|
// Specificly, if we are rendering using a third person camera. We would like to render the hand controllers in front of the camera,
|
||||||
// not in front of the avatar.
|
// not in front of the avatar.
|
||||||
glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& controllerSensorMatrix) const {
|
glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& controllerSensorMatrix) const {
|
||||||
|
|
||||||
// Fetch the current camera transform.
|
// Fetch the current camera transform.
|
||||||
glm::mat4 cameraWorldMatrix = qApp->getCamera().getTransform();
|
glm::mat4 cameraWorldMatrix = qApp->getCamera().getTransform();
|
||||||
if (qApp->getCamera().getMode() == CAMERA_MODE_MIRROR) {
|
if (qApp->getCamera().getMode() == CAMERA_MODE_MIRROR) {
|
||||||
|
@ -3568,9 +3573,7 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||||
return glmExtractRotation(invAvatarMat * qApp->getCamera().getTransform());
|
return glmExtractRotation(invAvatarMat * qApp->getCamera().getTransform());
|
||||||
}
|
}
|
||||||
default: {
|
default: { return Avatar::getAbsoluteJointRotationInObjectFrame(index); }
|
||||||
return Avatar::getAbsoluteJointRotationInObjectFrame(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3605,9 +3608,7 @@ glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||||
return extractTranslation(invAvatarMat * qApp->getCamera().getTransform());
|
return extractTranslation(invAvatarMat * qApp->getCamera().getTransform());
|
||||||
}
|
}
|
||||||
default: {
|
default: { return Avatar::getAbsoluteJointTranslationInObjectFrame(index); }
|
||||||
return Avatar::getAbsoluteJointTranslationInObjectFrame(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3616,7 +3617,9 @@ glm::mat4 MyAvatar::getCenterEyeCalibrationMat() const {
|
||||||
int rightEyeIndex = _skeletonModel->getRig().indexOfJoint("RightEye");
|
int rightEyeIndex = _skeletonModel->getRig().indexOfJoint("RightEye");
|
||||||
int leftEyeIndex = _skeletonModel->getRig().indexOfJoint("LeftEye");
|
int leftEyeIndex = _skeletonModel->getRig().indexOfJoint("LeftEye");
|
||||||
if (rightEyeIndex >= 0 && leftEyeIndex >= 0) {
|
if (rightEyeIndex >= 0 && leftEyeIndex >= 0) {
|
||||||
auto centerEyePos = (getAbsoluteDefaultJointTranslationInObjectFrame(rightEyeIndex) + getAbsoluteDefaultJointTranslationInObjectFrame(leftEyeIndex)) * 0.5f;
|
auto centerEyePos = (getAbsoluteDefaultJointTranslationInObjectFrame(rightEyeIndex) +
|
||||||
|
getAbsoluteDefaultJointTranslationInObjectFrame(leftEyeIndex)) *
|
||||||
|
0.5f;
|
||||||
auto centerEyeRot = Quaternions::Y_180;
|
auto centerEyeRot = Quaternions::Y_180;
|
||||||
return createMatFromQuatAndPos(centerEyeRot, centerEyePos / getSensorToWorldScale());
|
return createMatFromQuatAndPos(centerEyeRot, centerEyePos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
|
@ -3684,7 +3687,6 @@ glm::mat4 MyAvatar::getRightFootCalibrationMat() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
glm::mat4 MyAvatar::getRightArmCalibrationMat() const {
|
glm::mat4 MyAvatar::getRightArmCalibrationMat() const {
|
||||||
int rightArmIndex = _skeletonModel->getRig().indexOfJoint("RightArm");
|
int rightArmIndex = _skeletonModel->getRig().indexOfJoint("RightArm");
|
||||||
if (rightArmIndex >= 0) {
|
if (rightArmIndex >= 0) {
|
||||||
|
|
|
@ -49,6 +49,8 @@ enum AudioListenerMode {
|
||||||
CUSTOM
|
CUSTOM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int SIZE_OF_MODE_ARRAY = 50;
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AudioListenerMode);
|
Q_DECLARE_METATYPE(AudioListenerMode);
|
||||||
|
|
||||||
class MyAvatar : public Avatar {
|
class MyAvatar : public Avatar {
|
||||||
|
@ -1025,6 +1027,8 @@ public:
|
||||||
|
|
||||||
bool isReadyForPhysics() const;
|
bool isReadyForPhysics() const;
|
||||||
|
|
||||||
|
bool withinThresholdOfStandingHeightMode(float newReading);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -1631,6 +1635,10 @@ private:
|
||||||
bool _shouldLoadScripts { false };
|
bool _shouldLoadScripts { false };
|
||||||
|
|
||||||
bool _haveReceivedHeightLimitsFromDomain = { false };
|
bool _haveReceivedHeightLimitsFromDomain = { false };
|
||||||
|
int _heightModeArray[SIZE_OF_MODE_ARRAY];
|
||||||
|
int _currentMode = 0;
|
||||||
|
bool _resetMode = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||||
|
|
Loading…
Reference in a new issue