added the first pass at mode computation

This commit is contained in:
amantley 2018-06-27 18:02:11 -07:00
parent 7b49ae4950
commit 61a935dbb5
2 changed files with 271 additions and 261 deletions

View file

@ -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) {

View file

@ -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);