From fc018257e1c5cec851da80c0b5366db03c6db04d Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 9 Oct 2019 12:20:35 -0700 Subject: [PATCH] Select avatar to look using API. Blink when look at change --- interface/src/avatar/MyAvatar.cpp | 28 +++++++++++++------ interface/src/avatar/MyAvatar.h | 2 ++ .../src/avatars-renderer/Head.cpp | 7 +++-- libraries/avatars/src/HeadData.cpp | 16 +++++++++++ libraries/avatars/src/HeadData.h | 15 ++++++---- 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ea0efe29cb..f529f168f4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2188,15 +2188,20 @@ void MyAvatar::computeMyLookAtTarget(const AvatarHash& hash) { foreach (const AvatarSharedPointer& avatarData, hash) { std::shared_ptr avatar = std::static_pointer_cast(avatarData); if (!avatar->isMyAvatar() && avatar->isInitialized()) { - glm::vec3 otherForward = avatar->getHead()->getForwardDirection(); - glm::vec3 otherPosition = avatar->getHead()->getEyePosition(); - const float TIME_WITHOUT_TALKING_THRESHOLD = 1.0f; - bool otherIsTalking = avatar->getHead()->getTimeWithoutTalking() <= TIME_WITHOUT_TALKING_THRESHOLD; - bool lookingAtOtherAlready = _lookAtTargetAvatar.lock().get() == avatar.get(); - float cost = lookAtCostFunction(myForward, myPosition, otherForward, otherPosition, otherIsTalking, lookingAtOtherAlready); - if (cost < bestCost) { - bestCost = cost; + if (_forceTargetAvatarID.isNull() || avatar->getID() != _forceTargetAvatarID) { + glm::vec3 otherForward = avatar->getHead()->getForwardDirection(); + glm::vec3 otherPosition = avatar->getHead()->getEyePosition(); + const float TIME_WITHOUT_TALKING_THRESHOLD = 1.0f; + bool otherIsTalking = avatar->getHead()->getTimeWithoutTalking() <= TIME_WITHOUT_TALKING_THRESHOLD; + bool lookingAtOtherAlready = _lookAtTargetAvatar.lock().get() == avatar.get(); + float cost = lookAtCostFunction(myForward, myPosition, otherForward, otherPosition, otherIsTalking, lookingAtOtherAlready); + if (cost < bestCost) { + bestCost = cost; + bestAvatar = avatar; + } + } else { bestAvatar = avatar; + break; } } } @@ -6838,3 +6843,10 @@ void MyAvatar::resetPointAt() { } } +void MyAvatar::setLookAtAvatarID(const QUuid& avatarID) { + if (QThread::currentThread() != thread()) { + BLOCKING_INVOKE_METHOD(this, "setLookAtAvatarID", + Q_ARG(const QUuid&, avatarID)); + } + _forceTargetAvatarID = avatarID; +} \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a7ba639461..d93ee776be 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -971,6 +971,7 @@ public: * @param {Uuid} entityID - The entity that the hand touch effect will be enabled for. */ Q_INVOKABLE void enableHandTouchForID(const QUuid& entityID); + Q_INVOKABLE void setLookAtAvatarID(const QUuid& avatarID); bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } void setUseAdvancedMovementControls(bool useAdvancedMovementControls) @@ -2656,6 +2657,7 @@ private: AvatarWeakPointer _lookAtTargetAvatar; glm::vec3 _targetAvatarPosition; + QUuid _forceTargetAvatarID; bool _shouldRender { true }; float _oculusYawOffset; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Head.cpp b/libraries/avatars-renderer/src/avatars-renderer/Head.cpp index 63d8e2981c..a9dde201af 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Head.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Head.cpp @@ -96,10 +96,13 @@ void Head::simulate(float deltaTime) { // no blinking when brows are raised; blink less with increasing loudness const float BASE_BLINK_RATE = 15.0f / 60.0f; const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f; - if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(fabs(_averageLoudness - _longTermAverageLoudness)) * + if (_forceBlink || forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(fabs(_averageLoudness - _longTermAverageLoudness)) * ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) { float randSpeedVariability = randFloat(); float eyeBlinkVelocity = BLINK_SPEED + randSpeedVariability * BLINK_SPEED_VARIABILITY; + if (_forceBlink) { + eyeBlinkVelocity = 0.5f * eyeBlinkVelocity; + } _leftEyeBlinkVelocity = eyeBlinkVelocity; _rightEyeBlinkVelocity = eyeBlinkVelocity; if (randFloat() < 0.5f) { @@ -114,7 +117,7 @@ void Head::simulate(float deltaTime) { if (_leftEyeBlink == FULLY_CLOSED) { _leftEyeBlinkVelocity = -BLINK_SPEED; - + updateEyeLookAt(); } else if (_leftEyeBlink == FULLY_OPEN) { _leftEyeBlinkVelocity = 0.0f; } diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index c86e534929..f8a09905ef 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -233,3 +233,19 @@ void HeadData::setHasProceduralEyeMovement(bool hasProceduralEyeMovement) { void HeadData::setFaceTrackerConnected(bool value) { _isFaceTrackerConnected = value; } + +void HeadData::setLookAtPosition(const glm::vec3& lookAtPosition) { + if (_requestLookAtPosition != lookAtPosition) { + _lookAtPositionChanged = usecTimestampNow(); + glm::vec3 oldAvatarLookAtVector = _requestLookAtPosition - _owningAvatar->getWorldPosition(); + glm::vec3 newAvatarLookAtVector = lookAtPosition - _owningAvatar->getWorldPosition(); + const float MIN_BLINK_ANGLE = 0.35f; // 20 degrees + _forceBlink = angleBetween(oldAvatarLookAtVector, newAvatarLookAtVector) > MIN_BLINK_ANGLE; + _lookAtUpdated = false; + } + _requestLookAtPosition = lookAtPosition; + if (_lookAtUpdated) { + _forceBlink = false; + _lookAtPosition = lookAtPosition; + } +} \ No newline at end of file diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index dc5aaf2595..a8005b5659 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -64,12 +64,7 @@ public: void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { _blendshapeCoefficients = blendshapeCoefficients; } const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } - void setLookAtPosition(const glm::vec3& lookAtPosition) { - if (_lookAtPosition != lookAtPosition) { - _lookAtPositionChanged = usecTimestampNow(); - } - _lookAtPosition = lookAtPosition; - } + void setLookAtPosition(const glm::vec3& lookAtPosition); bool lookAtPositionChangedSince(quint64 time) { return _lookAtPositionChanged >= time; } bool getHasProceduralEyeFaceMovement() const; @@ -84,6 +79,11 @@ public: void setFaceTrackerConnected(bool value); bool getFaceTrackerConnected() const { return _isFaceTrackerConnected; } + void updateEyeLookAt() { + _lookAtPosition = _requestLookAtPosition; + _lookAtUpdated = true; + } + friend class AvatarData; QJsonObject toJson() const; @@ -95,6 +95,7 @@ protected: float _basePitch; float _baseRoll; + glm::vec3 _requestLookAtPosition; glm::vec3 _lookAtPosition; quint64 _lookAtPositionChanged { 0 }; @@ -115,6 +116,8 @@ protected: QVector _summedBlendshapeCoefficients; QMap _blendshapeLookupMap; AvatarData* _owningAvatar; + bool _forceBlink { false }; + bool _lookAtUpdated { false }; private: // privatize copy ctor and assignment operator so copies of this object cannot be made