diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d0d01f4534..80231d6342 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -585,6 +585,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // The offscreen UI needs to intercept the mouse and keyboard // events coming from the onscreen window _glWidget->installEventFilter(DependencyManager::get().data()); + + // initialize our face trackers after loading the menu settings + auto faceshiftTracker = DependencyManager::get(); + faceshiftTracker->init(); + connect(faceshiftTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled); + auto ddeTracker = DependencyManager::get(); + ddeTracker->init(); + connect(ddeTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled); } @@ -911,6 +919,12 @@ void Application::audioMuteToggled() { muteAction->setChecked(DependencyManager::get()->isMuted()); } +void Application::faceTrackerMuteToggled() { + QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking); + Q_CHECK_PTR(muteAction); + muteAction->setChecked(getActiveFaceTracker()->isMuted()); +} + void Application::aboutApp() { InfoView::forcedShow(INFO_HELP_PATH); } @@ -1889,17 +1903,29 @@ FaceTracker* Application::getActiveFaceTracker() { } void Application::setActiveFaceTracker() { + bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking); #ifdef HAVE_FACESHIFT - DependencyManager::get()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); + auto faceshiftTracker = DependencyManager::get(); + faceshiftTracker->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); + faceshiftTracker->setIsMuted(isMuted); #endif #ifdef HAVE_DDE bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera); Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE); Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE); - DependencyManager::get()->setEnabled(isUsingDDE); + auto ddeTracker = DependencyManager::get(); + ddeTracker->setEnabled(isUsingDDE); + ddeTracker->setIsMuted(isMuted); #endif } +void Application::toggleFaceTrackerMute() { + FaceTracker* faceTracker = getActiveFaceTracker(); + if (faceTracker) { + faceTracker->toggleMute(); + } +} + bool Application::exportEntities(const QString& filename, const QVector& entityIDs) { QVector entities; @@ -2068,10 +2094,6 @@ void Application::init() { SixenseManager::getInstance().toggleSixense(true); #endif - // initialize our face trackers after loading the menu settings - DependencyManager::get()->init(); - DependencyManager::get()->init(); - Leapmotion::init(); RealSense::init(); @@ -2209,7 +2231,7 @@ void Application::updateMyAvatarLookAtPosition() { isLookingAtSomeone = true; // If I am looking at someone else, look directly at one of their eyes - if (tracker) { + if (tracker && !tracker->isMuted()) { // If a face tracker is active, look at the eye for the side my gaze is biased toward if (tracker->getEstimatedEyeYaw() > _myAvatar->getHead()->getFinalYaw()) { // Look at their right eye @@ -2235,7 +2257,7 @@ void Application::updateMyAvatarLookAtPosition() { // // Deflect the eyes a bit to match the detected Gaze from 3D camera if active // - if (tracker) { + if (tracker && !tracker->isMuted()) { float eyePitch = tracker->getEstimatedEyePitch(); float eyeYaw = tracker->getEstimatedEyeYaw(); const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f; @@ -2290,7 +2312,7 @@ void Application::updateCamera(float deltaTime) { if (!OculusManager::isConnected() && !TV3DManager::isConnected() && Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { FaceTracker* tracker = getActiveFaceTracker(); - if (tracker) { + if (tracker && !tracker->isMuted()) { const float EYE_OFFSET_SCALE = 0.025f; glm::vec3 position = tracker->getHeadTranslation() * EYE_OFFSET_SCALE; float xSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? 1.0f : -1.0f; @@ -2353,7 +2375,7 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("devices"); DeviceTracker::updateAll(); FaceTracker* tracker = getActiveFaceTracker(); - if (tracker) { + if (tracker && !tracker->isMuted()) { tracker->update(deltaTime); } SixenseManager::getInstance().update(deltaTime); diff --git a/interface/src/Application.h b/interface/src/Application.h index 9f87d05711..91bded9267 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -391,6 +391,7 @@ public slots: void resetSensors(); void setActiveFaceTracker(); + void toggleFaceTrackerMute(); void aboutApp(); void showEditEntitiesHelp(); @@ -432,6 +433,7 @@ private slots: void runTests(); void audioMuteToggled(); + void faceTrackerMuteToggled(); void setCursorVisible(bool visible); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 90a9d3b22c..789a1ebb27 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -394,6 +394,12 @@ Menu::Menu() { QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); ddeFiltering->setVisible(false); #endif +#if defined(HAVE_FACESHIFT) || defined(HAVE_DDE) + faceTrackingMenu->addSeparator(); + addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::MuteFaceTracking, + 0, false, + qApp, SLOT(toggleFaceTrackerMute())); +#endif auto avatarManager = DependencyManager::get(); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7d105687ab..a622668742 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -211,6 +211,7 @@ namespace MenuOption { const QString Mirror = "Mirror"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; + const QString MuteFaceTracking = "Mute Face Tracking"; const QString NoFaceTracking = "None"; const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 41c2e9b54c..16cd906133 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -90,7 +90,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { // Only use face trackers when not playing back a recording. if (!myAvatar->isPlaying()) { FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker(); - _isFaceTrackerConnected = faceTracker != NULL; + _isFaceTrackerConnected = faceTracker != NULL && !faceTracker->isMuted(); if (_isFaceTrackerConnected) { _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 557d630ebf..73c2e6a6e8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -243,7 +243,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { estimatedPosition /= OCULUS_LEAN_SCALE; } else { FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); - if (tracker) { + if (tracker && !tracker->isMuted()) { estimatedPosition = tracker->getHeadTranslation(); _trackedHeadPosition = estimatedPosition; estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index b6525ffb52..72c53e5826 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -316,7 +316,13 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const { } void DdeFaceTracker::decodePacket(const QByteArray& buffer) { - if(buffer.size() > MIN_PACKET_SIZE) { + _lastReceiveTimestamp = usecTimestampNow(); + + if (_isMuted) { + return; + } + + if (buffer.size() > MIN_PACKET_SIZE) { bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::VelocityFilter); Packet packet; @@ -328,7 +334,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { memcpy(&translation, packet.translation, sizeof(packet.translation)); glm::quat rotation; memcpy(&rotation, &packet.rotation, sizeof(packet.rotation)); - if (_reset || (_lastReceiveTimestamp == 0)) { + if (_reset || (_lastMessageReceived == 0)) { memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3)); memcpy(&_referenceRotation, &rotation, sizeof(glm::quat)); _reset = false; @@ -503,5 +509,4 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { } else { qCWarning(interfaceapp) << "DDE Face Tracker: Decode error"; } - _lastReceiveTimestamp = usecTimestampNow(); } diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index 0d40249c26..a6351c2d64 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -15,16 +15,22 @@ #include "FaceTracker.h" #include "InterfaceLogging.h" +#include "Menu.h" const int FPS_TIMER_DELAY = 2000; // ms const int FPS_TIMER_DURATION = 2000; // ms FaceTracker::FaceTracker() : _isCalculatingFPS(false), - _frameCount(0) + _frameCount(0), + _isMuted(false) { } +void FaceTracker::init() { + _isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking); +} + inline float FaceTracker::getBlendshapeCoefficient(int index) const { return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient()) : 0.0f; @@ -101,3 +107,8 @@ void FaceTracker::finishFPSTimer() { qCDebug(interfaceapp) << "Face tracker FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f); _isCalculatingFPS = false; } + +void FaceTracker::toggleMute() { + _isMuted = !_isMuted; + emit muteToggled(); +} diff --git a/interface/src/devices/FaceTracker.h b/interface/src/devices/FaceTracker.h index a0a434ee9e..2ffd9f01bf 100644 --- a/interface/src/devices/FaceTracker.h +++ b/interface/src/devices/FaceTracker.h @@ -26,7 +26,7 @@ public: virtual bool isActive() const { return false; } virtual bool isTracking() const { return false; } - virtual void init() {} + virtual void init(); virtual void update(float deltaTime); virtual void reset(); @@ -42,6 +42,13 @@ public: bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); } const QVector& getBlendshapeCoefficients() const; float getBlendshapeCoefficient(int index) const; + + bool isMuted() const { return _isMuted; } + void setIsMuted(bool isMuted) { _isMuted = isMuted; } + void toggleMute(); + +signals: + void muteToggled(); protected: FaceTracker(); @@ -56,6 +63,8 @@ protected: float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f + bool _isMuted; + void countFrame(); private slots: diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 8a0e5a324c..3c3386a076 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -50,6 +50,7 @@ Faceshift::Faceshift() : #ifdef HAVE_FACESHIFT void Faceshift::init() { setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); + FaceTracker::init(); } void Faceshift::update(float deltaTime) { @@ -92,7 +93,7 @@ void Faceshift::reset() { bool Faceshift::isActive() const { const quint64 ACTIVE_TIMEOUT_USECS = 1000000; - return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS; + return (usecTimestampNow() - _lastReceiveTimestamp) < ACTIVE_TIMEOUT_USECS; } bool Faceshift::isTracking() const { @@ -196,6 +197,12 @@ void Faceshift::send(const std::string& message) { void Faceshift::receive(const QByteArray& buffer) { #ifdef HAVE_FACESHIFT + _lastReceiveTimestamp = usecTimestampNow(); + + if (_isMuted) { + return; + } + _stream.received(buffer.size(), buffer.constData()); fsMsgPtr msg; for (fsMsgPtr msg; (msg = _stream.get_message()); ) { @@ -240,11 +247,11 @@ void Faceshift::receive(const QByteArray& buffer) { const float FRAME_AVERAGING_FACTOR = 0.99f; quint64 usecsNow = usecTimestampNow(); - if (_lastTrackingStateReceived != 0) { + if (_lastMessageReceived != 0) { _averageFrameTime = FRAME_AVERAGING_FACTOR * _averageFrameTime + - (1.0f - FRAME_AVERAGING_FACTOR) * (float)(usecsNow - _lastTrackingStateReceived) / 1000000.0f; + (1.0f - FRAME_AVERAGING_FACTOR) * (float)(usecsNow - _lastMessageReceived) / 1000000.0f; } - _lastTrackingStateReceived = usecsNow; + _lastMessageReceived = usecsNow; } break; } diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 3d38af5654..d2d9821382 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -114,7 +114,8 @@ private: bool _tcpEnabled = true; int _tcpRetryCount = 0; bool _tracking = false; - quint64 _lastTrackingStateReceived = 0; + quint64 _lastReceiveTimestamp = 0; + quint64 _lastMessageReceived = 0; float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME; glm::vec3 _headAngularVelocity = glm::vec3(0.0f); diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index a5bc50b288..b9bd195ded 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -161,6 +161,7 @@ public: Mirror, MuteAudio, MuteEnvironment, + MuteFaceTracking, NoFaceTracking, NoShadows, OctreeStats,