mirror of
https://github.com/overte-org/overte.git
synced 2025-07-28 19:30:10 +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_SIMPLE_MODE = 0;
|
||||
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_MAX = 25.0f;
|
||||
|
@ -90,33 +91,15 @@ const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
|||
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
||||
|
||||
MyAvatar::MyAvatar(QThread* thread) :
|
||||
Avatar(thread),
|
||||
_yawSpeed(YAW_SPEED_DEFAULT),
|
||||
_pitchSpeed(PITCH_SPEED_DEFAULT),
|
||||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
||||
_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),
|
||||
Avatar(thread), _yawSpeed(YAW_SPEED_DEFAULT), _pitchSpeed(PITCH_SPEED_DEFAULT),
|
||||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _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),
|
||||
_smoothOrientationTimer(std::numeric_limits<float>::max()),
|
||||
_smoothOrientationInitial(),
|
||||
_smoothOrientationTarget(),
|
||||
_hmdSensorMatrix(),
|
||||
_hmdSensorOrientation(),
|
||||
_hmdSensorPosition(),
|
||||
_bodySensorMatrix(),
|
||||
_goToPending(false),
|
||||
_goToPosition(),
|
||||
_goToOrientation(),
|
||||
_prevShouldDrawHead(true),
|
||||
_audioListenerMode(FROM_HEAD),
|
||||
_hmdAtRestDetector(glm::vec3(0), glm::quat())
|
||||
{
|
||||
|
||||
_smoothOrientationTimer(std::numeric_limits<float>::max()), _smoothOrientationInitial(), _smoothOrientationTarget(),
|
||||
_hmdSensorMatrix(), _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
|
||||
_headData = new MyHead(this);
|
||||
|
||||
|
@ -148,8 +131,8 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
using SlotType = void (MyAvatar::*)(const glm::vec3&, bool, const glm::quat&, bool);
|
||||
|
||||
// connect to AddressManager signal for location jumps
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired, this,
|
||||
static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||
|
||||
// handle scale constraints imposed on us by the domain-server
|
||||
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
@ -211,7 +194,6 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
|
||||
if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&
|
||||
(dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {
|
||||
|
||||
setSkeletonModelURL(dummyAvatar.getSkeletonModelURL());
|
||||
}
|
||||
|
||||
|
@ -258,7 +240,8 @@ void MyAvatar::setDominantHand(const QString& hand) {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
QScriptValue driveKeys = engine->newObject();
|
||||
|
@ -371,7 +354,6 @@ void MyAvatar::clearIKJointLimitHistory() {
|
|||
}
|
||||
|
||||
void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
||||
|
||||
assert(QThread::currentThread() == thread());
|
||||
|
||||
// Reset dynamic state.
|
||||
|
@ -412,7 +394,6 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
|||
}
|
||||
|
||||
void MyAvatar::update(float deltaTime) {
|
||||
|
||||
// update moving average of HMD facing in xz plane.
|
||||
const float HMD_FACING_TIMESCALE = 4.0f; // very slow average
|
||||
float tau = deltaTime / HMD_FACING_TIMESCALE;
|
||||
|
@ -426,8 +407,11 @@ void MyAvatar::update(float deltaTime) {
|
|||
#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE
|
||||
auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation());
|
||||
glm::vec3 worldFacingAverage = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
|
||||
glm::vec3 worldFacing = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacing.x, 0.0f, _headControllerFacing.y));
|
||||
glm::vec3 worldFacingAverage =
|
||||
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 + worldFacingAverage, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
#endif
|
||||
|
@ -464,7 +448,8 @@ void MyAvatar::update(float deltaTime) {
|
|||
setAudioLoudness(audio->getLastInputLoudness());
|
||||
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
|
||||
halfBoundingBoxDimensions += _characterController.getCapsuleLocalOffset();
|
||||
QMetaObject::invokeMethod(audio.data(), "setAvatarBoundingBoxParameters",
|
||||
|
@ -491,13 +476,10 @@ void MyAvatar::update(float deltaTime) {
|
|||
}
|
||||
|
||||
void MyAvatar::updateEyeContactTarget(float deltaTime) {
|
||||
|
||||
_eyeContactTargetTimer -= deltaTime;
|
||||
if (_eyeContactTargetTimer < 0.0f) {
|
||||
|
||||
const float CHANCE_OF_CHANGING_TARGET = 0.01f;
|
||||
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
|
||||
|
||||
float const FIFTY_FIFTY_CHANCE = 0.5f;
|
||||
float const EYE_TO_MOUTH_CHANCE = 0.25f;
|
||||
switch (_eyeContactTarget) {
|
||||
|
@ -550,9 +532,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
|
||||
if (isChildOfHead) {
|
||||
updateChildCauterization(object);
|
||||
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
updateChildCauterization(descendant);
|
||||
});
|
||||
object->forEachDescendant([&](SpatiallyNestablePointer descendant) { updateChildCauterization(descendant); });
|
||||
}
|
||||
});
|
||||
_cauterizationNeedsUpdate = false;
|
||||
|
@ -672,7 +652,8 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
EntityItemProperties descendantProperties;
|
||||
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
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
|
||||
}
|
||||
});
|
||||
|
@ -703,8 +684,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
_hmdSensorMatrix = hmdSensorMatrix;
|
||||
auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
||||
|
||||
if (newHmdSensorPosition != getHMDSensorPosition() &&
|
||||
glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
|
||||
if (newHmdSensorPosition != getHMDSensorPosition() && glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
|
||||
qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition;
|
||||
// Ignore unreasonable HMD sensor data
|
||||
return;
|
||||
|
@ -736,11 +716,11 @@ void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeV
|
|||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
void MyAvatar::updateSensorToWorldMatrix() {
|
||||
|
||||
// update the sensor mat so that the body position will end up in the desired
|
||||
// position when driven from the head.
|
||||
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);
|
||||
|
||||
bool hasSensorToWorldScaleChanged = false;
|
||||
|
@ -762,7 +742,6 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
if (hasSensorToWorldScaleChanged) {
|
||||
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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_MIN_YAW_TURN = 15.0f;
|
||||
const float TRACKER_MAX_YAW_TURN = 50.0f;
|
||||
if ( (fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) &&
|
||||
(fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN) ) {
|
||||
if ((fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) && (fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN)) {
|
||||
if (estimatedRotation.y > 0.0f) {
|
||||
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
} 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.
|
||||
// Note that roll is magnified by a constant because it is not related to field of view.
|
||||
|
||||
|
||||
Head* head = getHead();
|
||||
if (inHmd || playing) {
|
||||
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) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "overrideAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps),
|
||||
Q_ARG(bool, loop), Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
||||
QMetaObject::invokeMethod(this, "overrideAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps), Q_ARG(bool, loop),
|
||||
Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
||||
return;
|
||||
}
|
||||
_skeletonModel->getRig().overrideAnimation(url, fps, loop, firstFrame, lastFrame);
|
||||
|
@ -971,8 +948,12 @@ QStringList MyAvatar::getAnimationRoles() {
|
|||
return _skeletonModel->getRig().getAnimationRoles();
|
||||
}
|
||||
|
||||
void MyAvatar::overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop,
|
||||
float firstFrame, float lastFrame) {
|
||||
void MyAvatar::overrideRoleAnimation(const QString& role,
|
||||
const QString& url,
|
||||
float fps,
|
||||
bool loop,
|
||||
float firstFrame,
|
||||
float lastFrame) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
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));
|
||||
|
@ -993,10 +974,9 @@ void MyAvatar::saveAvatarUrl() {
|
|||
Settings settings;
|
||||
settings.beginGroup("Avatar");
|
||||
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
|
||||
settings.setValue("fullAvatarURL",
|
||||
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
|
||||
"" :
|
||||
_fullAvatarURLFromPreferences.toString());
|
||||
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl()
|
||||
? ""
|
||||
: _fullAvatarURLFromPreferences.toString());
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
@ -1017,10 +997,9 @@ void MyAvatar::saveData() {
|
|||
// (so the overrideURL is not valid), or it was overridden _and_ we specified
|
||||
// --replaceAvatarURL (so _saveAvatarOverrideUrl is true)
|
||||
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
|
||||
settings.setValue("fullAvatarURL",
|
||||
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
|
||||
"" :
|
||||
_fullAvatarURLFromPreferences.toString());
|
||||
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl()
|
||||
? ""
|
||||
: _fullAvatarURLFromPreferences.toString());
|
||||
}
|
||||
|
||||
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
|
||||
|
@ -1332,16 +1311,15 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
bool isCurrentTarget = avatar->getIsLookAtTarget();
|
||||
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
||||
avatar->setIsLookAtTarget(false);
|
||||
if (!avatar->isMyAvatar() && avatar->isInitialized() &&
|
||||
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getModelScale())) {
|
||||
if (!avatar->isMyAvatar() && avatar->isInitialized() && (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getModelScale())) {
|
||||
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))) {
|
||||
_lookAtTargetAvatar = avatarPointer;
|
||||
_targetAvatarPosition = avatarPointer->getWorldPosition();
|
||||
}
|
||||
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.
|
||||
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));
|
||||
return;
|
||||
}
|
||||
writeLockWithNamedJointIndex(name, [&](int index) {
|
||||
_skeletonModel->getRig().clearJointAnimationPriority(index);
|
||||
});
|
||||
writeLockWithNamedJointIndex(name, [&](int index) { _skeletonModel->getRig().clearJointAnimationPriority(index); });
|
||||
}
|
||||
|
||||
void MyAvatar::clearJointsData() {
|
||||
|
@ -1523,9 +1499,9 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
_cauterizationNeedsUpdate = true;
|
||||
|
||||
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 (_fullAvatarModelName.isEmpty()) {
|
||||
// Store the FST file name into preferences
|
||||
const auto& mapping = _skeletonModel->getGeometry()->getMapping();
|
||||
|
@ -1536,7 +1512,8 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
|
||||
initHeadBones();
|
||||
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
|
||||
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
|
||||
_fstAnimGraphOverrideUrl =
|
||||
_skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
|
||||
initAnimGraph();
|
||||
}
|
||||
QObject::disconnect(*skeletonConnection);
|
||||
|
@ -1577,7 +1554,6 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
|
|||
return avatarEntitiesData;
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::resetFullAvatarURL() {
|
||||
auto lastAvatarURL = getFullAvatarURLFromPreferences();
|
||||
auto lastAvatarName = getFullAvatarModelName();
|
||||
|
@ -1586,11 +1562,8 @@ void MyAvatar::resetFullAvatarURL() {
|
|||
}
|
||||
|
||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL",
|
||||
Q_ARG(const QUrl&, fullAvatarURL),
|
||||
Q_ARG(const QString&, modelName));
|
||||
BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL", Q_ARG(const QUrl&, fullAvatarURL), Q_ARG(const QString&, modelName));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1610,8 +1583,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
|||
|
||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
|
||||
Q_ARG(const QVector<AttachmentData>, attachmentData));
|
||||
BLOCKING_INVOKE_METHOD(this, "setAttachmentData", Q_ARG(const QVector<AttachmentData>, attachmentData));
|
||||
return;
|
||||
}
|
||||
Avatar::setAttachmentData(attachmentData);
|
||||
|
@ -1716,7 +1688,8 @@ void MyAvatar::updateMotors() {
|
|||
}
|
||||
|
||||
if (_isPushing || _isBraking || !_isBeingPushed) {
|
||||
_characterController.addMotor(_actionMotorVelocity, motorRotation, horizontalMotorTimescale, verticalMotorTimescale);
|
||||
_characterController.addMotor(_actionMotorVelocity, motorRotation, horizontalMotorTimescale,
|
||||
verticalMotorTimescale);
|
||||
} else {
|
||||
// _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
|
||||
|
@ -1736,7 +1709,8 @@ void MyAvatar::updateMotors() {
|
|||
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, _scriptedMotorTimescale);
|
||||
} else {
|
||||
// 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) {
|
||||
// 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
|
||||
_scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
|
||||
DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
|
||||
_scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
|
||||
}
|
||||
|
||||
void MyAvatar::setScriptedMotorFrame(QString frame) {
|
||||
|
@ -1883,10 +1856,14 @@ SharedSoundPointer MyAvatar::getCollisionSound() {
|
|||
return _collisionSound;
|
||||
}
|
||||
|
||||
void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
||||
const glm::vec3& translation, const glm::quat& rotation,
|
||||
float scale, bool isSoft,
|
||||
bool allowDuplicates, bool useSaved) {
|
||||
void MyAvatar::attach(const QString& modelURL,
|
||||
const QString& jointName,
|
||||
const glm::vec3& translation,
|
||||
const glm::quat& rotation,
|
||||
float scale,
|
||||
bool isSoft,
|
||||
bool allowDuplicates,
|
||||
bool useSaved) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved);
|
||||
return;
|
||||
|
@ -1894,10 +1871,8 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
|||
if (useSaved) {
|
||||
AttachmentData attachment = loadAttachmentData(modelURL, jointName);
|
||||
if (attachment.isValid()) {
|
||||
Avatar::attach(modelURL, attachment.jointName,
|
||||
attachment.translation, attachment.rotation,
|
||||
attachment.scale, attachment.isSoft,
|
||||
allowDuplicates, useSaved);
|
||||
Avatar::attach(modelURL, attachment.jointName, attachment.translation, attachment.rotation, attachment.scale,
|
||||
attachment.isSoft, allowDuplicates, useSaved);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1950,7 +1925,6 @@ QUrl MyAvatar::getAnimGraphUrl() const {
|
|||
}
|
||||
|
||||
void MyAvatar::setAnimGraphUrl(const QUrl& url) {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setAnimGraphUrl", Q_ARG(QUrl, url));
|
||||
return;
|
||||
|
@ -1995,10 +1969,8 @@ void MyAvatar::animGraphLoaded() {
|
|||
}
|
||||
|
||||
void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||
|
||||
Avatar::postUpdate(deltaTime, scene);
|
||||
if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
|
||||
|
||||
auto animSkeleton = _skeletonModel->getRig().getAnimSkeleton();
|
||||
|
||||
// the rig is in the skeletonModel frame
|
||||
|
@ -2006,7 +1978,8 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
|
||||
if (_enableDebugDrawDefaultPose && animSkeleton) {
|
||||
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) {
|
||||
|
@ -2027,13 +2000,15 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
auto rightHandPose = getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND);
|
||||
|
||||
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 {
|
||||
DebugDraw::getInstance().removeMarker("leftHandController");
|
||||
}
|
||||
|
||||
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 {
|
||||
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());
|
||||
const int NUM_DEBUG_COLORS = 8;
|
||||
const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = {
|
||||
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(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?
|
||||
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(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()) {
|
||||
|
@ -2079,7 +2049,6 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
}
|
||||
|
||||
void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
|
||||
|
||||
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
|
||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||
|
@ -2144,7 +2113,6 @@ void MyAvatar::setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement)
|
|||
}
|
||||
|
||||
void MyAvatar::updateOrientation(float deltaTime) {
|
||||
|
||||
// Smoothly rotate body with arrow keys
|
||||
float targetSpeed = getDriveKey(YAW) * _yawSpeed;
|
||||
if (targetSpeed != 0.0f) {
|
||||
|
@ -2171,7 +2139,6 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
|
||||
float totalBodyYaw = _bodyYawDelta * deltaTime;
|
||||
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) {
|
||||
|
||||
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover &&
|
||||
_hmdRollControlEnabled && hasDriveInput()) {
|
||||
// Turn with head roll.
|
||||
const float MIN_CONTROL_SPEED = 2.0f * getSensorToWorldScale(); // meters / sec
|
||||
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
|
||||
if (fabsf(forwardSpeed) >= MIN_CONTROL_SPEED) {
|
||||
|
||||
float direction = forwardSpeed > 0.0f ? 1.0f : -1.0f;
|
||||
float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT)));
|
||||
float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f;
|
||||
|
@ -2245,8 +2211,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
|
||||
void MyAvatar::updateActionMotor(float deltaTime) {
|
||||
bool thrustIsPushing = (glm::length2(_thrust) > EPSILON);
|
||||
bool scriptedMotorIsPushing = (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)
|
||||
&& _scriptedMotorTimescale < MAX_CHARACTER_MOTOR_TIMESCALE;
|
||||
bool scriptedMotorIsPushing =
|
||||
(_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) && _scriptedMotorTimescale < MAX_CHARACTER_MOTOR_TIMESCALE;
|
||||
_isBeingPushed = thrustIsPushing || scriptedMotorIsPushing;
|
||||
if (_isPushing || _isBeingPushed) {
|
||||
// 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
|
||||
}
|
||||
|
||||
bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float heightA,
|
||||
const glm::vec3 positionB, float radiusB, float heightB, glm::vec3& penetration) {
|
||||
bool findAvatarAvatarPenetration(const glm::vec3 positionA,
|
||||
float radiusA,
|
||||
float heightA,
|
||||
const glm::vec3 positionB,
|
||||
float radiusB,
|
||||
float heightB,
|
||||
glm::vec3& penetration) {
|
||||
glm::vec3 positionBA = positionB - positionA;
|
||||
float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z);
|
||||
if (xzDistance < (radiusA + radiusB)) {
|
||||
|
@ -2531,9 +2502,9 @@ void MyAvatar::goToLocation(const QVariant& propertiesVar) {
|
|||
}
|
||||
|
||||
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||
bool hasOrientation, const glm::quat& newOrientation,
|
||||
bool hasOrientation,
|
||||
const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation) {
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// 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 << ", "
|
||||
<< newPosition.y << ", " << newPosition.z;
|
||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", " << newPosition.y << ", "
|
||||
<< newPosition.z;
|
||||
|
||||
_goToPending = true;
|
||||
_goToPosition = newPosition;
|
||||
_goToOrientation = getWorldOrientation();
|
||||
if (hasOrientation) {
|
||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "
|
||||
<< newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
|
||||
qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " << newOrientation.x << ", "
|
||||
<< newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
|
||||
|
||||
// orient the user to face the target
|
||||
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.
|
||||
setCollisionsEnabled(false);
|
||||
// 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));
|
||||
}
|
||||
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.
|
||||
bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& betterPositionOut) {
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
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;
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
@ -2648,8 +2620,9 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
|
|||
bool* accurateResult = NULL;
|
||||
|
||||
QVariantMap extraInfo;
|
||||
EntityItemID entityID = entityTree->findRayIntersection(startPointIn, directionIn, include, ignore, visibleOnly, collidableOnly, precisionPicking,
|
||||
element, distance, face, normalOut, extraInfo, lockType, accurateResult);
|
||||
EntityItemID entityID = entityTree->findRayIntersection(startPointIn, directionIn, include, ignore, visibleOnly,
|
||||
collidableOnly, precisionPicking, element, distance, face,
|
||||
normalOut, extraInfo, lockType, accurateResult);
|
||||
if (entityID.isNull()) {
|
||||
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.
|
||||
if (isDown(upperNormal) && isUp(lowerNormal)) {
|
||||
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)) {
|
||||
// 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.
|
||||
|
@ -2716,7 +2690,6 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette
|
|||
}
|
||||
|
||||
void MyAvatar::updateMotionBehaviorFromMenu() {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateMotionBehaviorFromMenu");
|
||||
return;
|
||||
|
@ -2766,7 +2739,6 @@ float MyAvatar::getAvatarScale() {
|
|||
}
|
||||
|
||||
void MyAvatar::setAvatarScale(float val) {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setAvatarScale", Q_ARG(float, val));
|
||||
return;
|
||||
|
@ -2776,7 +2748,6 @@ void MyAvatar::setAvatarScale(float val) {
|
|||
}
|
||||
|
||||
void MyAvatar::setCollisionsEnabled(bool enabled) {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setCollisionsEnabled", Q_ARG(bool, enabled));
|
||||
return;
|
||||
|
@ -2983,12 +2954,14 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
|||
tposeHead = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgHeadMass.name));
|
||||
}
|
||||
if (_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name) != -1) {
|
||||
cgLeftHandMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name));
|
||||
cgLeftHandMass.position =
|
||||
getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name));
|
||||
} else {
|
||||
cgLeftHandMass.position = DEFAULT_AVATAR_LEFTHAND_POS;
|
||||
}
|
||||
if (_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name) != -1) {
|
||||
cgRightHandMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name));
|
||||
cgRightHandMass.position =
|
||||
getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name));
|
||||
} else {
|
||||
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
|
||||
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;
|
||||
|
||||
glm::vec3 currentCg = (1.0f / totalMass) * sumOfMoments;
|
||||
|
@ -3037,7 +3011,6 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
|||
// headOrientation, headPosition and hipsPosition are 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) {
|
||||
|
||||
glm::quat bodyOrientation = computeBodyFacingFromHead(headOrientation, Vectors::UNIT_Y);
|
||||
|
||||
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 u, v, w;
|
||||
generateBasisVectors(glm::normalize(spineVec), hipsFacing, u, v, w);
|
||||
return glm::mat4(glm::vec4(w, 0.0f),
|
||||
glm::vec4(u, 0.0f),
|
||||
glm::vec4(v, 0.0f),
|
||||
glm::vec4(hipsPosition, 1.0f));
|
||||
return glm::mat4(glm::vec4(w, 0.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) {
|
||||
|
@ -3091,7 +3061,8 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
|||
|
||||
if (_enableDebugDrawBaseOfSupport) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -3099,7 +3070,8 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
|||
const glm::vec3 cgHipsPosition = computeCounterBalance();
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
float magnitudeAngularVelocity = glm::length(xzPlaneAngularVelocity);
|
||||
bool isBelowThreshold = (magnitudeAngularVelocity < ANGULAR_VELOCITY_THRESHOLD);
|
||||
qCDebug(interfaceapp) << "magnitude " << magnitudeAngularVelocity << "head velocity below threshold is: " << isBelowThreshold;
|
||||
qCDebug(interfaceapp) << "ang vel values x: " << angularVelocity.x << " y: " << angularVelocity.y << " z: " << angularVelocity.z;
|
||||
qCDebug(interfaceapp) << "magnitude " << magnitudeAngularVelocity
|
||||
<< "head velocity below threshold is: " << isBelowThreshold;
|
||||
qCDebug(interfaceapp) << "ang vel values x: " << angularVelocity.x << " y: " << angularVelocity.y
|
||||
<< " z: " << angularVelocity.z;
|
||||
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;
|
||||
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 {
|
||||
return _userHeight.get();
|
||||
}
|
||||
|
@ -3250,12 +3252,10 @@ void driveKeysFromScriptValue(const QScriptValue& object, MyAvatar::DriveKeys& d
|
|||
driveKeys = static_cast<MyAvatar::DriveKeys>(object.toUInt16());
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::lateUpdatePalms() {
|
||||
Avatar::updatePalms();
|
||||
}
|
||||
|
||||
|
||||
static const float FOLLOW_TIME = 0.5f;
|
||||
|
||||
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
|
||||
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
||||
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.
|
||||
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
|
||||
// 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_BACKWARD_LEAN = 0.1f;
|
||||
|
||||
|
||||
if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
|
||||
return true;
|
||||
} 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;
|
||||
|
||||
}
|
||||
|
||||
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_BOTTOM = -1.5f;
|
||||
|
||||
|
@ -3349,11 +3353,11 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co
|
|||
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
|
||||
}
|
||||
|
||||
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix,
|
||||
const glm::mat4& currentBodyMatrix, bool hasDriveInput) {
|
||||
|
||||
if (myAvatar.getHMDLeanRecenterEnabled() &&
|
||||
qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
|
||||
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar,
|
||||
const glm::mat4& desiredBodyMatrix,
|
||||
const glm::mat4& currentBodyMatrix,
|
||||
bool hasDriveInput) {
|
||||
if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
|
||||
if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
|
||||
activate(Rotation);
|
||||
}
|
||||
|
@ -3376,8 +3380,8 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
|
||||
if (!isActive(Horizontal) && (getForceActivateHorizontal() ||
|
||||
(!withinBaseOfSupport(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation()) &&
|
||||
headAngularVelocityBelowThreshold(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getAngularVelocity()))) &&
|
||||
withinThresholdOfStandingHeightMode(0.01f)) {
|
||||
headAngularVelocityBelowThreshold(myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getAngularVelocity())))){ //&&
|
||||
//withinThresholdOfStandingHeightMode(0.01f)))) {
|
||||
qCDebug(interfaceapp) << "----------------------------------------over the base of support";
|
||||
activate(Horizontal);
|
||||
setForceActivateHorizontal(false);
|
||||
|
@ -3433,7 +3437,8 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
|
|||
glm::mat4 worldToSensorMatrix = glm::inverse(sensorToWorldMatrix);
|
||||
|
||||
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),
|
||||
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
||||
|
@ -3496,7 +3501,8 @@ bool MyAvatar::didTeleport() {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -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,
|
||||
// not in front of the avatar.
|
||||
glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& controllerSensorMatrix) const {
|
||||
|
||||
// Fetch the current camera transform.
|
||||
glm::mat4 cameraWorldMatrix = qApp->getCamera().getTransform();
|
||||
if (qApp->getCamera().getMode() == CAMERA_MODE_MIRROR) {
|
||||
|
@ -3568,9 +3573,7 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
|||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return glmExtractRotation(invAvatarMat * qApp->getCamera().getTransform());
|
||||
}
|
||||
default: {
|
||||
return Avatar::getAbsoluteJointRotationInObjectFrame(index);
|
||||
}
|
||||
default: { return Avatar::getAbsoluteJointRotationInObjectFrame(index); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3605,9 +3608,7 @@ glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
|||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return extractTranslation(invAvatarMat * qApp->getCamera().getTransform());
|
||||
}
|
||||
default: {
|
||||
return Avatar::getAbsoluteJointTranslationInObjectFrame(index);
|
||||
}
|
||||
default: { return Avatar::getAbsoluteJointTranslationInObjectFrame(index); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3616,7 +3617,9 @@ glm::mat4 MyAvatar::getCenterEyeCalibrationMat() const {
|
|||
int rightEyeIndex = _skeletonModel->getRig().indexOfJoint("RightEye");
|
||||
int leftEyeIndex = _skeletonModel->getRig().indexOfJoint("LeftEye");
|
||||
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;
|
||||
return createMatFromQuatAndPos(centerEyeRot, centerEyePos / getSensorToWorldScale());
|
||||
} else {
|
||||
|
@ -3684,7 +3687,6 @@ glm::mat4 MyAvatar::getRightFootCalibrationMat() const {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
glm::mat4 MyAvatar::getRightArmCalibrationMat() const {
|
||||
int rightArmIndex = _skeletonModel->getRig().indexOfJoint("RightArm");
|
||||
if (rightArmIndex >= 0) {
|
||||
|
|
|
@ -49,6 +49,8 @@ enum AudioListenerMode {
|
|||
CUSTOM
|
||||
};
|
||||
|
||||
const int SIZE_OF_MODE_ARRAY = 50;
|
||||
|
||||
Q_DECLARE_METATYPE(AudioListenerMode);
|
||||
|
||||
class MyAvatar : public Avatar {
|
||||
|
@ -1025,6 +1027,8 @@ public:
|
|||
|
||||
bool isReadyForPhysics() const;
|
||||
|
||||
bool withinThresholdOfStandingHeightMode(float newReading);
|
||||
|
||||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -1631,6 +1635,10 @@ private:
|
|||
bool _shouldLoadScripts { false };
|
||||
|
||||
bool _haveReceivedHeightLimitsFromDomain = { false };
|
||||
int _heightModeArray[SIZE_OF_MODE_ARRAY];
|
||||
int _currentMode = 0;
|
||||
bool _resetMode = false;
|
||||
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
Loading…
Reference in a new issue