From 55e0035fc890b0e618e0c6439cc4a8a9c316a990 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 9 Apr 2014 11:14:47 -0700 Subject: [PATCH] More progress on Faceplus integration. --- interface/src/Menu.cpp | 5 ++ interface/src/Menu.h | 1 + interface/src/devices/Faceplus.cpp | 113 ++++++++++++++++++++++++++++- interface/src/devices/Faceplus.h | 17 +++++ interface/src/devices/Faceshift.h | 3 - interface/src/devices/Visage.cpp | 1 + interface/src/devices/Visage.h | 3 - 7 files changed, 135 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8a97c98f02..b85f83ab05 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -301,6 +301,11 @@ Menu::Menu() : true, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); +#ifdef HAVE_FACEPLUS + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Faceplus, 0, true, + appInstance->getFaceplus(), SLOT(updateEnabled())); +#endif + #ifdef HAVE_VISAGE addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, appInstance->getVisage(), SLOT(updateEnabled())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7bb0b75675..b7a82b0b0e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -250,6 +250,7 @@ namespace MenuOption { const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString Faceplus = "Faceplus"; const QString Faceshift = "Faceshift"; const QString FilterSixense = "Smooth Sixense Movement"; const QString FirstPerson = "First Person"; diff --git a/interface/src/devices/Faceplus.cpp b/interface/src/devices/Faceplus.cpp index 64dd4bf52d..2e02126240 100644 --- a/interface/src/devices/Faceplus.cpp +++ b/interface/src/devices/Faceplus.cpp @@ -10,23 +10,132 @@ #include #endif +#include "Application.h" #include "Faceplus.h" +#include "renderer/FBXReader.h" Faceplus::Faceplus() : + _enabled(false), _active(false) { -} -void Faceplus::init() { #ifdef HAVE_FACEPLUS // these are ignored--any values will do faceplus_log_in("username", "password"); #endif } +Faceplus::~Faceplus() { + setEnabled(false); +} + +void Faceplus::init() { + connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); + updateEnabled(); +} + +#ifdef HAVE_FACEPLUS +static QMultiHash > createChannelNameMap() { + QMultiHash > blendshapeMap; + blendshapeMap.insert("JawFwd", QPair("au_jaw_z_push", 1.0f)); + blendshapeMap.insert("JawLeft", QPair("au_jaw_x_push", 1.0f)); + blendshapeMap.insert("JawOpen", QPair("au_jaw_drop", 1.0f)); + blendshapeMap.insert("LipsLowerDown", QPair("au_lower_lip_drop", 1.0f)); + blendshapeMap.insert("LipsUpperOpen", QPair("au_upper_lip_raiser", 1.0f)); + blendshapeMap.insert("LipsStretch_R", QPair("au_lip_stretcher_left", 0.5f)); + blendshapeMap.insert("MouthSmile_L", QPair("au_lip_corner_depressor", -1.0f)); + blendshapeMap.insert("MouthSmile_R", QPair("au_lip_corner_depressor", -1.0f)); + blendshapeMap.insert("BrowsU_R", QPair("au_left_outer_brow_raiser", 1.0f)); + blendshapeMap.insert("BrowsU_C", QPair("au_left_inner_brow_raiser", 1.0f)); + blendshapeMap.insert("BrowsD_R", QPair("au_left_brow_lowerer", 1.0f)); + blendshapeMap.insert("EyeBlink_L", QPair("au_leye_closed", 1.0f)); + blendshapeMap.insert("EyeBlink_R", QPair("au_reye_closed", 1.0f)); + blendshapeMap.insert("EyeOpen_L", QPair("au_upper_lid_raiser", 1.0f)); + blendshapeMap.insert("EyeOpen_R", QPair("au_upper_lid_raiser", 1.0f)); + blendshapeMap.insert("LipLowerOpen", QPair("au_lower_lip_x_push", 1.0f)); + blendshapeMap.insert("LipsStretch_L", QPair("au_lip_stretcher_right", 0.5f)); + blendshapeMap.insert("BrowsU_L", QPair("au_right_outer_brow_raiser", 1.0f)); + blendshapeMap.insert("BrowsU_C", QPair("au_right_inner_brow_raiser", 1.0f)); + blendshapeMap.insert("BrowsD_L", QPair("au_right_brow_lowerer", 1.0f)); + + QMultiHash > channelNameMap; + for (int i = 0;; i++) { + QByteArray blendshape = FACESHIFT_BLENDSHAPES[i]; + if (blendshape.isEmpty()) { + break; + } + for (QMultiHash >::const_iterator it = blendshapeMap.constFind(blendshape); + it != blendshapeMap.constEnd() && it.key() == blendshape; it++) { + channelNameMap.insert(it.value().first, QPair(i, it.value().second)); + } + } + + return channelNameMap; +} + +static const QMultiHash >& getChannelNameMap() { + static QMultiHash > channelNameMap = createChannelNameMap(); + return channelNameMap; +} +#endif + void Faceplus::update() { +#ifdef HAVE_FACEPLUS + if (!_active) { + return; + } + if (!(_active = faceplus_current_output_vector(_outputVector.data()))) { + return; + } + qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f); + for (int i = 0; i < _outputVector.size(); i++) { + for (QMultiHash >::const_iterator it = _channelIndexMap.constFind(i); + it != _channelIndexMap.constEnd() && it.key() == i; it++) { + _blendshapeCoefficients[it.value().first] += _outputVector.at(i) * it.value().second; + } + } +#endif } void Faceplus::reset() { } +void Faceplus::updateEnabled() { + setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) && + !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && + Application::getInstance()->getFaceshift()->isConnectedOrConnecting())); +} +void Faceplus::setEnabled(bool enabled) { +#ifdef HAVE_FACEPLUS + if (_enabled == enabled) { + return; + } + if ((_enabled = enabled)) { + if (faceplus_init("VGA")) { + qDebug() << "Faceplus initialized."; + _active = true; + + int channelCount = faceplus_output_channels_count(); + _outputVector.resize(channelCount); + + int maxIndex = -1; + _channelIndexMap.clear(); + for (int i = 0; i < channelCount; i++) { + QByteArray channelName = faceplus_output_channel_name(i); + + qDebug() << channelName; + + for (QMultiHash >::const_iterator it = getChannelNameMap().constFind(name); + it != getChannelNameMap().constEnd() && it.key() == name; it++) { + _channelIndexMap.insert(i, it.value()); + maxIndex = qMax(maxIndex, it.value().first); + } + } + _blendshapeCoefficients.resize(maxIndex + 1); + } + } else if (faceplus_teardown()) { + qDebug() << "Faceplus torn down."; + _active = false; + } +#endif +} diff --git a/interface/src/devices/Faceplus.h b/interface/src/devices/Faceplus.h index cf7a6583a1..a511313d0c 100644 --- a/interface/src/devices/Faceplus.h +++ b/interface/src/devices/Faceplus.h @@ -9,6 +9,10 @@ #ifndef __interface__Faceplus__ #define __interface__Faceplus__ +#include +#include +#include + #include "FaceTracker.h" /// Interface for Mixamo FacePlus. @@ -18,6 +22,7 @@ class Faceplus : public FaceTracker { public: Faceplus(); + virtual ~Faceplus(); void init(); @@ -26,9 +31,21 @@ public: void update(); void reset(); +public slots: + + void updateEnabled(); + private: + void setEnabled(bool enabled); + + bool _enabled; bool _active; + +#ifdef HAVE_VISAGE + QMultiHash > _channelIndexMap; + QVector _outputVector; +#endif }; #endif /* defined(__interface__Faceplus__) */ diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index c49c6661e7..c245d648b8 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -12,9 +12,6 @@ #include #include -#include -#include - #include #include "FaceTracker.h" diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 0cb534f8c3..3792cc913d 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -159,6 +159,7 @@ void Visage::reset() { void Visage::updateEnabled() { setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && + !Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) && !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && Application::getInstance()->getFaceshift()->isConnectedOrConnecting())); } diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 0da87fb332..1a02f5d7c3 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -13,9 +13,6 @@ #include #include -#include -#include - #include "FaceTracker.h" namespace VisageSDK {