From 641e1526998fe5fcf57f35816c7a5675133d330f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 6 May 2016 18:55:09 -0700 Subject: [PATCH 1/5] Eye tracking bug fix and debug rendering improvement * Bug fix for eye tracking in HMD, the "up" orientation of your eyes now match your head. * DebugDraw: added drawRay method. * Application: Renamed preRender to postUpdate * AvatarManager: added postUpdate method that iterates over all avatars. * MyAvatar: Renamed preRender to preDisplaySide * MyAvatar: split preRender code into postUpdate and preDisplaySide. * Removed "Show who is looking at me", "Render focus indicator" and "Render lookat target" debug draw. * Split "Show Look At Vectors" into "Show My Look At Vectors" and "Show Other Look At Vectors", to make it easier to debug eye tracking. * "Show Look at Vectors" now draws the right eye red and the left eye blue. * Removed Avatar and MyAvatar renderBody * Removed look at rendering from head. * GLMHelpers: Bugfix for generateBasisVectors when up primary and secondary axis were orthogonal --- interface/src/Application.cpp | 27 +++-- interface/src/Application.h | 6 +- interface/src/Menu.cpp | 6 +- interface/src/Menu.h | 6 +- interface/src/avatar/Avatar.cpp | 105 ++++++------------ interface/src/avatar/Avatar.h | 7 +- interface/src/avatar/AvatarManager.cpp | 9 ++ interface/src/avatar/AvatarManager.h | 2 + interface/src/avatar/Head.cpp | 46 -------- interface/src/avatar/Head.h | 32 ++---- interface/src/avatar/MyAvatar.cpp | 45 ++------ interface/src/avatar/MyAvatar.h | 4 +- interface/src/avatar/SkeletonModel.cpp | 2 +- libraries/animation/src/Rig.cpp | 18 ++- .../src/AbstractViewStateInterface.h | 4 +- libraries/render-utils/src/AnimDebugDraw.cpp | 18 +++ libraries/render-utils/src/Model.cpp | 2 +- libraries/shared/src/DebugDraw.cpp | 5 + libraries/shared/src/DebugDraw.h | 12 +- libraries/shared/src/GLMHelpers.cpp | 20 +++- 20 files changed, 159 insertions(+), 217 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2a4088dcc..ea088135bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -45,11 +45,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -101,7 +103,7 @@ #include #include -#include "AnimDebugDraw.h" + #include "AudioClient.h" #include "audio/AudioScope.h" #include "avatar/AvatarManager.h" @@ -3033,9 +3035,9 @@ void Application::updateLOD() const { } } -void Application::pushPreRenderLambda(void* key, std::function func) { - std::unique_lock guard(_preRenderLambdasLock); - _preRenderLambdas[key] = func; +void Application::pushPostUpdateLambda(void* key, std::function func) { + std::unique_lock guard(_postUpdateLambdasLock); + _postUpdateLambdas[key] = func; } // Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone. @@ -3553,15 +3555,19 @@ void Application::update(float deltaTime) { } } + avatarManager->postUpdate(deltaTime); + { PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0); - std::unique_lock guard(_preRenderLambdasLock); - for (auto& iter : _preRenderLambdas) { + std::unique_lock guard(_postUpdateLambdasLock); + for (auto& iter : _postUpdateLambdas) { iter.second(); } - _preRenderLambdas.clear(); + _postUpdateLambdas.clear(); } + + AnimDebugDraw::getInstance().update(); } @@ -4006,13 +4012,10 @@ namespace render { void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) { - // FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering. + // FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering. // Then we can move this logic into the Avatar::simulate call. auto myAvatar = getMyAvatar(); - myAvatar->preRender(renderArgs); - - // Update animation debug draw renderer - AnimDebugDraw::getInstance().update(); + myAvatar->preDisplaySide(renderArgs); activeRenderingThread = QThread::currentThread(); PROFILE_RANGE(__FUNCTION__); diff --git a/interface/src/Application.h b/interface/src/Application.h index 2911d42b65..303cb3fb1d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -212,7 +212,7 @@ public: render::EnginePointer getRenderEngine() override { return _renderEngine; } gpu::ContextPointer getGPUContext() const { return _gpuContext; } - virtual void pushPreRenderLambda(void* key, std::function func) override; + virtual void pushPostUpdateLambda(void* key, std::function func) override; const QRect& getMirrorViewRect() const { return _mirrorViewRect; } @@ -513,8 +513,8 @@ private: QThread* _deadlockWatchdogThread; - std::map> _preRenderLambdas; - std::mutex _preRenderLambdasLock; + std::map> _postUpdateLambdas; + std::mutex _postUpdateLambdasLock; std::atomic _fullSceneReceivedCounter { 0 }; // how many times have we received a full-scene octree stats packet uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c5fa52e49d..4436e86931 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -480,10 +480,8 @@ Menu::Menu() { avatarManager.data(), SLOT(setShouldShowReceiveStats(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtTargets, 0, false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowWhosLookingAtMe, 0, false); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderMyLookAtVectors, 0, false); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderOtherLookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false, avatar, SLOT(setEnableDebugDrawDefaultPose(bool))); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5796575780..39c3a6fe1f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -147,9 +147,8 @@ namespace MenuOption { const QString ReloadAllScripts = "Reload All Scripts"; const QString ReloadContent = "Reload Content (Clears all caches)"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; - const QString RenderFocusIndicator = "Show Eye Focus"; - const QString RenderLookAtTargets = "Show Look-at Targets"; - const QString RenderLookAtVectors = "Show Look-at Vectors"; + const QString RenderMyLookAtVectors = "Show My Eye Vectors"; + const QString RenderOtherLookAtVectors = "Show Other Eye Vectors"; const QString RenderMaxTextureMemory = "Maximum Texture Memory"; const QString RenderMaxTextureAutomatic = "Automatic Texture Memory"; const QString RenderMaxTexture64MB = "64 MB"; @@ -174,7 +173,6 @@ namespace MenuOption { const QString ShowDSConnectTable = "Show Domain Connection Timing"; const QString ShowBordersEntityNodes = "Show Entity Nodes"; const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats"; - const QString ShowWhosLookingAtMe = "Show Who's Looking at Me"; const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; const QString SimulateEyeTracking = "Simulate"; const QString SMIEyeTracking = "SMI Eye Tracking"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2cacb81ce4..14385ddfcb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "Application.h" #include "Avatar.h" @@ -65,11 +66,6 @@ namespace render { } template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) { auto avatarPtr = static_pointer_cast(avatar); - bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors); - avatarPtr->setDisplayingLookatVectors(renderLookAtVectors); - bool renderLookAtTarget = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtTargets); - avatarPtr->setDisplayingLookatTarget(renderLookAtTarget); - if (avatarPtr->isInitialized() && args) { PROFILE_RANGE_BATCH(*args->_batch, "renderAvatarPayload"); avatarPtr->render(args, qApp->getCamera()->getPosition()); @@ -318,6 +314,39 @@ void Avatar::updateRenderItem(render::PendingChanges& pendingChanges) { } } +void Avatar::postUpdate(float deltaTime) { + + bool renderLookAtVectors; + if (isMyAvatar()) { + renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderMyLookAtVectors); + } else { + renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderOtherLookAtVectors); + } + + if (renderLookAtVectors) { + const float EYE_RAY_LENGTH = 10.0; + const glm::vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f); + const glm::vec4 RED(1.0f, 0.0f, 0.0f, 1.0f); + + int leftEyeJoint = getJointIndex("LeftEye"); + glm::vec3 leftEyePosition; + glm::quat leftEyeRotation; + + if (_skeletonModel->getJointPositionInWorldFrame(leftEyeJoint, leftEyePosition) && + _skeletonModel->getJointRotationInWorldFrame(leftEyeJoint, leftEyeRotation)) { + DebugDraw::getInstance().drawRay(leftEyePosition, leftEyePosition + leftEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, BLUE); + } + + int rightEyeJoint = getJointIndex("RightEye"); + glm::vec3 rightEyePosition; + glm::quat rightEyeRotation; + if (_skeletonModel->getJointPositionInWorldFrame(rightEyeJoint, rightEyePosition) && + _skeletonModel->getJointRotationInWorldFrame(rightEyeJoint, rightEyeRotation)) { + DebugDraw::getInstance().drawRay(rightEyePosition, rightEyePosition + rightEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, RED); + } + } +} + void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { auto& batch = *renderArgs->_batch; PROFILE_RANGE_BATCH(batch, __FUNCTION__); @@ -412,8 +441,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { ? 1.0f : GLOW_FROM_AVERAGE_LOUDNESS; - // render body - renderBody(renderArgs, frustum, glowLevel); + fixupModelsInScene(); if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { // add local lights @@ -437,64 +465,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { const float BOUNDING_SHAPE_ALPHA = 0.7f; _skeletonModel->renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA); } - - // If this is the avatar being looked at, render a little ball above their head - if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) { - static const float INDICATOR_OFFSET = 0.22f; - static const float INDICATOR_RADIUS = 0.03f; - static const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; - glm::vec3 avatarPosition = getPosition(); - glm::vec3 position = glm::vec3(avatarPosition.x, getDisplayNamePosition().y + INDICATOR_OFFSET, avatarPosition.z); - PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderFocusIndicator"); - Transform transform; - transform.setTranslation(position); - transform.postScale(INDICATOR_RADIUS); - batch.setModelTransform(transform); - DependencyManager::get()->renderSolidSphereInstance(batch, LOOK_AT_INDICATOR_COLOR); - } - - // If the avatar is looking at me, indicate that they are - if (getHead()->isLookingAtMe() && Menu::getInstance()->isOptionChecked(MenuOption::ShowWhosLookingAtMe)) { - PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderLookingAtMe"); - const glm::vec3 LOOKING_AT_ME_COLOR = { 1.0f, 1.0f, 1.0f }; - const float LOOKING_AT_ME_ALPHA_START = 0.8f; - const float LOOKING_AT_ME_DURATION = 0.5f; // seconds - quint64 now = usecTimestampNow(); - float alpha = LOOKING_AT_ME_ALPHA_START - * (1.0f - ((float)(now - getHead()->getLookingAtMeStarted())) - / (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND)); - if (alpha > 0.0f) { - if (_skeletonModel->isLoaded()) { - const auto& geometry = _skeletonModel->getFBXGeometry(); - const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye - const float RADIUS_INCREMENT = 0.005f; - batch.setModelTransform(Transform()); - - glm::vec3 position = getHead()->getLeftEyePosition(); - Transform transform; - transform.setTranslation(position); - float eyeDiameter = geometry.leftEyeSize; - if (eyeDiameter == 0.0f) { - eyeDiameter = DEFAULT_EYE_DIAMETER; - } - - batch.setModelTransform(Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT)); - DependencyManager::get()->renderSolidSphereInstance(batch, - glm::vec4(LOOKING_AT_ME_COLOR, alpha)); - - position = getHead()->getRightEyePosition(); - transform.setTranslation(position); - eyeDiameter = geometry.rightEyeSize; - if (eyeDiameter == 0.0f) { - eyeDiameter = DEFAULT_EYE_DIAMETER; - } - batch.setModelTransform(Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT)); - DependencyManager::get()->renderSolidSphereInstance(batch, - glm::vec4(LOOKING_AT_ME_COLOR, alpha)); - - } - } - } } const float DISPLAYNAME_DISTANCE = 20.0f; @@ -553,11 +523,6 @@ void Avatar::fixupModelsInScene() { scene->enqueuePendingChanges(pendingChanges); } -void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { - fixupModelsInScene(); - getHead()->renderLookAts(renderArgs); -} - bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { return true; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cb35fbb5eb..2580ac1d37 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -77,9 +77,9 @@ public: void updateRenderItem(render::PendingChanges& pendingChanges); + virtual void postUpdate(float deltaTime); + //setters - void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); } - void setDisplayingLookatTarget(bool displayingLookatTarget) { getHead()->setRenderLookatTarget(displayingLookatTarget); } void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; } bool getIsLookAtTarget() const { return _isLookAtTarget; } //getters @@ -232,7 +232,6 @@ protected: Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const; void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f); virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual void fixupModelsInScene(); @@ -251,7 +250,7 @@ private: bool _initialized; bool _shouldAnimate { true }; bool _shouldSkipRender { false }; - bool _isLookAtTarget; + bool _isLookAtTarget { false }; float getBoundingRadius() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 402245d0c3..7ff2976cd9 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -156,6 +156,15 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { simulateAvatarFades(deltaTime); } +void AvatarManager::postUpdate(float deltaTime) { + auto hashCopy = getHashCopy(); + AvatarHash::iterator avatarIterator = hashCopy.begin(); + for (avatarIterator = hashCopy.begin(); avatarIterator != hashCopy.end(); avatarIterator++) { + auto avatar = std::static_pointer_cast(avatarIterator.value()); + avatar->postUpdate(deltaTime); + } +} + void AvatarManager::simulateAvatarFades(float deltaTime) { QVector::iterator fadingIterator = _avatarFades.begin(); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 94a66782f2..1cd295d69f 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -44,6 +44,8 @@ public: void updateMyAvatar(float deltaTime); void updateOtherAvatars(float deltaTime); + void postUpdate(float deltaTime); + void clearOtherAvatars(); void clearAllAvatars(); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b7247334fc..3af8b8a423 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -46,8 +46,6 @@ Head::Head(Avatar* owningAvatar) : _mouth3(0.0f), _mouth4(0.0f), _mouthTime(0.0f), - _renderLookatVectors(false), - _renderLookatTarget(false), _saccade(0.0f, 0.0f, 0.0f), _saccadeTarget(0.0f, 0.0f, 0.0f), _leftEyeBlinkVelocity(0.0f), @@ -316,22 +314,6 @@ void Head::relaxLean(float deltaTime) { _deltaLeanForward *= relaxationFactor; } -void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum) { -} - -void Head::renderLookAts(RenderArgs* renderArgs) { - renderLookAts(renderArgs, _leftEyePosition, _rightEyePosition); -} - -void Head::renderLookAts(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition) { - if (_renderLookatVectors) { - renderLookatVectors(renderArgs, leftEyePosition, rightEyePosition, getCorrectedLookAtPosition()); - } - if (_renderLookatTarget) { - renderLookatTarget(renderArgs, getCorrectedLookAtPosition()); - } -} - void Head::setScale (float scale) { if (_scale == scale) { return; @@ -442,31 +424,3 @@ void Head::addLeanDeltas(float sideways, float forward) { _deltaLeanSideways += sideways; _deltaLeanForward += forward; } - -void Head::renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { - auto& batch = *renderArgs->_batch; - auto transform = Transform{}; - batch.setModelTransform(transform); - // FIXME: THe line width of 2.0f is not supported anymore, we ll need a workaround - - glm::vec4 startColor(0.2f, 0.2f, 0.2f, 1.0f); - glm::vec4 endColor(1.0f, 1.0f, 1.0f, 0.0f); - - auto geometryCache = DependencyManager::get(); - geometryCache->bindSimpleProgram(batch); - geometryCache->renderLine(batch, leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID); - geometryCache->renderLine(batch, rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID); -} - -void Head::renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition) { - auto& batch = *renderArgs->_batch; - auto transform = Transform{}; - transform.setTranslation(lookatPosition); - - auto geometryCache = DependencyManager::get(); - const float LOOK_AT_TARGET_RADIUS = 0.075f; - transform.postScale(LOOK_AT_TARGET_RADIUS); - const glm::vec4 LOOK_AT_TARGET_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; - batch.setModelTransform(transform); - geometryCache->renderSolidSphereInstance(batch, LOOK_AT_TARGET_COLOR); -} diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index d0bd4fdb77..e4b8fefea5 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -28,29 +28,24 @@ class Avatar; class Head : public HeadData { public: explicit Head(Avatar* owningAvatar); - + void init(); void reset(); void simulate(float deltaTime, bool isMine, bool billboard = false); - void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; } - void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; } - void setRenderLookatTarget(bool onOff) { _renderLookatTarget = onOff; } - void renderLookAts(RenderArgs* renderArgs); - void renderLookAts(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition); /// \return orientationBase+Delta glm::quat getFinalOrientationInLocalFrame() const; - + /// \return orientationBody * (orientationBase+Delta) glm::quat getFinalOrientationInWorldFrame() const; /// \return orientationBody * orientationBasePitch glm::quat getCameraOrientation () const; - + void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition); glm::vec3 getCorrectedLookAtPosition(); void clearCorrectedLookAtPosition() { _isLookingAtMe = false; } @@ -66,9 +61,9 @@ public: glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; } float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; } - + glm::quat getEyeRotation(const glm::vec3& eyePosition) const; - + const glm::vec3& getRightEyePosition() const { return _rightEyePosition; } const glm::vec3& getLeftEyePosition() const { return _leftEyePosition; } glm::vec3 getRightEarPosition() const { return _rightEyePosition + (getRightDirection() * EYE_EAR_GAP) + (getFrontDirection() * -EYE_EAR_GAP); } @@ -85,10 +80,10 @@ public: void setDeltaYaw(float yaw) { _deltaYaw = yaw; } float getDeltaYaw() const { return _deltaYaw; } - + void setDeltaRoll(float roll) { _deltaRoll = roll; } float getDeltaRoll() const { return _deltaRoll; } - + virtual void setFinalYaw(float finalYaw); virtual void setFinalPitch(float finalPitch); virtual void setFinalRoll(float finalRoll); @@ -100,7 +95,7 @@ public: void addLeanDeltas(float sideways, float forward); float getTimeWithoutTalking() const { return _timeWithoutTalking; } - + private: glm::vec3 calculateAverageEyePosition() const { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * 0.5f; } @@ -114,7 +109,7 @@ private: glm::vec3 _leftEyePosition; glm::vec3 _rightEyePosition; glm::vec3 _eyePosition; - + float _scale; float _lastLoudness; float _longTermAverageLoudness; @@ -125,8 +120,7 @@ private: float _mouth3; float _mouth4; float _mouthTime; - bool _renderLookatVectors; - bool _renderLookatTarget; + glm::vec3 _saccade; glm::vec3 _saccadeTarget; float _leftEyeBlinkVelocity; @@ -146,15 +140,13 @@ private: bool _isLookingAtMe; quint64 _lookingAtMeStarted; quint64 _wasLastLookingAtMe; - + glm::vec3 _correctedLookAtPosition; int _leftEyeLookAtID; int _rightEyeLookAtID; - + // private methods - void renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition); - void renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition); void calculateMouthShapes(); void applyEyelidOffset(glm::quat headOrientation); }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bad60643ec..b2d653d573 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1259,40 +1259,6 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved); } -void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { - - if (!_skeletonModel->isRenderable()) { - return; // wait until all models are loaded - } - - fixupModelsInScene(); - - // Render head so long as the camera isn't inside it - if (shouldRenderHead(renderArgs)) { - getHead()->render(renderArgs, 1.0f, renderFrustum); - } - - // This is drawing the lookat vectors from our avatar to wherever we're looking. - if (qApp->isHMDMode()) { - glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - - glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); - glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left); - leftEyePose = leftEyePose * headPose; - glm::vec3 leftEyePosition = extractTranslation(leftEyePose); - glm::mat4 rightEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right); - rightEyePose = rightEyePose * headPose; - glm::vec3 rightEyePosition = extractTranslation(rightEyePose); - glm::vec3 headPosition = extractTranslation(headPose); - - getHead()->renderLookAts(renderArgs, - cameraPosition + getOrientation() * (leftEyePosition - headPosition), - cameraPosition + getOrientation() * (rightEyePosition - headPosition)); - } else { - getHead()->renderLookAts(renderArgs); - } -} - void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visible) { if (model->isActive() && model->isRenderable()) { model->setVisibleInScene(visible, scene); @@ -1349,11 +1315,11 @@ void MyAvatar::destroyAnimGraph() { _rig->destroyAnimGraph(); } -void MyAvatar::preRender(RenderArgs* renderArgs) { +void MyAvatar::postUpdate(float deltaTime) { + + Avatar::postUpdate(deltaTime); render::ScenePointer scene = qApp->getMain3DScene(); - const bool shouldDrawHead = shouldRenderHead(renderArgs); - if (_skeletonModel->initWhenReady(scene)) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); @@ -1403,7 +1369,12 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { DebugDraw::getInstance().updateMyAvatarPos(getPosition()); DebugDraw::getInstance().updateMyAvatarRot(getOrientation()); +} +void MyAvatar::preDisplaySide(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) { _skeletonModel->setCauterizeBones(!shouldDrawHead); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fee1a9add3..949b4fdfb3 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -95,7 +95,8 @@ public: Q_INVOKABLE void reset(bool andRecenter = false); void update(float deltaTime); - void preRender(RenderArgs* renderArgs); + virtual void postUpdate(float deltaTime) override; + void preDisplaySide(RenderArgs* renderArgs); const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; } const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; } @@ -306,7 +307,6 @@ private: void simulate(float deltaTime); void updateFromTrackers(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); } bool getShouldRenderLocally() const { return _shouldRender; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 0fe1a59bb2..5deeb545a1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "Application.h" #include "Avatar.h" @@ -92,7 +93,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Head* head = _owningAvatar->getHead(); - // make sure lookAt is not too close to face (avoid crosseyes) glm::vec3 lookAt = _owningAvatar->isMyAvatar() ? head->getLookAtPosition() : head->getCorrectedLookAtPosition(); glm::vec3 focusOffset = lookAt - _owningAvatar->getHead()->getEyePosition(); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index a7115199a2..67dfbec24a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1057,20 +1057,30 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { } void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { + + // TODO: does not properly handle avatar scale. + if (isIndexValid(index)) { glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation); glm::mat4 worldToRig = glm::inverse(rigToWorld); - glm::vec3 zAxis = glm::normalize(_internalPoseSet._absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot)); + glm::vec3 lookAtVector = glm::normalize(transformPoint(worldToRig, lookAtSpot) - _internalPoseSet._absolutePoses[index].trans); - glm::quat desiredQuat = rotationBetween(IDENTITY_FRONT, zAxis); - glm::quat headQuat; int headIndex = indexOfJoint("Head"); + glm::quat headQuat; if (headIndex >= 0) { headQuat = _internalPoseSet._absolutePoses[headIndex].rot; } + + glm::vec3 headUp = headQuat * Vectors::UNIT_Y; + glm::vec3 z, y, x; + generateBasisVectors(lookAtVector, headUp, z, y, x); + glm::mat3 m(glm::cross(y, z), y, z); + glm::quat desiredQuat = glm::normalize(glm::quat_cast(m)); + glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat); - // limit rotation + // limit swing rotation of the deltaQuat by a 30 degree cone. + // TODO: use swing twist decomposition constraint instead, for off axis rotation clamping. const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; if (fabsf(glm::angle(deltaQuat)) > MAX_ANGLE) { deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat)); diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 7c7c263562..51a030567d 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -35,7 +35,7 @@ public: virtual ViewFrustum* getShadowViewFrustum() = 0; virtual QThread* getMainThread() = 0; - + virtual PickRay computePickRay(float x, float y) const = 0; virtual glm::vec3 getAvatarPosition() const = 0; @@ -46,7 +46,7 @@ public: virtual render::ScenePointer getMain3DScene() = 0; virtual render::EnginePointer getRenderEngine() = 0; - virtual void pushPreRenderLambda(void* key, std::function func) = 0; + virtual void pushPostUpdateLambda(void* key, std::function func) = 0; // FIXME - we shouldn't assume that there's a single instance of an AbstractViewStateInterface static AbstractViewStateInterface* instance(); diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index e2abc226e5..220b673591 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -307,6 +307,16 @@ static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPo } } +static void addLine(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, Vertex*& v) { + uint32_t colorInt = toRGBA(color); + v->pos = start; + v->rgba = colorInt; + v++; + v->pos = end; + v->rgba = colorInt; + v++; +} + void AnimDebugDraw::update() { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); @@ -319,6 +329,7 @@ void AnimDebugDraw::update() { const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3); const size_t VERTICES_PER_LINK = 8 * 2; + const size_t VERTICES_PER_RAY = 2; const float BONE_RADIUS = 0.01f; // 1 cm const float POSE_RADIUS = 0.1f; // 10 cm @@ -342,6 +353,7 @@ void AnimDebugDraw::update() { numVerts += (int)markerMap.size() * VERTICES_PER_BONE; auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap(); numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE; + numVerts += (int)DebugDraw::getInstance().getRays().size() * VERTICES_PER_RAY; // allocate verts! data._vertexBuffer->resize(sizeof(Vertex) * numVerts); @@ -390,6 +402,12 @@ void AnimDebugDraw::update() { addBone(myAvatarPose, AnimPose(glm::vec3(1), rot, pos), radius, v); } + // draw rays from shared DebugDraw singleton + for (auto& iter : DebugDraw::getInstance().getRays()) { + addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v); + } + DebugDraw::getInstance().clearRays(); + assert(numVerts == (v - verts)); render::Item::Bound theBound; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index eda856342c..2fe4427333 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -132,7 +132,7 @@ void Model::updateRenderItems() { // the application will ensure only the last lambda is actually invoked. void* key = (void*)this; std::weak_ptr weakSelf = shared_from_this(); - AbstractViewStateInterface::instance()->pushPreRenderLambda(key, [weakSelf]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() { // do nothing, if the model has already been destroyed. auto self = weakSelf.lock(); diff --git a/libraries/shared/src/DebugDraw.cpp b/libraries/shared/src/DebugDraw.cpp index 557889cab0..04759e6187 100644 --- a/libraries/shared/src/DebugDraw.cpp +++ b/libraries/shared/src/DebugDraw.cpp @@ -23,6 +23,11 @@ DebugDraw::~DebugDraw() { } +// world space line, drawn only once +void DebugDraw::drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color) { + _rays.push_back(Ray(start, end, color)); +} + void DebugDraw::addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { _markers[key] = MarkerInfo(rotation, position, color); } diff --git a/libraries/shared/src/DebugDraw.h b/libraries/shared/src/DebugDraw.h index 2f62f17abf..2d30618afe 100644 --- a/libraries/shared/src/DebugDraw.h +++ b/libraries/shared/src/DebugDraw.h @@ -23,16 +23,21 @@ public: DebugDraw(); ~DebugDraw(); - // world space maker + // world space line, drawn only once + void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color); + + // world space maker, marker drawn every frame until it is removed. void addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color); void removeMarker(const std::string& key); - // myAvatar relative marker + // myAvatar relative marker, maker is drawn every frame until it is removed. void addMyAvatarMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color); void removeMyAvatarMarker(const std::string& key); using MarkerInfo = std::tuple; using MarkerMap = std::unordered_map; + using Ray = std::tuple; + using Rays = std::vector; // // accessors used by renderer @@ -44,12 +49,15 @@ public: const glm::vec3& getMyAvatarPos() const { return _myAvatarPos; } void updateMyAvatarRot(const glm::quat& rot) { _myAvatarRot = rot; } const glm::quat& getMyAvatarRot() const { return _myAvatarRot; } + const Rays getRays() const { return _rays; } + void clearRays() { _rays.clear(); } protected: MarkerMap _markers; MarkerMap _myAvatarMarkers; glm::quat _myAvatarRot; glm::vec3 _myAvatarPos; + Rays _rays; }; #endif // hifi_DebugDraw_h diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 53abb3827d..5762122707 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -431,13 +431,23 @@ glm::vec3 transformVectorFull(const glm::mat4& m, const glm::vec3& v) { void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis, glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut) { + // primaryAxis & secondaryAxis must not be zero. + assert(fabsf(glm::length2(primaryAxis) > 0.01f)); + assert(fabsf(glm::length2(secondaryAxis) > 0.01f)); + uAxisOut = glm::normalize(primaryAxis); - wAxisOut = glm::cross(uAxisOut, secondaryAxis); - if (glm::length(wAxisOut) > 0.0f) { - wAxisOut = glm::normalize(wAxisOut); - } else { - wAxisOut = glm::normalize(glm::cross(uAxisOut, glm::vec3(0, 1, 0))); + glm::vec3 normSecondary = glm::normalize(secondaryAxis); + + // if secondaryAxis is parallel with the primaryAxis, pick another axis. + if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > 0.001f) { + // pick a better secondaryAxis. + normSecondary = glm::vec3(1.0f, 0.0f, 0.0f); + if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > 0.001f) { + normSecondary = glm::vec3(0.0f, 1.0f, 0.0f); + } } + + wAxisOut = glm::normalize(glm::cross(uAxisOut, secondaryAxis)); vAxisOut = glm::cross(wAxisOut, uAxisOut); } From cb5c7a35591f6416a37ac631ec0d2acf950a2d13 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 8 May 2016 17:14:14 -0700 Subject: [PATCH 2/5] compile fix for macosx --- libraries/shared/src/DebugDraw.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/DebugDraw.h b/libraries/shared/src/DebugDraw.h index 2d30618afe..f77e281e06 100644 --- a/libraries/shared/src/DebugDraw.h +++ b/libraries/shared/src/DebugDraw.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include From 87d513b5f8c4af2c39c9d0dba1d8f4cc14eb9abb Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 8 May 2016 18:14:18 -0700 Subject: [PATCH 3/5] fixed unused variable warnings --- interface/src/avatar/Avatar.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 14385ddfcb..a78c6635f9 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -427,20 +427,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { float distanceToTarget = glm::length(toTarget); { - // glow when moving far away - const float GLOW_DISTANCE = 20.0f; - const float GLOW_MAX_LOUDNESS = 2500.0f; - const float MAX_GLOW = 0.5f; - - float GLOW_FROM_AVERAGE_LOUDNESS = ((this == DependencyManager::get()->getMyAvatar()) - ? 0.0f - : MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS); - GLOW_FROM_AVERAGE_LOUDNESS = 0.0f; - - float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE - ? 1.0f - : GLOW_FROM_AVERAGE_LOUDNESS; - fixupModelsInScene(); if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { From 7f5296f5664b343d73cdc6c434ce334d0c324844 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 9 May 2016 11:53:09 -0700 Subject: [PATCH 4/5] Increased tolerance for near zero length vectors Also, replaced some magic numbers with constants. --- libraries/shared/src/GLMHelpers.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 5762122707..1f15541758 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -432,17 +432,19 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut) { // primaryAxis & secondaryAxis must not be zero. - assert(fabsf(glm::length2(primaryAxis) > 0.01f)); - assert(fabsf(glm::length2(secondaryAxis) > 0.01f)); + const float MIN_LENGTH_SQUARED = 1.0e-6f; + assert(fabsf(glm::length2(primaryAxis) > MIN_LENGTH_SQUARED)); + assert(fabsf(glm::length2(secondaryAxis) > MIN_LENGTH_SQUARED)); uAxisOut = glm::normalize(primaryAxis); glm::vec3 normSecondary = glm::normalize(secondaryAxis); // if secondaryAxis is parallel with the primaryAxis, pick another axis. - if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > 0.001f) { + const float EPSILON = 1.0e-4f; + if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) { // pick a better secondaryAxis. normSecondary = glm::vec3(1.0f, 0.0f, 0.0f); - if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > 0.001f) { + if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) { normSecondary = glm::vec3(0.0f, 1.0f, 0.0f); } } From 9821c276adcb83c2b732490a393ccbba9005be53 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 9 May 2016 13:56:56 -0700 Subject: [PATCH 5/5] warning fix in release --- libraries/shared/src/GLMHelpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 1f15541758..bd8bffefd2 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -432,7 +432,9 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut) { // primaryAxis & secondaryAxis must not be zero. +#ifndef NDEBUG const float MIN_LENGTH_SQUARED = 1.0e-6f; +#endif assert(fabsf(glm::length2(primaryAxis) > MIN_LENGTH_SQUARED)); assert(fabsf(glm::length2(secondaryAxis) > MIN_LENGTH_SQUARED));