Delete legacy blendshape code

Move FaceshiftConstants to BlendshapeConstants.
Delete FaceTracker and DdeFaceTracker classes.
Delete old facetracker menu and preferences
This commit is contained in:
Anthony J. Thibault 2019-10-08 16:08:29 -07:00
parent 8411e6b033
commit da0911e01b
27 changed files with 110 additions and 1510 deletions

View file

@ -211,10 +211,10 @@ endif()
link_hifi_libraries(
shared workload task octree ktx gpu gl procedural graphics graphics-scripting render
pointers recording hfm fbx networking material-networking
model-networking model-baker entities avatars trackers
model-networking model-baker entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer avatars-renderer ui qml auto-updater midi
controllers plugins image trackers platform
controllers plugins image platform
ui-plugins display-plugins input-plugins
# Platform specific GL libraries
${PLATFORM_GL_BACKEND}

View file

@ -170,7 +170,6 @@
#include "avatar/MyCharacterController.h"
#include "CrashRecoveryHandler.h"
#include "CrashHandler.h"
#include "devices/DdeFaceTracker.h"
#include "DiscoverabilityManager.h"
#include "GLCanvas.h"
#include "InterfaceDynamicFactory.h"
@ -887,11 +886,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<ScriptCache>();
DependencyManager::set<SoundCache>();
DependencyManager::set<SoundCacheScriptingInterface>();
#ifdef HAVE_DDE
DependencyManager::set<DdeFaceTracker>();
#endif
DependencyManager::set<AudioClient>();
DependencyManager::set<AudioScope>();
DependencyManager::set<DeferredLightingEffect>();
@ -1067,7 +1061,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_lastSendDownstreamAudioStats(usecTimestampNow()),
_notifiedPacketVersionMismatchThisDomain(false),
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
_lastFaceTrackerUpdate(0),
_snapshotSound(nullptr),
_sampleSound(nullptr)
{
@ -2014,13 +2007,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
this->installEventFilter(this);
#ifdef HAVE_DDE
auto ddeTracker = DependencyManager::get<DdeFaceTracker>();
ddeTracker->init();
connect(ddeTracker.data(), &FaceTracker::muteToggled, this, &Application::faceTrackerMuteToggled);
#endif
// If launched from Steam, let it handle updates
const QString HIFI_NO_UPDATER_COMMAND_LINE_KEY = "--no-updater";
bool noUpdater = arguments().indexOf(HIFI_NO_UPDATER_COMMAND_LINE_KEY) != -1;
@ -2762,9 +2748,6 @@ void Application::cleanupBeforeQuit() {
}
// Stop third party processes so that they're not left running in the event of a subsequent shutdown crash.
#ifdef HAVE_DDE
DependencyManager::get<DdeFaceTracker>()->setEnabled(false);
#endif
AnimDebugDraw::getInstance().shutdown();
// FIXME: once we move to shared pointer for the INputDevice we shoud remove this naked delete:
@ -2835,10 +2818,6 @@ void Application::cleanupBeforeQuit() {
_window->saveGeometry();
// Destroy third party processes after scripts have finished using them.
#ifdef HAVE_DDE
DependencyManager::destroy<DdeFaceTracker>();
#endif
DependencyManager::destroy<ContextOverlayInterface>(); // Must be destroyed before TabletScriptingInterface
// stop QML
@ -3457,9 +3436,6 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
#ifdef HAVE_DDE
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
#endif
surfaceContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data());
surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
@ -3723,16 +3699,6 @@ void Application::runTests() {
runUnitTests();
}
void Application::faceTrackerMuteToggled() {
QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking);
Q_CHECK_PTR(muteAction);
bool isMuted = getSelectedFaceTracker()->isMuted();
muteAction->setChecked(isMuted);
getSelectedFaceTracker()->setEnabled(!isMuted);
Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setEnabled(!isMuted);
}
void Application::setFieldOfView(float fov) {
if (fov != _fieldOfView.get()) {
_fieldOfView.set(fov);
@ -5307,43 +5273,6 @@ ivec2 Application::getMouse() const {
return getApplicationCompositor().getReticlePosition();
}
FaceTracker* Application::getActiveFaceTracker() {
#ifdef HAVE_DDE
auto dde = DependencyManager::get<DdeFaceTracker>();
if (dde && dde->isActive()) {
return static_cast<FaceTracker*>(dde.data());
}
#endif
return nullptr;
}
FaceTracker* Application::getSelectedFaceTracker() {
FaceTracker* faceTracker = nullptr;
#ifdef HAVE_DDE
if (Menu::getInstance()->isOptionChecked(MenuOption::UseCamera)) {
faceTracker = DependencyManager::get<DdeFaceTracker>().data();
}
#endif
return faceTracker;
}
void Application::setActiveFaceTracker() const {
#ifdef HAVE_DDE
bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking);
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera);
Menu::getInstance()->getActionForOption(MenuOption::BinaryEyelidControl)->setVisible(isUsingDDE);
Menu::getInstance()->getActionForOption(MenuOption::CoupleEyelids)->setVisible(isUsingDDE);
Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE);
Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE);
Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setVisible(isUsingDDE);
auto ddeTracker = DependencyManager::get<DdeFaceTracker>();
ddeTracker->setIsMuted(isMuted);
ddeTracker->setEnabled(isUsingDDE && !isMuted);
#endif
}
bool Application::exportEntities(const QString& filename,
const QVector<QUuid>& entityIDs,
const glm::vec3* givenOffset) {
@ -5827,8 +5756,7 @@ void Application::updateMyAvatarLookAtPosition() {
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");
auto myAvatar = getMyAvatar();
FaceTracker* faceTracker = getActiveFaceTracker();
myAvatar->updateLookAtPosition(faceTracker, _myCamera);
myAvatar->updateLookAtPosition(_myCamera);
}
void Application::updateThreads(float deltaTime) {
@ -6254,37 +6182,6 @@ void Application::update(float deltaTime) {
auto myAvatar = getMyAvatar();
{
PerformanceTimer perfTimer("devices");
FaceTracker* tracker = getSelectedFaceTracker();
if (tracker && Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking) != tracker->isMuted()) {
tracker->toggleMute();
}
tracker = getActiveFaceTracker();
if (tracker && !tracker->isMuted()) {
tracker->update(deltaTime);
// Auto-mute microphone after losing face tracking?
if (tracker->isTracking()) {
_lastFaceTrackerUpdate = usecTimestampNow();
} else {
const quint64 MUTE_MICROPHONE_AFTER_USECS = 5000000; //5 secs
Menu* menu = Menu::getInstance();
auto audioClient = DependencyManager::get<AudioClient>();
if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) {
if (_lastFaceTrackerUpdate > 0
&& ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) {
audioClient->setMuted(true);
_lastFaceTrackerUpdate = 0;
}
} else {
_lastFaceTrackerUpdate = 0;
}
}
} else {
_lastFaceTrackerUpdate = 0;
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
controller::HmdAvatarAlignmentType hmdAvatarAlignmentType;
@ -7080,10 +6977,6 @@ void Application::copyDisplayViewFrustum(ViewFrustum& viewOut) const {
// feature. However, we still use this to reset face trackers, eye trackers, audio and to optionally re-load the avatar
// rig and animations from scratch.
void Application::resetSensors(bool andReload) {
#ifdef HAVE_DDE
DependencyManager::get<DdeFaceTracker>()->reset();
#endif
_overlayConductor.centerUI();
getActiveDisplayPlugin()->resetSensors();
getMyAvatar()->reset(true, andReload);
@ -7485,10 +7378,6 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine
scriptEngine->registerGlobalObject("AccountServices", AccountServicesScriptingInterface::getInstance());
qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
#ifdef HAVE_DDE
scriptEngine->registerGlobalObject("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
#endif
scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get<AvatarManager>().data());
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get<LODManager>().data());

View file

@ -81,7 +81,6 @@
#include "VisionSqueeze.h"
class GLCanvas;
class FaceTracker;
class MainWindow;
class AssetUpload;
class CompositorHelper;
@ -191,9 +190,6 @@ public:
ivec2 getMouse() const;
FaceTracker* getActiveFaceTracker();
FaceTracker* getSelectedFaceTracker();
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }
CompositorHelper& getApplicationCompositor() const;
@ -423,7 +419,6 @@ public slots:
static void packageModel();
void resetSensors(bool andReload = false);
void setActiveFaceTracker() const;
void hmdVisibleChanged(bool visible);
@ -497,8 +492,6 @@ private slots:
void resettingDomain();
void faceTrackerMuteToggled();
void activeChanged(Qt::ApplicationState state);
void windowMinimizedChanged(bool minimized);
@ -736,8 +729,6 @@ private:
PerformanceManager _performanceManager;
RefreshRateManager _refreshRateManager;
quint64 _lastFaceTrackerUpdate;
GameWorkload _gameWorkload;
GraphicsEngine _graphicsEngine;

View file

@ -37,7 +37,6 @@
#include "avatar/AvatarManager.h"
#include "avatar/AvatarPackager.h"
#include "AvatarBookmarks.h"
#include "devices/DdeFaceTracker.h"
#include "MainWindow.h"
#include "render/DrawStatus.h"
#include "scripting/MenuScriptingInterface.h"
@ -493,47 +492,6 @@ Menu::Menu() {
// Developer > Avatar >>>
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
// Developer > Avatar > Face Tracking
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
{
QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu);
bool defaultNoFaceTracking = true;
#ifdef HAVE_DDE
defaultNoFaceTracking = false;
#endif
QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking,
0, defaultNoFaceTracking,
qApp, SLOT(setActiveFaceTracker()));
faceTrackerGroup->addAction(noFaceTracker);
#ifdef HAVE_DDE
QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseCamera,
0, true,
qApp, SLOT(setActiveFaceTracker()));
faceTrackerGroup->addAction(ddeFaceTracker);
#endif
}
#ifdef HAVE_DDE
faceTrackingMenu->addSeparator();
QAction* binaryEyelidControl = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::BinaryEyelidControl, 0, true);
binaryEyelidControl->setVisible(true); // DDE face tracking is on by default
QAction* coupleEyelids = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::CoupleEyelids, 0, true);
coupleEyelids->setVisible(true); // DDE face tracking is on by default
QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true);
useAudioForMouth->setVisible(true); // DDE face tracking is on by default
QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true);
ddeFiltering->setVisible(true); // DDE face tracking is on by default
QAction* ddeCalibrate = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::CalibrateCamera, 0,
DependencyManager::get<DdeFaceTracker>().data(), SLOT(calibrate()));
ddeCalibrate->setVisible(true); // DDE face tracking is on by default
faceTrackingMenu->addSeparator();
addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::MuteFaceTracking,
[](bool mute) { FaceTracker::setIsMuted(mute); },
Qt::CTRL | Qt::SHIFT | Qt::Key_F, FaceTracker::isMuted());
addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::AutoMuteAudio, 0, false);
#endif
action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false);
connect(action, &QAction::triggered, [this]{ Avatar::setShowReceiveStats(isOptionChecked(MenuOption::AvatarReceiveStats)); });
action = addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowBoundingCollisionShapes, 0, false);

View file

@ -48,7 +48,6 @@
#include <recording/Clip.h>
#include <recording/Frame.h>
#include <RecordingScriptingInterface.h>
#include <trackers/FaceTracker.h>
#include <RenderableModelEntityItem.h>
#include <VariantMapToScriptValue.h>
@ -749,7 +748,6 @@ void MyAvatar::update(float deltaTime) {
Head* head = getHead();
head->relax(deltaTime);
updateFromTrackers(deltaTime);
if (getIsInWalkingState() && glm::length(getControllerPoseInAvatarFrame(controller::Action::HEAD).getVelocity()) < DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) {
setIsInWalkingState(false);
@ -1140,60 +1138,6 @@ void MyAvatar::updateSensorToWorldMatrix() {
}
// Update avatar head rotation with sensor data
void MyAvatar::updateFromTrackers(float deltaTime) {
glm::vec3 estimatedRotation;
bool hasHead = getControllerPoseInAvatarFrame(controller::Action::HEAD).isValid();
bool playing = DependencyManager::get<recording::Deck>()->isPlaying();
if (hasHead && playing) {
return;
}
FaceTracker* tracker = qApp->getActiveFaceTracker();
bool inFacetracker = tracker && !FaceTracker::isMuted();
if (inFacetracker) {
estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
}
// Rotate the body if the head is turned beyond the screen
if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
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 (estimatedRotation.y > 0.0f) {
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
} else {
_bodyYawDelta += (estimatedRotation.y + TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
}
}
}
// Set the rotation of the avatar's head (as seen by others, not affecting view frustum)
// to be scaled such that when the user's physical head is pointing at edge of screen, the
// avatar head is at the edge of the in-world view frustum. So while a real person may move
// 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 (hasHead || playing) {
head->setDeltaPitch(estimatedRotation.x);
head->setDeltaYaw(estimatedRotation.y);
head->setDeltaRoll(estimatedRotation.z);
} else {
ViewFrustum viewFrustum;
qApp->copyViewFrustum(viewFrustum);
float magnifyFieldOfView = viewFrustum.getFieldOfView() / _realWorldFieldOfView.get();
head->setDeltaPitch(estimatedRotation.x * magnifyFieldOfView);
head->setDeltaYaw(estimatedRotation.y * magnifyFieldOfView);
head->setDeltaRoll(estimatedRotation.z);
}
}
glm::vec3 MyAvatar::getLeftHandPosition() const {
auto pose = getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
@ -6585,7 +6529,7 @@ bool MyAvatar::getIsJointOverridden(int jointIndex) const {
return _skeletonModel->getIsJointOverridden(jointIndex);
}
void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera) {
void MyAvatar::updateLookAtPosition(Camera& myCamera) {
updateLookAtTargetAvatar();
@ -6681,21 +6625,6 @@ void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera)
(getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
}
}
// Deflect the eyes a bit to match the detected gaze from the face tracker if active.
if (faceTracker && !faceTracker->isMuted()) {
float eyePitch = faceTracker->getEstimatedEyePitch();
float eyeYaw = faceTracker->getEstimatedEyeYaw();
const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f;
glm::vec3 origin = myHead->getEyePosition();
float deflection = faceTracker->getEyeDeflection();
if (isLookingAtSomeone) {
deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT;
}
lookAtSpot = origin + myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3(
eyePitch * deflection, eyeYaw * deflection, 0.0f))) *
glm::inverse(myCamera.getOrientation()) * (lookAtSpot - origin);
}
}
}

View file

@ -34,7 +34,6 @@
#include "AtRestDetector.h"
#include "MyCharacterController.h"
#include "RingBufferHistory.h"
#include "devices/DdeFaceTracker.h"
class AvatarActionHold;
class ModelItemID;
@ -1899,7 +1898,7 @@ public:
bool getFlowActive() const;
bool getNetworkGraphActive() const;
void updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera);
void updateLookAtPosition(Camera& myCamera);
// sets the reaction enabled and triggered parameters of the passed in params
// also clears internal reaction triggers
@ -2542,7 +2541,6 @@ private:
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) override;
void simulate(float deltaTime, bool inView) override;
void updateFromTrackers(float deltaTime);
void saveAvatarUrl();
virtual void render(RenderArgs* renderArgs) override;
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override;

View file

@ -14,10 +14,8 @@
#include <NodeList.h>
#include <recording/Deck.h>
#include <Rig.h>
#include <trackers/FaceTracker.h>
#include <FaceshiftConstants.h>
#include <BlendshapeConstants.h>
#include "devices/DdeFaceTracker.h"
#include "Application.h"
#include "MyAvatar.h"

View file

@ -1,686 +0,0 @@
//
// DdeFaceTracker.cpp
//
//
// Created by Clement on 8/2/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "DdeFaceTracker.h"
#include <SharedUtil.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtCore/QTimer>
#include <GLMHelpers.h>
#include <NumericalConstants.h>
#include <FaceshiftConstants.h>
#include "Application.h"
#include "InterfaceLogging.h"
#include "Menu.h"
static const QHostAddress DDE_SERVER_ADDR("127.0.0.1");
static const quint16 DDE_SERVER_PORT = 64204;
static const quint16 DDE_CONTROL_PORT = 64205;
#if defined(Q_OS_WIN)
static const QString DDE_PROGRAM_PATH = "/dde/dde.exe";
#elif defined(Q_OS_MAC)
static const QString DDE_PROGRAM_PATH = "/dde.app/Contents/MacOS/dde";
#endif
static const QStringList DDE_ARGUMENTS = QStringList()
<< "--udp=" + DDE_SERVER_ADDR.toString() + ":" + QString::number(DDE_SERVER_PORT)
<< "--receiver=" + QString::number(DDE_CONTROL_PORT)
<< "--facedet_interval=500" // ms
<< "--headless";
static const int NUM_EXPRESSIONS = 46;
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int);
static const int MAX_NAME_SIZE = 31;
// There's almost but not quite a 1-1 correspondence between DDE's 46 and Faceshift 1.3's 48 packets.
// The best guess at mapping is to:
// - Swap L and R values
// - Skip two Faceshift values: JawChew (22) and LipsLowerDown (37)
static const int DDE_TO_FACESHIFT_MAPPING[] = {
1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
16,
18, 17,
19,
23,
21,
// Skip JawChew
20,
25, 24, 27, 26, 29, 28, 31, 30, 33, 32,
34, 35, 36,
// Skip LipsLowerDown
38, 39, 40, 41, 42, 43, 44, 45,
47, 46
};
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
// less than this.
static const float DDE_COEFFICIENT_SCALES[] = {
1.0f, // EyeBlink_L
1.0f, // EyeBlink_R
1.0f, // EyeSquint_L
1.0f, // EyeSquint_R
1.0f, // EyeDown_L
1.0f, // EyeDown_R
1.0f, // EyeIn_L
1.0f, // EyeIn_R
1.0f, // EyeOpen_L
1.0f, // EyeOpen_R
1.0f, // EyeOut_L
1.0f, // EyeOut_R
1.0f, // EyeUp_L
1.0f, // EyeUp_R
3.0f, // BrowsD_L
3.0f, // BrowsD_R
3.0f, // BrowsU_C
3.0f, // BrowsU_L
3.0f, // BrowsU_R
1.0f, // JawFwd
2.0f, // JawLeft
1.8f, // JawOpen
1.0f, // JawChew
2.0f, // JawRight
1.5f, // MouthLeft
1.5f, // MouthRight
1.5f, // MouthFrown_L
1.5f, // MouthFrown_R
2.5f, // MouthSmile_L
2.5f, // MouthSmile_R
1.0f, // MouthDimple_L
1.0f, // MouthDimple_R
1.0f, // LipsStretch_L
1.0f, // LipsStretch_R
1.0f, // LipsUpperClose
1.0f, // LipsLowerClose
1.0f, // LipsUpperUp
1.0f, // LipsLowerDown
1.0f, // LipsUpperOpen
1.0f, // LipsLowerOpen
1.5f, // LipsFunnel
2.5f, // LipsPucker
1.5f, // ChinLowerRaise
1.5f, // ChinUpperRaise
1.0f, // Sneer
3.0f, // Puff
1.0f, // CheekSquint_L
1.0f // CheekSquint_R
};
struct DDEPacket {
//roughly in mm
float focal_length[1];
float translation[3];
//quaternion
float rotation[4];
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
// less than this.
float expressions[NUM_EXPRESSIONS];
//avatar id selected on the UI
int avatar_id;
//client name, arbitrary length
char name[MAX_NAME_SIZE + 1];
};
static const float STARTING_DDE_MESSAGE_TIME = 0.033f;
static const float DEFAULT_DDE_EYE_CLOSING_THRESHOLD = 0.8f;
static const int CALIBRATION_SAMPLES = 150;
DdeFaceTracker::DdeFaceTracker() :
DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT)
{
}
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) :
_ddeProcess(NULL),
_ddeStopping(false),
_host(host),
_serverPort(serverPort),
_controlPort(controlPort),
_lastReceiveTimestamp(0),
_reset(false),
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
_rightBlinkIndex(1),
_leftEyeDownIndex(4),
_rightEyeDownIndex(5),
_leftEyeInIndex(6),
_rightEyeInIndex(7),
_leftEyeOpenIndex(8),
_rightEyeOpenIndex(9),
_browDownLeftIndex(14),
_browDownRightIndex(15),
_browUpCenterIndex(16),
_browUpLeftIndex(17),
_browUpRightIndex(18),
_mouthSmileLeftIndex(28),
_mouthSmileRightIndex(29),
_jawOpenIndex(21),
_lastMessageReceived(0),
_averageMessageTime(STARTING_DDE_MESSAGE_TIME),
_lastHeadTranslation(glm::vec3(0.0f)),
_filteredHeadTranslation(glm::vec3(0.0f)),
_lastBrowUp(0.0f),
_filteredBrowUp(0.0f),
_eyePitch(0.0f),
_eyeYaw(0.0f),
_lastEyePitch(0.0f),
_lastEyeYaw(0.0f),
_filteredEyePitch(0.0f),
_filteredEyeYaw(0.0f),
_longTermAverageEyePitch(0.0f),
_longTermAverageEyeYaw(0.0f),
_lastEyeBlinks(),
_filteredEyeBlinks(),
_lastEyeCoefficients(),
_eyeClosingThreshold("ddeEyeClosingThreshold", DEFAULT_DDE_EYE_CLOSING_THRESHOLD),
_isCalibrating(false),
_calibrationCount(0),
_calibrationValues(),
_calibrationBillboard(NULL),
_calibrationMessage(QString()),
_isCalibrated(false)
{
_coefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
_blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
_coefficientAverages.resize(NUM_FACESHIFT_BLENDSHAPES);
_calibrationValues.resize(NUM_FACESHIFT_BLENDSHAPES);
_eyeStates[0] = EYE_UNCONTROLLED;
_eyeStates[1] = EYE_UNCONTROLLED;
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError)));
connect(&_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(socketStateChanged(QAbstractSocket::SocketState)));
}
DdeFaceTracker::~DdeFaceTracker() {
setEnabled(false);
if (_isCalibrating) {
cancelCalibration();
}
}
void DdeFaceTracker::init() {
FaceTracker::init();
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::UseCamera) && !_isMuted);
Menu::getInstance()->getActionForOption(MenuOption::CalibrateCamera)->setEnabled(!_isMuted);
}
void DdeFaceTracker::setEnabled(bool enabled) {
if (!_isInitialized) {
// Don't enable until have explicitly initialized
return;
}
#ifdef HAVE_DDE
if (_isCalibrating) {
cancelCalibration();
}
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
_udpSocket.close();
// Terminate any existing DDE process, perhaps left running after an Interface crash.
// Do this even if !enabled in case user reset their settings after crash.
const char* DDE_EXIT_COMMAND = "exit";
_udpSocket.bind(_host, _serverPort);
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
if (enabled && !_ddeProcess) {
_ddeStopping = false;
qCDebug(interfaceapp) << "DDE Face Tracker: Starting";
_ddeProcess = new QProcess(qApp);
connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS);
}
if (!enabled && _ddeProcess) {
_ddeStopping = true;
qCDebug(interfaceapp) << "DDE Face Tracker: Stopping";
}
#endif
}
void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
if (_ddeProcess) {
if (_ddeStopping) {
qCDebug(interfaceapp) << "DDE Face Tracker: Stopped";
} else {
qCWarning(interfaceapp) << "DDE Face Tracker: Stopped unexpectedly";
Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true);
}
_udpSocket.close();
delete _ddeProcess;
_ddeProcess = NULL;
}
}
void DdeFaceTracker::reset() {
if (_udpSocket.state() == QAbstractSocket::BoundState) {
_reset = true;
qCDebug(interfaceapp) << "DDE Face Tracker: Reset";
const char* DDE_RESET_COMMAND = "reset";
_udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort);
FaceTracker::reset();
_reset = true;
}
}
void DdeFaceTracker::update(float deltaTime) {
if (!isActive()) {
return;
}
FaceTracker::update(deltaTime);
glm::vec3 headEulers = glm::degrees(glm::eulerAngles(_headRotation));
_estimatedEyePitch = _eyePitch - headEulers.x;
_estimatedEyeYaw = _eyeYaw - headEulers.y;
}
bool DdeFaceTracker::isActive() const {
return (_ddeProcess != NULL);
}
bool DdeFaceTracker::isTracking() const {
static const quint64 ACTIVE_TIMEOUT_USECS = 3000000; //3 secs
return (usecTimestampNow() - _lastReceiveTimestamp < ACTIVE_TIMEOUT_USECS);
}
//private slots and methods
void DdeFaceTracker::socketErrorOccurred(QAbstractSocket::SocketError socketError) {
qCWarning(interfaceapp) << "DDE Face Tracker: Socket error: " << _udpSocket.errorString();
}
void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState) {
QString state;
switch(socketState) {
case QAbstractSocket::BoundState:
state = "Bound";
break;
case QAbstractSocket::ClosingState:
state = "Closing";
break;
case QAbstractSocket::ConnectedState:
state = "Connected";
break;
case QAbstractSocket::ConnectingState:
state = "Connecting";
break;
case QAbstractSocket::HostLookupState:
state = "Host Lookup";
break;
case QAbstractSocket::ListeningState:
state = "Listening";
break;
case QAbstractSocket::UnconnectedState:
state = "Unconnected";
break;
}
qCDebug(interfaceapp) << "DDE Face Tracker: Socket: " << state;
}
void DdeFaceTracker::readPendingDatagrams() {
QByteArray buffer;
while (_udpSocket.hasPendingDatagrams()) {
buffer.resize(_udpSocket.pendingDatagramSize());
_udpSocket.readDatagram(buffer.data(), buffer.size());
}
decodePacket(buffer);
}
float DdeFaceTracker::getBlendshapeCoefficient(int index) const {
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
}
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
_lastReceiveTimestamp = usecTimestampNow();
if (buffer.size() > MIN_PACKET_SIZE) {
if (!_isCalibrated) {
calibrate();
}
bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::VelocityFilter);
DDEPacket packet;
int bytesToCopy = glm::min((int)sizeof(packet), buffer.size());
memset(&packet.name, '\n', MAX_NAME_SIZE + 1);
memcpy(&packet, buffer.data(), bytesToCopy);
glm::vec3 translation;
memcpy(&translation, packet.translation, sizeof(packet.translation));
glm::quat rotation;
memcpy(&rotation, &packet.rotation, sizeof(packet.rotation));
if (_reset || (_lastMessageReceived == 0)) {
memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
_reset = false;
}
// Compute relative translation
float LEAN_DAMPING_FACTOR = 75.0f;
translation -= _referenceTranslation;
translation /= LEAN_DAMPING_FACTOR;
translation.x *= -1;
if (isFiltering) {
glm::vec3 linearVelocity = (translation - _lastHeadTranslation) / _averageMessageTime;
const float LINEAR_VELOCITY_FILTER_STRENGTH = 0.3f;
float velocityFilter = glm::clamp(1.0f - glm::length(linearVelocity) *
LINEAR_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
_filteredHeadTranslation = velocityFilter * _filteredHeadTranslation + (1.0f - velocityFilter) * translation;
_lastHeadTranslation = translation;
_headTranslation = _filteredHeadTranslation;
} else {
_headTranslation = translation;
}
// Compute relative rotation
rotation = glm::inverse(_referenceRotation) * rotation;
if (isFiltering) {
glm::quat r = glm::normalize(rotation * glm::inverse(_headRotation));
float theta = 2 * acos(r.w);
glm::vec3 angularVelocity;
if (theta > EPSILON) {
float rMag = glm::length(glm::vec3(r.x, r.y, r.z));
angularVelocity = theta / _averageMessageTime * glm::vec3(r.x, r.y, r.z) / rMag;
} else {
angularVelocity = glm::vec3(0, 0, 0);
}
const float ANGULAR_VELOCITY_FILTER_STRENGTH = 0.3f;
_headRotation = safeMix(_headRotation, rotation, glm::clamp(glm::length(angularVelocity) *
ANGULAR_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f));
} else {
_headRotation = rotation;
}
// Translate DDE coefficients to Faceshift compatible coefficients
for (int i = 0; i < NUM_EXPRESSIONS; i++) {
_coefficients[DDE_TO_FACESHIFT_MAPPING[i]] = packet.expressions[i];
}
// Calibration
if (_isCalibrating) {
addCalibrationDatum();
}
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
_coefficients[i] -= _coefficientAverages[i];
}
// Use BrowsU_C to control both brows' up and down
float browUp = _coefficients[_browUpCenterIndex];
if (isFiltering) {
const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f;
float velocity = fabsf(browUp - _lastBrowUp) / _averageMessageTime;
float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
_filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp;
_lastBrowUp = browUp;
browUp = _filteredBrowUp;
_coefficients[_browUpCenterIndex] = browUp;
}
_coefficients[_browUpLeftIndex] = browUp;
_coefficients[_browUpRightIndex] = browUp;
_coefficients[_browDownLeftIndex] = -browUp;
_coefficients[_browDownRightIndex] = -browUp;
// Offset jaw open coefficient
static const float JAW_OPEN_THRESHOLD = 0.1f;
_coefficients[_jawOpenIndex] = _coefficients[_jawOpenIndex] - JAW_OPEN_THRESHOLD;
// Offset smile coefficients
static const float SMILE_THRESHOLD = 0.5f;
_coefficients[_mouthSmileLeftIndex] = _coefficients[_mouthSmileLeftIndex] - SMILE_THRESHOLD;
_coefficients[_mouthSmileRightIndex] = _coefficients[_mouthSmileRightIndex] - SMILE_THRESHOLD;
// Eye pitch and yaw
// EyeDown coefficients work better over both +ve and -ve values than EyeUp values.
// EyeIn coefficients work better over both +ve and -ve values than EyeOut values.
// Pitch and yaw values are relative to the screen.
const float EYE_PITCH_SCALE = -1500.0f; // Sign, scale, and average to be similar to Faceshift values.
_eyePitch = EYE_PITCH_SCALE * (_coefficients[_leftEyeDownIndex] + _coefficients[_rightEyeDownIndex]);
const float EYE_YAW_SCALE = 2000.0f; // Scale and average to be similar to Faceshift values.
_eyeYaw = EYE_YAW_SCALE * (_coefficients[_leftEyeInIndex] + _coefficients[_rightEyeInIndex]);
if (isFiltering) {
const float EYE_VELOCITY_FILTER_STRENGTH = 0.005f;
float pitchVelocity = fabsf(_eyePitch - _lastEyePitch) / _averageMessageTime;
float pitchVelocityFilter = glm::clamp(pitchVelocity * EYE_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
_filteredEyePitch = pitchVelocityFilter * _eyePitch + (1.0f - pitchVelocityFilter) * _filteredEyePitch;
_lastEyePitch = _eyePitch;
_eyePitch = _filteredEyePitch;
float yawVelocity = fabsf(_eyeYaw - _lastEyeYaw) / _averageMessageTime;
float yawVelocityFilter = glm::clamp(yawVelocity * EYE_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
_filteredEyeYaw = yawVelocityFilter * _eyeYaw + (1.0f - yawVelocityFilter) * _filteredEyeYaw;
_lastEyeYaw = _eyeYaw;
_eyeYaw = _filteredEyeYaw;
}
// Velocity filter EyeBlink values
const float DDE_EYEBLINK_SCALE = 3.0f;
float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex],
DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] };
if (isFiltering) {
const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f;
for (int i = 0; i < 2; i++) {
float velocity = fabsf(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime;
float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
_filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i];
_lastEyeBlinks[i] = eyeBlinks[i];
}
}
// Finesse EyeBlink values
float eyeCoefficients[2];
if (Menu::getInstance()->isOptionChecked(MenuOption::BinaryEyelidControl)) {
if (_eyeStates[0] == EYE_UNCONTROLLED) {
_eyeStates[0] = EYE_OPEN;
_eyeStates[1] = EYE_OPEN;
}
for (int i = 0; i < 2; i++) {
// Scale EyeBlink values so that they can be used to control both EyeBlink and EyeOpen
// -ve values control EyeOpen; +ve values control EyeBlink
static const float EYE_CONTROL_THRESHOLD = 0.5f; // Resting eye value
eyeCoefficients[i] = (_filteredEyeBlinks[i] - EYE_CONTROL_THRESHOLD) / (1.0f - EYE_CONTROL_THRESHOLD);
// Change to closing or opening states
const float EYE_CONTROL_HYSTERISIS = 0.25f;
float eyeClosingThreshold = getEyeClosingThreshold();
float eyeOpeningThreshold = eyeClosingThreshold - EYE_CONTROL_HYSTERISIS;
if ((_eyeStates[i] == EYE_OPEN || _eyeStates[i] == EYE_OPENING) && eyeCoefficients[i] > eyeClosingThreshold) {
_eyeStates[i] = EYE_CLOSING;
} else if ((_eyeStates[i] == EYE_CLOSED || _eyeStates[i] == EYE_CLOSING)
&& eyeCoefficients[i] < eyeOpeningThreshold) {
_eyeStates[i] = EYE_OPENING;
}
const float EYELID_MOVEMENT_RATE = 10.0f; // units/second
const float EYE_OPEN_SCALE = 0.2f;
if (_eyeStates[i] == EYE_CLOSING) {
// Close eyelid until it's fully closed
float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime;
if (closingValue >= 1.0f) {
_eyeStates[i] = EYE_CLOSED;
eyeCoefficients[i] = 1.0f;
} else {
eyeCoefficients[i] = closingValue;
}
} else if (_eyeStates[i] == EYE_OPENING) {
// Open eyelid until it meets the current adjusted value
float openingValue = _lastEyeCoefficients[i] - EYELID_MOVEMENT_RATE * _averageMessageTime;
if (openingValue < eyeCoefficients[i] * EYE_OPEN_SCALE) {
_eyeStates[i] = EYE_OPEN;
eyeCoefficients[i] = eyeCoefficients[i] * EYE_OPEN_SCALE;
} else {
eyeCoefficients[i] = openingValue;
}
} else if (_eyeStates[i] == EYE_OPEN) {
// Reduce eyelid movement
eyeCoefficients[i] = eyeCoefficients[i] * EYE_OPEN_SCALE;
} else if (_eyeStates[i] == EYE_CLOSED) {
// Keep eyelid fully closed
eyeCoefficients[i] = 1.0;
}
}
if (_eyeStates[0] == EYE_OPEN && _eyeStates[1] == EYE_OPEN) {
// Couple eyelids
eyeCoefficients[0] = eyeCoefficients[1] = (eyeCoefficients[0] + eyeCoefficients[0]) / 2.0f;
}
_lastEyeCoefficients[0] = eyeCoefficients[0];
_lastEyeCoefficients[1] = eyeCoefficients[1];
} else {
_eyeStates[0] = EYE_UNCONTROLLED;
_eyeStates[1] = EYE_UNCONTROLLED;
eyeCoefficients[0] = _filteredEyeBlinks[0];
eyeCoefficients[1] = _filteredEyeBlinks[1];
}
// Couple eyelid values if configured - use the most "open" value for both
if (Menu::getInstance()->isOptionChecked(MenuOption::CoupleEyelids)) {
float eyeCoefficient = std::min(eyeCoefficients[0], eyeCoefficients[1]);
eyeCoefficients[0] = eyeCoefficient;
eyeCoefficients[1] = eyeCoefficient;
}
// Use EyeBlink values to control both EyeBlink and EyeOpen
if (eyeCoefficients[0] > 0) {
_coefficients[_leftBlinkIndex] = eyeCoefficients[0];
_coefficients[_leftEyeOpenIndex] = 0.0f;
} else {
_coefficients[_leftBlinkIndex] = 0.0f;
_coefficients[_leftEyeOpenIndex] = -eyeCoefficients[0];
}
if (eyeCoefficients[1] > 0) {
_coefficients[_rightBlinkIndex] = eyeCoefficients[1];
_coefficients[_rightEyeOpenIndex] = 0.0f;
} else {
_coefficients[_rightBlinkIndex] = 0.0f;
_coefficients[_rightEyeOpenIndex] = -eyeCoefficients[1];
}
// Scale all coefficients
for (int i = 0; i < NUM_EXPRESSIONS; i++) {
_blendshapeCoefficients[i]
= glm::clamp(DDE_COEFFICIENT_SCALES[i] * _coefficients[i], 0.0f, 1.0f);
}
// Calculate average frame time
const float FRAME_AVERAGING_FACTOR = 0.99f;
quint64 usecsNow = usecTimestampNow();
if (_lastMessageReceived != 0) {
_averageMessageTime = FRAME_AVERAGING_FACTOR * _averageMessageTime
+ (1.0f - FRAME_AVERAGING_FACTOR) * (float)(usecsNow - _lastMessageReceived) / 1000000.0f;
}
_lastMessageReceived = usecsNow;
FaceTracker::countFrame();
} else {
qCWarning(interfaceapp) << "DDE Face Tracker: Decode error";
}
if (_isCalibrating && _calibrationCount > CALIBRATION_SAMPLES) {
finishCalibration();
}
}
void DdeFaceTracker::setEyeClosingThreshold(float eyeClosingThreshold) {
_eyeClosingThreshold.set(eyeClosingThreshold);
}
static const int CALIBRATION_BILLBOARD_WIDTH = 300;
static const int CALIBRATION_BILLBOARD_HEIGHT = 120;
static QString CALIBRATION_INSTRUCTION_MESSAGE = "Hold still to calibrate camera";
void DdeFaceTracker::calibrate() {
if (!Menu::getInstance()->isOptionChecked(MenuOption::UseCamera) || _isMuted) {
return;
}
if (!_isCalibrating) {
qCDebug(interfaceapp) << "DDE Face Tracker: Calibration started";
_isCalibrating = true;
_calibrationCount = 0;
_calibrationMessage = CALIBRATION_INSTRUCTION_MESSAGE + "\n\n";
// FIXME: this overlay probably doesn't work anymore
_calibrationBillboard = new TextOverlay();
glm::vec2 viewport = qApp->getCanvasSize();
_calibrationBillboard->setX((viewport.x - CALIBRATION_BILLBOARD_WIDTH) / 2);
_calibrationBillboard->setY((viewport.y - CALIBRATION_BILLBOARD_HEIGHT) / 2);
_calibrationBillboard->setWidth(CALIBRATION_BILLBOARD_WIDTH);
_calibrationBillboard->setHeight(CALIBRATION_BILLBOARD_HEIGHT);
_calibrationBillboardID = qApp->getOverlays().addOverlay(_calibrationBillboard);
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
_calibrationValues[i] = 0.0f;
}
}
}
void DdeFaceTracker::addCalibrationDatum() {
const int LARGE_TICK_INTERVAL = 30;
const int SMALL_TICK_INTERVAL = 6;
int samplesLeft = CALIBRATION_SAMPLES - _calibrationCount;
if (samplesLeft % LARGE_TICK_INTERVAL == 0) {
_calibrationMessage += QString::number(samplesLeft / LARGE_TICK_INTERVAL);
// FIXME: set overlay text
} else if (samplesLeft % SMALL_TICK_INTERVAL == 0) {
_calibrationMessage += ".";
// FIXME: set overlay text
}
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
_calibrationValues[i] += _coefficients[i];
}
_calibrationCount += 1;
}
void DdeFaceTracker::cancelCalibration() {
qApp->getOverlays().deleteOverlay(_calibrationBillboardID);
_calibrationBillboard = NULL;
_isCalibrating = false;
qCDebug(interfaceapp) << "DDE Face Tracker: Calibration cancelled";
}
void DdeFaceTracker::finishCalibration() {
qApp->getOverlays().deleteOverlay(_calibrationBillboardID);
_calibrationBillboard = NULL;
_isCalibrating = false;
_isCalibrated = true;
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
_coefficientAverages[i] = _calibrationValues[i] / (float)CALIBRATION_SAMPLES;
}
reset();
qCDebug(interfaceapp) << "DDE Face Tracker: Calibration finished";
}

View file

@ -1,181 +0,0 @@
//
// DdeFaceTracker.h
//
//
// Created by Clement on 8/2/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_DdeFaceTracker_h
#define hifi_DdeFaceTracker_h
#include <QtCore/QtGlobal>
//Disabling dde due to random crashes with closing the socket on macos. all the accompanying code is wrapped with the ifdef HAVE_DDE. uncomment the define below to enable
#if defined(Q_OS_WIN) || defined(Q_OS_OSX)
//#define HAVE_DDE
#endif
#include <QProcess>
#include <QUdpSocket>
#include <DependencyManager.h>
#include <ui/overlays/TextOverlay.h>
#include <trackers/FaceTracker.h>
/**jsdoc
* The FaceTracker API helps manage facial tracking hardware.
* @namespace FaceTracker
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class DdeFaceTracker : public FaceTracker, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
virtual void init() override;
virtual void reset() override;
virtual void update(float deltaTime) override;
virtual bool isActive() const override;
virtual bool isTracking() const override;
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
float getLeftEyeOpen() const { return getBlendshapeCoefficient(_leftEyeOpenIndex); }
float getRightEyeOpen() const { return getBlendshapeCoefficient(_rightEyeOpenIndex); }
float getBrowDownLeft() const { return getBlendshapeCoefficient(_browDownLeftIndex); }
float getBrowDownRight() const { return getBlendshapeCoefficient(_browDownRightIndex); }
float getBrowUpCenter() const { return getBlendshapeCoefficient(_browUpCenterIndex); }
float getBrowUpLeft() const { return getBlendshapeCoefficient(_browUpLeftIndex); }
float getBrowUpRight() const { return getBlendshapeCoefficient(_browUpRightIndex); }
float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); }
float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); }
float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); }
float getEyeClosingThreshold() { return _eyeClosingThreshold.get(); }
void setEyeClosingThreshold(float eyeClosingThreshold);
public slots:
/**jsdoc
* @function FaceTracker.setEnabled
* @param {boolean} enabled
*/
void setEnabled(bool enabled) override;
/**jsdoc
* @function FaceTracker.calibrate
*/
void calibrate();
private slots:
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
//sockets
void socketErrorOccurred(QAbstractSocket::SocketError socketError);
void readPendingDatagrams();
void socketStateChanged(QAbstractSocket::SocketState socketState);
private:
DdeFaceTracker();
DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort);
virtual ~DdeFaceTracker();
QProcess* _ddeProcess;
bool _ddeStopping;
QHostAddress _host;
quint16 _serverPort;
quint16 _controlPort;
float getBlendshapeCoefficient(int index) const;
void decodePacket(const QByteArray& buffer);
// sockets
QUdpSocket _udpSocket;
quint64 _lastReceiveTimestamp;
bool _reset;
glm::vec3 _referenceTranslation;
glm::quat _referenceRotation;
int _leftBlinkIndex;
int _rightBlinkIndex;
int _leftEyeDownIndex;
int _rightEyeDownIndex;
int _leftEyeInIndex;
int _rightEyeInIndex;
int _leftEyeOpenIndex;
int _rightEyeOpenIndex;
int _browDownLeftIndex;
int _browDownRightIndex;
int _browUpCenterIndex;
int _browUpLeftIndex;
int _browUpRightIndex;
int _mouthSmileLeftIndex;
int _mouthSmileRightIndex;
int _jawOpenIndex;
QVector<float> _coefficients;
quint64 _lastMessageReceived;
float _averageMessageTime;
glm::vec3 _lastHeadTranslation;
glm::vec3 _filteredHeadTranslation;
float _lastBrowUp;
float _filteredBrowUp;
float _eyePitch; // Degrees, relative to screen
float _eyeYaw;
float _lastEyePitch;
float _lastEyeYaw;
float _filteredEyePitch;
float _filteredEyeYaw;
float _longTermAverageEyePitch = 0.0f;
float _longTermAverageEyeYaw = 0.0f;
bool _longTermAverageInitialized = false;
enum EyeState {
EYE_UNCONTROLLED,
EYE_OPEN,
EYE_CLOSING,
EYE_CLOSED,
EYE_OPENING
};
EyeState _eyeStates[2];
float _lastEyeBlinks[2];
float _filteredEyeBlinks[2];
float _lastEyeCoefficients[2];
Setting::Handle<float> _eyeClosingThreshold;
QVector<float> _coefficientAverages;
bool _isCalibrating;
int _calibrationCount;
QVector<float> _calibrationValues;
TextOverlay* _calibrationBillboard;
QUuid _calibrationBillboardID;
QString _calibrationMessage;
bool _isCalibrated;
void addCalibrationDatum();
void cancelCalibration();
void finishCalibration();
};
#endif // hifi_DdeFaceTracker_h

View file

@ -11,7 +11,6 @@
#include <AudioClient.h>
#include <SettingHandle.h>
#include <trackers/FaceTracker.h>
#include <UsersScriptingInterface.h>
#include "Application.h"
@ -76,8 +75,6 @@ void AvatarInputs::update() {
return;
}
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
AI_UPDATE(isHMD, qApp->isHMDMode());
}
@ -103,13 +100,6 @@ bool AvatarInputs::getIgnoreRadiusEnabled() const {
return DependencyManager::get<NodeList>()->getIgnoreRadiusEnabled();
}
void AvatarInputs::toggleCameraMute() {
FaceTracker* faceTracker = qApp->getSelectedFaceTracker();
if (faceTracker) {
faceTracker->toggleMute();
}
}
void AvatarInputs::resetSensors() {
qApp->resetSensors();
}

View file

@ -32,14 +32,6 @@ class AvatarInputs : public QObject {
* @hifi-client-entity
* @hifi-avatar
*
* @property {boolean} cameraEnabled - <code>true</code> if webcam face tracking is enabled, <code>false</code> if it is
* disabled.
* <em>Read-only.</em>
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {boolean} cameraMuted - <code>true</code> if webcam face tracking is muted (temporarily disabled),
* <code>false</code> it if isn't.
* <em>Read-only.</em>
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {boolean} ignoreRadiusEnabled - <code>true</code> if the privacy shield is enabled, <code>false</code> if it
* is disabled.
* <em>Read-only.</em>
@ -51,8 +43,6 @@ class AvatarInputs : public QObject {
* it is hidden.
*/
AI_PROPERTY(bool, cameraEnabled, false)
AI_PROPERTY(bool, cameraMuted, false)
AI_PROPERTY(bool, isHMD, false)
Q_PROPERTY(bool showAudioTools READ showAudioTools WRITE setShowAudioTools NOTIFY showAudioToolsChanged)
@ -97,22 +87,6 @@ public slots:
signals:
/**jsdoc
* Triggered when webcam face tracking is enabled or disabled.
* @deprecated This signal is deprecated and will be removed.
* @function AvatarInputs.cameraEnabledChanged
* @returns {Signal}
*/
void cameraEnabledChanged();
/**jsdoc
* Triggered when webcam face tracking is muted (temporarily disabled) or unmuted.
* @deprecated This signal is deprecated and will be removed.
* @function AvatarInputs.cameraMutedChanged
* @returns {Signal}
*/
void cameraMutedChanged();
/**jsdoc
* Triggered when the display mode changes between desktop and HMD.
* @function AvatarInputs.isHMDChanged
@ -183,13 +157,6 @@ protected:
*/
Q_INVOKABLE void resetSensors();
/**jsdoc
* Toggles the muting (temporary disablement) of webcam face tracking on/off.
* <p class="important">Deprecated: This function is deprecated and will be removed.</p>
* @function AvatarInputs.toggleCameraMute
*/
Q_INVOKABLE void toggleCameraMute();
private:
void onAvatarEnteredIgnoreRadius();
void onAvatarLeftIgnoreRadius();

View file

@ -10,7 +10,6 @@
#include <AudioClient.h>
#include <avatar/AvatarManager.h>
#include <devices/DdeFaceTracker.h>
#include <ScriptEngines.h>
#include <OffscreenUi.h>
#include <Preferences.h>
@ -285,22 +284,6 @@ void setupPreferences() {
preferences->addPreference(preference);
}
static const QString FACE_TRACKING{ "Face Tracking" };
{
#ifdef HAVE_DDE
auto getter = []()->float { return DependencyManager::get<DdeFaceTracker>()->getEyeClosingThreshold(); };
auto setter = [](float value) { DependencyManager::get<DdeFaceTracker>()->setEyeClosingThreshold(value); };
preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Closing Threshold", getter, setter));
#endif
}
{
auto getter = []()->float { return FaceTracker::getEyeDeflection(); };
auto setter = [](float value) { FaceTracker::setEyeDeflection(value); };
preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Deflection", getter, setter));
}
static const QString VR_MOVEMENT{ "VR Movement" };
{
auto getter = [myAvatar]()->bool { return myAvatar->getAllowTeleporting(); };

View file

@ -1,6 +1,6 @@
set(TARGET_NAME avatars-renderer)
setup_hifi_library(Network Script)
link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking script-engine render render-utils image trackers entities-renderer)
link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking script-engine render render-utils image entities-renderer)
include_hifi_library_headers(avatars)
include_hifi_library_headers(networking)
include_hifi_library_headers(hfm)

View file

@ -16,7 +16,6 @@
#include <NodeList.h>
#include <DependencyManager.h>
#include <GeometryUtil.h>
#include <trackers/FaceTracker.h>
#include <Rig.h>
#include "Logging.h"
@ -26,6 +25,22 @@ using namespace std;
static bool disableEyelidAdjustment { false };
static void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp,
float jawOpen, float mouth2, float mouth3, float mouth4, QVector<float>& coefficients) {
coefficients.resize(std::max((int)coefficients.size(), (int)Blendshapes::BlendshapeCount));
qFill(coefficients.begin(), coefficients.end(), 0.0f);
coefficients[(int)Blendshapes::EyeBlink_L] = leftBlink;
coefficients[(int)Blendshapes::EyeBlink_R] = rightBlink;
coefficients[(int)Blendshapes::BrowsU_C] = browUp;
coefficients[(int)Blendshapes::BrowsU_L] = browUp;
coefficients[(int)Blendshapes::BrowsU_R] = browUp;
coefficients[(int)Blendshapes::JawOpen] = jawOpen;
coefficients[(int)Blendshapes::MouthSmile_L] = coefficients[(int)Blendshapes::MouthSmile_R] = mouth4;
coefficients[(int)Blendshapes::LipsUpperClose] = mouth2;
coefficients[(int)Blendshapes::LipsFunnel] = mouth3;
}
Head::Head(Avatar* owningAvatar) :
HeadData(owningAvatar),
_leftEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID()),
@ -153,7 +168,7 @@ void Head::simulate(float deltaTime) {
_mouthTime = 0.0f;
}
FaceTracker::updateFakeCoefficients(
updateFakeCoefficients(
_leftEyeBlink,
_rightEyeBlink,
_browAudioLift,

View file

@ -71,7 +71,7 @@ void HeadData::setOrientation(const glm::quat& orientation) {
}
void HeadData::computeBlendshapesLookupMap(){
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
for (int i = 0; i < (int)Blendshapes::BlendshapeCount; i++) {
_blendshapeLookupMap[FACESHIFT_BLENDSHAPES[i]] = i;
}
}

View file

@ -20,7 +20,7 @@
#include <glm/gtc/quaternion.hpp>
#include <SharedUtil.h>
#include <FaceshiftConstants.h>
#include <BlendshapeConstants.h>
// degrees
const float MIN_HEAD_YAW = -180.0f;

View file

@ -17,7 +17,7 @@
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include <FaceshiftConstants.h>
#include <BlendshapeConstants.h>
#include <hfm/ModelFormatLogging.h>

View file

@ -33,7 +33,7 @@
#include <ResourceManager.h>
#include <PathUtils.h>
#include <image/ColorChannel.h>
#include <FaceshiftConstants.h>
#include <BlendshapeConstants.h>
#include "FBXSerializer.h"

View file

@ -1,5 +1,5 @@
//
// FaceshiftConstants.cpp
// BlendshapeConstants.cpp
//
//
// Created by Clement on 1/23/15.
@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "FaceshiftConstants.h"
#include "BlendshapeConstants.h"
const char* FACESHIFT_BLENDSHAPES[] = {
"EyeBlink_L",
@ -34,7 +34,7 @@ const char* FACESHIFT_BLENDSHAPES[] = {
"JawFwd",
"JawLeft",
"JawOpen",
"JawChew", // legacy not in ARKit
"JawChew",
"JawRight",
"MouthLeft",
"MouthRight",
@ -48,15 +48,15 @@ const char* FACESHIFT_BLENDSHAPES[] = {
"LipsStretch_R",
"LipsUpperClose",
"LipsLowerClose",
"LipsUpperUp", // legacy, split in ARKit
"LipsLowerDown", // legacy, split in ARKit
"LipsUpperUp",
"LipsLowerDown",
"LipsUpperOpen",
"LipsLowerOpen",
"LipsFunnel",
"LipsPucker",
"ChinLowerRaise",
"ChinUpperRaise",
"Sneer", // legacy, split in ARKit
"Sneer",
"Puff",
"CheekSquint_L",
"CheekSquint_R",
@ -71,8 +71,6 @@ const char* FACESHIFT_BLENDSHAPES[] = {
// MouthShrugUpper
// TongueOut
const int NUM_FACESHIFT_BLENDSHAPES = sizeof(FACESHIFT_BLENDSHAPES) / sizeof(char*);
const int EYE_BLINK_L_INDEX = 0;
const int EYE_BLINK_R_INDEX = 1;
const int EYE_SQUINT_L_INDEX = 2;

View file

@ -0,0 +1,76 @@
//
// BlendshapeConstants.h
//
//
// Created by Clement on 1/23/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_BlendshapeConstants_h
#define hifi_BlendshapeConstants_h
/// The names of the blendshapes expected by Faceshift, terminated with an empty string.
extern const char* FACESHIFT_BLENDSHAPES[];
// Eyes and Brows indices
extern const int EYE_BLINK_INDICES[];
extern const int EYE_OPEN_INDICES[];
extern const int BROWS_U_INDICES[];
extern const int EYE_SQUINT_INDICES[];
enum class Blendshapes : int {
EyeBlink_L = 0,
EyeBlink_R,
EyeSquint_L,
EyeSquint_R,
EyeDown_L,
EyeDown_R,
EyeIn_L,
EyeIn_R,
EyeOpen_L,
EyeOpen_R,
EyeOut_L, // 10
EyeOut_R,
EyeUp_L,
EyeUp_R,
BrowsD_L,
BrowsD_R,
BrowsU_C,
BrowsU_L,
BrowsU_R,
JawFwd,
JawLeft, // 20
JawOpen,
JawChew, // legacy not in ARKit
JawRight,
MouthLeft,
MouthRight,
MouthFrown_L,
MouthFrown_R,
MouthSmile_L,
MouthSmile_R,
MouthDimple_L, // 30
MouthDimple_R,
LipsStretch_L,
LipsStretch_R,
LipsUpperClose,
LipsLowerClose,
LipsUpperUp, // legacy, split in ARKit
LipsLowerDown, // legacy, split in ARKit
LipsUpperOpen,
LipsLowerOpen,
LipsFunnel, // 40
LipsPucker,
ChinLowerRaise,
ChinUpperRaise,
Sneer, // legacy, split in ARKit
Puff,
CheekSquint_L,
CheekSquint_R,
BlendshapeCount
};
#endif // hifi_BlendshapeConstants_h

View file

@ -1,25 +0,0 @@
//
// FaceshiftConstants.h
//
//
// Created by Clement on 1/23/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_FaceshiftConstants_h
#define hifi_FaceshiftConstants_h
/// The names of the blendshapes expected by Faceshift, terminated with an empty string.
extern const char* FACESHIFT_BLENDSHAPES[];
/// The size of FACESHIFT_BLENDSHAPES
extern const int NUM_FACESHIFT_BLENDSHAPES;
// Eyes and Brows indices
extern const int EYE_BLINK_INDICES[];
extern const int EYE_OPEN_INDICES[];
extern const int BROWS_U_INDICES[];
extern const int EYE_SQUINT_INDICES[];
#endif // hifi_FaceshiftConstants_h

View file

@ -1,7 +0,0 @@
set(TARGET_NAME trackers)
setup_hifi_library()
GroupSources("src")
link_hifi_libraries(shared)
include_hifi_library_headers(octree)
target_bullet()

View file

@ -1,133 +0,0 @@
//
// Created by Andrzej Kapolka on 4/9/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "FaceTracker.h"
#include <QTimer>
#include <GLMHelpers.h>
#include "Logging.h"
//#include "Menu.h"
const int FPS_TIMER_DELAY = 2000; // ms
const int FPS_TIMER_DURATION = 2000; // ms
const float DEFAULT_EYE_DEFLECTION = 0.25f;
Setting::Handle<float> FaceTracker::_eyeDeflection("faceshiftEyeDeflection", DEFAULT_EYE_DEFLECTION);
bool FaceTracker::_isMuted { true };
void FaceTracker::init() {
_isInitialized = true; // FaceTracker can be used now
}
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient())
: 0.0f;
}
const QVector<float>& FaceTracker::getBlendshapeCoefficients() const {
static QVector<float> blendshapes;
float fadeCoefficient = getFadeCoefficient();
if (fadeCoefficient == 1.0f) {
return _blendshapeCoefficients;
} else {
blendshapes.resize(_blendshapeCoefficients.size());
for (int i = 0; i < _blendshapeCoefficients.size(); i++) {
blendshapes[i] = glm::mix(0.0f, _blendshapeCoefficients[i], fadeCoefficient);
}
return blendshapes;
}
}
float FaceTracker::getFadeCoefficient() const {
return _fadeCoefficient;
}
const glm::vec3 FaceTracker::getHeadTranslation() const {
return glm::mix(glm::vec3(0.0f), _headTranslation, getFadeCoefficient());
}
const glm::quat FaceTracker::getHeadRotation() const {
return safeMix(glm::quat(), _headRotation, getFadeCoefficient());
}
void FaceTracker::update(float deltaTime) {
// Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution
static const float EPSILON = 0.02f; // MUST BE < 1.0f
static const float INVERSE_AT_EPSILON = -std::log(EPSILON); // So that f(1.0f) = EPSILON ~ 0.0f
static const float RELAXATION_TIME = 0.8f; // sec
if (isTracking()) {
if (_relaxationStatus == 1.0f) {
_fadeCoefficient = 1.0f;
return;
}
_relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
_fadeCoefficient = 1.0f - std::exp(-_relaxationStatus * INVERSE_AT_EPSILON);
} else {
if (_relaxationStatus == 0.0f) {
_fadeCoefficient = 0.0f;
return;
}
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
}
}
void FaceTracker::reset() {
if (isActive() && !_isCalculatingFPS) {
QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer()));
_isCalculatingFPS = true;
}
}
void FaceTracker::startFPSTimer() {
_frameCount = 0;
QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer()));
}
void FaceTracker::countFrame() {
if (_isCalculatingFPS) {
_frameCount++;
}
}
void FaceTracker::finishFPSTimer() {
qCDebug(trackers) << "Face tracker FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f);
_isCalculatingFPS = false;
}
void FaceTracker::toggleMute() {
_isMuted = !_isMuted;
emit muteToggled();
}
void FaceTracker::setEyeDeflection(float eyeDeflection) {
_eyeDeflection.set(eyeDeflection);
}
void FaceTracker::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp,
float jawOpen, float mouth2, float mouth3, float mouth4, QVector<float>& coefficients) {
const int MMMM_BLENDSHAPE = 34;
const int FUNNEL_BLENDSHAPE = 40;
const int SMILE_LEFT_BLENDSHAPE = 28;
const int SMILE_RIGHT_BLENDSHAPE = 29;
const int MAX_FAKE_BLENDSHAPE = 40; // Largest modified blendshape from above and below
coefficients.resize(std::max((int)coefficients.size(), MAX_FAKE_BLENDSHAPE + 1));
qFill(coefficients.begin(), coefficients.end(), 0.0f);
coefficients[_leftBlinkIndex] = leftBlink;
coefficients[_rightBlinkIndex] = rightBlink;
coefficients[_browUpCenterIndex] = browUp;
coefficients[_browUpLeftIndex] = browUp;
coefficients[_browUpRightIndex] = browUp;
coefficients[_jawOpenIndex] = jawOpen;
coefficients[SMILE_LEFT_BLENDSHAPE] = coefficients[SMILE_RIGHT_BLENDSHAPE] = mouth4;
coefficients[MMMM_BLENDSHAPE] = mouth2;
coefficients[FUNNEL_BLENDSHAPE] = mouth3;
}

View file

@ -1,131 +0,0 @@
//
// Created by Andrzej Kapolka on 4/9/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_FaceTracker_h
#define hifi_FaceTracker_h
#include <QObject>
#include <QVector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <SettingHandle.h>
/// Base class for face trackers (DDE, BinaryVR).
class FaceTracker : public QObject {
Q_OBJECT
public:
virtual bool isActive() const { return false; }
virtual bool isTracking() const { return false; }
virtual void init();
virtual void update(float deltaTime);
virtual void reset();
float getFadeCoefficient() const;
const glm::vec3 getHeadTranslation() const;
const glm::quat getHeadRotation() const;
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
int getNumBlendshapes() const { return _blendshapeCoefficients.size(); }
bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); }
const QVector<float>& getBlendshapeCoefficients() const;
float getBlendshapeCoefficient(int index) const;
static bool isMuted() { return _isMuted; }
static void setIsMuted(bool isMuted) { _isMuted = isMuted; }
static float getEyeDeflection() { return _eyeDeflection.get(); }
static void setEyeDeflection(float eyeDeflection);
static void updateFakeCoefficients(float leftBlink,
float rightBlink,
float browUp,
float jawOpen,
float mouth2,
float mouth3,
float mouth4,
QVector<float>& coefficients);
signals:
/**jsdoc
* @function FaceTracker.muteToggled
* @returns {Signal}
*/
void muteToggled();
public slots:
// No JSDoc here because it's overridden in DdeFaceTracker.
virtual void setEnabled(bool enabled) = 0;
/**jsdoc
* @function FaceTracker.toggleMute
*/
void toggleMute();
/**jsdoc
* @function FaceTracker.getMuted
* @returns {boolean}
*/
bool getMuted() { return _isMuted; }
protected:
virtual ~FaceTracker() {};
bool _isInitialized = false;
static bool _isMuted;
glm::vec3 _headTranslation = glm::vec3(0.0f);
glm::quat _headRotation = glm::quat();
float _estimatedEyePitch = 0.0f;
float _estimatedEyeYaw = 0.0f;
QVector<float> _blendshapeCoefficients;
float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f
float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f
void countFrame();
private slots:
void startFPSTimer();
void finishFPSTimer();
private:
bool _isCalculatingFPS = false;
int _frameCount = 0;
// see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
static const int _leftBlinkIndex = 0;
static const int _rightBlinkIndex = 1;
static const int _leftEyeOpenIndex = 8;
static const int _rightEyeOpenIndex = 9;
// Brows
static const int _browDownLeftIndex = 14;
static const int _browDownRightIndex = 15;
static const int _browUpCenterIndex = 16;
static const int _browUpLeftIndex = 17;
static const int _browUpRightIndex = 18;
static const int _mouthSmileLeftIndex = 28;
static const int _mouthSmileRightIndex = 29;
static const int _jawOpenIndex = 21;
static Setting::Handle<float> _eyeDeflection;
};
#endif // hifi_FaceTracker_h

View file

@ -1,11 +0,0 @@
//
// Created by Bradley Austin Davis on 2017/04/25
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Logging.h"
Q_LOGGING_CATEGORY(trackers, "hifi.trackers")

View file

@ -1,16 +0,0 @@
//
// Created by Bradley Austin Davis on 2017/04/25
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_TrackersLogging_h
#define hifi_TrackersLogging_h
#include <QtCore/QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(trackers)
#endif // hifi_TrackersLogging_h

View file

@ -29,7 +29,6 @@ exports.handlers = {
'../../interface/src/audio',
'../../interface/src/avatar',
'../../interface/src/commerce',
'../../interface/src/devices',
'../../interface/src/java',
'../../interface/src/networking',
'../../interface/src/raypick',
@ -64,7 +63,6 @@ exports.handlers = {
'../../libraries/shared/src',
'../../libraries/shared/src/shared',
'../../libraries/task/src/task',
'../../libraries/trackers/src/trackers',
'../../libraries/ui/src',
'../../libraries/ui/src/ui',
'../../plugins/oculus/src',