mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Move Faceplus reading to its own thread to avoid blocking the main one.
This commit is contained in:
parent
79455d5850
commit
28d3eae12b
4 changed files with 127 additions and 82 deletions
|
@ -1689,15 +1689,6 @@ void Application::updateMouseRay() {
|
|||
_myAvatar->setMouseRay(_mouseRayOrigin, _mouseRayDirection);
|
||||
}
|
||||
|
||||
void Application::updateFaceplus() {
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateFaceplus()");
|
||||
|
||||
// Update faceplus
|
||||
_faceplus.update();
|
||||
}
|
||||
|
||||
void Application::updateFaceshift() {
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
|
@ -1894,7 +1885,6 @@ void Application::update(float deltaTime) {
|
|||
// check what's under the mouse and update the mouse voxel
|
||||
updateMouseRay();
|
||||
|
||||
updateFaceplus();
|
||||
updateFaceshift();
|
||||
updateVisage();
|
||||
_myAvatar->updateLookAtTargetAvatar();
|
||||
|
@ -2945,7 +2935,6 @@ void Application::resetSensors() {
|
|||
_mouseX = _glWidget->width() / 2;
|
||||
_mouseY = _glWidget->height() / 2;
|
||||
|
||||
_faceplus.reset();
|
||||
_faceshift.reset();
|
||||
_visage.reset();
|
||||
|
||||
|
|
|
@ -174,7 +174,6 @@ public:
|
|||
bool isMouseHidden() const { return _mouseHidden; }
|
||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
Faceplus* getFaceplus() { return &_faceplus; }
|
||||
Faceshift* getFaceshift() { return &_faceshift; }
|
||||
Visage* getVisage() { return &_visage; }
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
#include <faceplus.h>
|
||||
#endif
|
||||
|
@ -33,6 +35,41 @@ void Faceplus::init() {
|
|||
updateEnabled();
|
||||
}
|
||||
|
||||
void Faceplus::setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||
const QVector<float>& blendshapeCoefficients) {
|
||||
_headRotation = headRotation;
|
||||
_estimatedEyePitch = estimatedEyePitch;
|
||||
_estimatedEyeYaw = estimatedEyeYaw;
|
||||
_blendshapeCoefficients = blendshapeCoefficients;
|
||||
_active = true;
|
||||
}
|
||||
|
||||
void Faceplus::updateEnabled() {
|
||||
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) &&
|
||||
!(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) &&
|
||||
Application::getInstance()->getFaceshift()->isConnectedOrConnecting()));
|
||||
}
|
||||
|
||||
void Faceplus::setEnabled(bool enabled) {
|
||||
if (_enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
if ((_enabled = enabled)) {
|
||||
_reader = new FaceplusReader();
|
||||
QThread* readerThread = new QThread(this);
|
||||
_reader->moveToThread(readerThread);
|
||||
readerThread->start();
|
||||
QMetaObject::invokeMethod(_reader, "init");
|
||||
|
||||
} else {
|
||||
QThread* readerThread = _reader->thread();
|
||||
QMetaObject::invokeMethod(_reader, "shutdown");
|
||||
readerThread->wait();
|
||||
delete readerThread;
|
||||
_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
static QMultiHash<QByteArray, QPair<int, float> > createChannelNameMap() {
|
||||
QMultiHash<QByteArray, QPair<QByteArray, float> > blendshapeMap;
|
||||
|
@ -97,18 +134,76 @@ static const QMultiHash<QByteArray, QPair<int, float> >& getChannelNameMap() {
|
|||
}
|
||||
#endif
|
||||
|
||||
void Faceplus::update() {
|
||||
void FaceplusReader::init() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (!_active) {
|
||||
if (!faceplus_init("VGA")) {
|
||||
qDebug() << "Failed to initialized Faceplus.";
|
||||
return;
|
||||
}
|
||||
if (!(_active = faceplus_synchronous_track() && faceplus_current_output_vector(_outputVector.data()))) {
|
||||
qDebug() << "Faceplus initialized.";
|
||||
|
||||
int channelCount = faceplus_output_channels_count();
|
||||
_outputVector.resize(channelCount);
|
||||
|
||||
int maxIndex = -1;
|
||||
_channelIndexMap.clear();
|
||||
for (int i = 0; i < channelCount; i++) {
|
||||
QByteArray name = faceplus_output_channel_name(i);
|
||||
if (name == "Head_Joint::Rotation_X") {
|
||||
_headRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Head_Joint::Rotation_Y") {
|
||||
_headRotationIndices[1] = i;
|
||||
|
||||
} else if (name == "Head_Joint::Rotation_Z") {
|
||||
_headRotationIndices[2] = i;
|
||||
|
||||
} else if (name == "Left_Eye_Joint::Rotation_X") {
|
||||
_leftEyeRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Left_Eye_Joint::Rotation_Y") {
|
||||
_leftEyeRotationIndices[1] = i;
|
||||
|
||||
} else if (name == "Right_Eye_Joint::Rotation_X") {
|
||||
_rightEyeRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Right_Eye_Joint::Rotation_Y") {
|
||||
_rightEyeRotationIndices[1] = i;
|
||||
}
|
||||
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);
|
||||
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FaceplusReader::shutdown() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (faceplus_teardown()) {
|
||||
qDebug() << "Faceplus torn down.";
|
||||
}
|
||||
#endif
|
||||
deleteLater();
|
||||
thread()->quit();
|
||||
}
|
||||
|
||||
void FaceplusReader::update() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (!(faceplus_synchronous_track() && faceplus_current_output_vector(_outputVector.data()))) {
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
_headRotation = glm::quat(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]),
|
||||
glm::quat headRotation(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]),
|
||||
_outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2]))));
|
||||
_estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) + _outputVector.at(_rightEyeRotationIndices[0])) * -0.5f;
|
||||
_estimatedEyeYaw = (_outputVector.at(_leftEyeRotationIndices[1]) + _outputVector.at(_rightEyeRotationIndices[1])) * 0.5f;
|
||||
float estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) +
|
||||
_outputVector.at(_rightEyeRotationIndices[0])) * -0.5f;
|
||||
float estimatedEyeYaw = (_outputVector.at(_leftEyeRotationIndices[1]) +
|
||||
_outputVector.at(_rightEyeRotationIndices[1])) * 0.5f;
|
||||
|
||||
qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f);
|
||||
for (int i = 0; i < _outputVector.size(); i++) {
|
||||
|
@ -117,67 +212,11 @@ void Faceplus::update() {
|
|||
_blendshapeCoefficients[it.value().first] += _outputVector.at(i) * it.value().second;
|
||||
}
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getFaceplus(), "setState", Q_ARG(const glm::quat&, headRotation),
|
||||
Q_ARG(float, estimatedEyePitch), Q_ARG(float, estimatedEyeYaw), Q_ARG(const QVector<float>&, _blendshapeCoefficients));
|
||||
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
#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 name = faceplus_output_channel_name(i);
|
||||
if (name == "Head_Joint::Rotation_X") {
|
||||
_headRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Head_Joint::Rotation_Y") {
|
||||
_headRotationIndices[1] = i;
|
||||
|
||||
} else if (name == "Head_Joint::Rotation_Z") {
|
||||
_headRotationIndices[2] = i;
|
||||
|
||||
} else if (name == "Left_Eye_Joint::Rotation_X") {
|
||||
_leftEyeRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Left_Eye_Joint::Rotation_Y") {
|
||||
_leftEyeRotationIndices[1] = i;
|
||||
|
||||
} else if (name == "Right_Eye_Joint::Rotation_X") {
|
||||
_rightEyeRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Right_Eye_Joint::Rotation_Y") {
|
||||
_rightEyeRotationIndices[1] = i;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
class FaceplusReader;
|
||||
|
||||
/// Interface for Mixamo FacePlus.
|
||||
class Faceplus : public FaceTracker {
|
||||
Q_OBJECT
|
||||
|
@ -28,9 +30,9 @@ public:
|
|||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
Q_INVOKABLE void setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||
const QVector<float>& blendshapeCoefficients);
|
||||
|
||||
public slots:
|
||||
|
||||
void updateEnabled();
|
||||
|
@ -42,12 +44,28 @@ private:
|
|||
bool _enabled;
|
||||
bool _active;
|
||||
|
||||
FaceplusReader* _reader;
|
||||
};
|
||||
|
||||
/// The reader object that lives in its own thread.
|
||||
class FaceplusReader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE void init();
|
||||
Q_INVOKABLE void shutdown();
|
||||
Q_INVOKABLE void update();
|
||||
|
||||
private:
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
QMultiHash<int, QPair<int, float> > _channelIndexMap;
|
||||
QVector<float> _outputVector;
|
||||
int _headRotationIndices[3];
|
||||
int _leftEyeRotationIndices[2];
|
||||
int _rightEyeRotationIndices[2];
|
||||
QVector<float> _blendshapeIndices;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue