More progress on Faceplus integration.

This commit is contained in:
Andrzej Kapolka 2014-04-09 11:14:47 -07:00
parent 5b0e7f818d
commit 55e0035fc8
7 changed files with 135 additions and 8 deletions

View file

@ -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()));

View file

@ -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";

View file

@ -10,23 +10,132 @@
#include <faceplus.h>
#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<QByteArray, QPair<int, float> > createChannelNameMap() {
QMultiHash<QByteArray, QPair<QByteArray, float> > blendshapeMap;
blendshapeMap.insert("JawFwd", QPair<QByteArray, float>("au_jaw_z_push", 1.0f));
blendshapeMap.insert("JawLeft", QPair<QByteArray, float>("au_jaw_x_push", 1.0f));
blendshapeMap.insert("JawOpen", QPair<QByteArray, float>("au_jaw_drop", 1.0f));
blendshapeMap.insert("LipsLowerDown", QPair<QByteArray, float>("au_lower_lip_drop", 1.0f));
blendshapeMap.insert("LipsUpperOpen", QPair<QByteArray, float>("au_upper_lip_raiser", 1.0f));
blendshapeMap.insert("LipsStretch_R", QPair<QByteArray, float>("au_lip_stretcher_left", 0.5f));
blendshapeMap.insert("MouthSmile_L", QPair<QByteArray, float>("au_lip_corner_depressor", -1.0f));
blendshapeMap.insert("MouthSmile_R", QPair<QByteArray, float>("au_lip_corner_depressor", -1.0f));
blendshapeMap.insert("BrowsU_R", QPair<QByteArray, float>("au_left_outer_brow_raiser", 1.0f));
blendshapeMap.insert("BrowsU_C", QPair<QByteArray, float>("au_left_inner_brow_raiser", 1.0f));
blendshapeMap.insert("BrowsD_R", QPair<QByteArray, float>("au_left_brow_lowerer", 1.0f));
blendshapeMap.insert("EyeBlink_L", QPair<QByteArray, float>("au_leye_closed", 1.0f));
blendshapeMap.insert("EyeBlink_R", QPair<QByteArray, float>("au_reye_closed", 1.0f));
blendshapeMap.insert("EyeOpen_L", QPair<QByteArray, float>("au_upper_lid_raiser", 1.0f));
blendshapeMap.insert("EyeOpen_R", QPair<QByteArray, float>("au_upper_lid_raiser", 1.0f));
blendshapeMap.insert("LipLowerOpen", QPair<QByteArray, float>("au_lower_lip_x_push", 1.0f));
blendshapeMap.insert("LipsStretch_L", QPair<QByteArray, float>("au_lip_stretcher_right", 0.5f));
blendshapeMap.insert("BrowsU_L", QPair<QByteArray, float>("au_right_outer_brow_raiser", 1.0f));
blendshapeMap.insert("BrowsU_C", QPair<QByteArray, float>("au_right_inner_brow_raiser", 1.0f));
blendshapeMap.insert("BrowsD_L", QPair<QByteArray, float>("au_right_brow_lowerer", 1.0f));
QMultiHash<QByteArray, QPair<int, float> > channelNameMap;
for (int i = 0;; i++) {
QByteArray blendshape = FACESHIFT_BLENDSHAPES[i];
if (blendshape.isEmpty()) {
break;
}
for (QMultiHash<QByteArray, QPair<QByteArray, float> >::const_iterator it = blendshapeMap.constFind(blendshape);
it != blendshapeMap.constEnd() && it.key() == blendshape; it++) {
channelNameMap.insert(it.value().first, QPair<int, float>(i, it.value().second));
}
}
return channelNameMap;
}
static const QMultiHash<QByteArray, QPair<int, float> >& getChannelNameMap() {
static QMultiHash<QByteArray, QPair<int, float> > 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<int, QPair<int, float> >::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<QByteArray, QPair<int, float> >::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
}

View file

@ -9,6 +9,10 @@
#ifndef __interface__Faceplus__
#define __interface__Faceplus__
#include <QMultiHash>
#include <QPair>
#include <QVector>
#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<int, QPair<int, float> > _channelIndexMap;
QVector<float> _outputVector;
#endif
};
#endif /* defined(__interface__Faceplus__) */

View file

@ -12,9 +12,6 @@
#include <QTcpSocket>
#include <QUdpSocket>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <fsbinarystream.h>
#include "FaceTracker.h"

View file

@ -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()));
}

View file

@ -13,9 +13,6 @@
#include <QPair>
#include <QVector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "FaceTracker.h"
namespace VisageSDK {