mirror of
https://github.com/overte-org/overte.git
synced 2025-06-21 21:41:09 +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);
|
_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() {
|
void Application::updateFaceshift() {
|
||||||
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
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
|
// check what's under the mouse and update the mouse voxel
|
||||||
updateMouseRay();
|
updateMouseRay();
|
||||||
|
|
||||||
updateFaceplus();
|
|
||||||
updateFaceshift();
|
updateFaceshift();
|
||||||
updateVisage();
|
updateVisage();
|
||||||
_myAvatar->updateLookAtTargetAvatar();
|
_myAvatar->updateLookAtTargetAvatar();
|
||||||
|
@ -2945,7 +2935,6 @@ void Application::resetSensors() {
|
||||||
_mouseX = _glWidget->width() / 2;
|
_mouseX = _glWidget->width() / 2;
|
||||||
_mouseY = _glWidget->height() / 2;
|
_mouseY = _glWidget->height() / 2;
|
||||||
|
|
||||||
_faceplus.reset();
|
|
||||||
_faceshift.reset();
|
_faceshift.reset();
|
||||||
_visage.reset();
|
_visage.reset();
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,6 @@ public:
|
||||||
bool isMouseHidden() const { return _mouseHidden; }
|
bool isMouseHidden() const { return _mouseHidden; }
|
||||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||||
Faceplus* getFaceplus() { return &_faceplus; }
|
|
||||||
Faceshift* getFaceshift() { return &_faceshift; }
|
Faceshift* getFaceshift() { return &_faceshift; }
|
||||||
Visage* getVisage() { return &_visage; }
|
Visage* getVisage() { return &_visage; }
|
||||||
FaceTracker* getActiveFaceTracker();
|
FaceTracker* getActiveFaceTracker();
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#ifdef HAVE_FACEPLUS
|
#ifdef HAVE_FACEPLUS
|
||||||
#include <faceplus.h>
|
#include <faceplus.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,6 +35,41 @@ void Faceplus::init() {
|
||||||
updateEnabled();
|
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
|
#ifdef HAVE_FACEPLUS
|
||||||
static QMultiHash<QByteArray, QPair<int, float> > createChannelNameMap() {
|
static QMultiHash<QByteArray, QPair<int, float> > createChannelNameMap() {
|
||||||
QMultiHash<QByteArray, QPair<QByteArray, float> > blendshapeMap;
|
QMultiHash<QByteArray, QPair<QByteArray, float> > blendshapeMap;
|
||||||
|
@ -97,18 +134,76 @@ static const QMultiHash<QByteArray, QPair<int, float> >& getChannelNameMap() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Faceplus::update() {
|
void FaceplusReader::init() {
|
||||||
#ifdef HAVE_FACEPLUS
|
#ifdef HAVE_FACEPLUS
|
||||||
if (!_active) {
|
if (!faceplus_init("VGA")) {
|
||||||
|
qDebug() << "Failed to initialized Faceplus.";
|
||||||
return;
|
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;
|
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]))));
|
_outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2]))));
|
||||||
_estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) + _outputVector.at(_rightEyeRotationIndices[0])) * -0.5f;
|
float estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) +
|
||||||
_estimatedEyeYaw = (_outputVector.at(_leftEyeRotationIndices[1]) + _outputVector.at(_rightEyeRotationIndices[1])) * 0.5f;
|
_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);
|
qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f);
|
||||||
for (int i = 0; i < _outputVector.size(); i++) {
|
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;
|
_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
|
#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"
|
#include "FaceTracker.h"
|
||||||
|
|
||||||
|
class FaceplusReader;
|
||||||
|
|
||||||
/// Interface for Mixamo FacePlus.
|
/// Interface for Mixamo FacePlus.
|
||||||
class Faceplus : public FaceTracker {
|
class Faceplus : public FaceTracker {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -28,9 +30,9 @@ public:
|
||||||
|
|
||||||
bool isActive() const { return _active; }
|
bool isActive() const { return _active; }
|
||||||
|
|
||||||
void update();
|
Q_INVOKABLE void setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||||
void reset();
|
const QVector<float>& blendshapeCoefficients);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void updateEnabled();
|
void updateEnabled();
|
||||||
|
@ -42,12 +44,28 @@ private:
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
bool _active;
|
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
|
#ifdef HAVE_FACEPLUS
|
||||||
QMultiHash<int, QPair<int, float> > _channelIndexMap;
|
QMultiHash<int, QPair<int, float> > _channelIndexMap;
|
||||||
QVector<float> _outputVector;
|
QVector<float> _outputVector;
|
||||||
int _headRotationIndices[3];
|
int _headRotationIndices[3];
|
||||||
int _leftEyeRotationIndices[2];
|
int _leftEyeRotationIndices[2];
|
||||||
int _rightEyeRotationIndices[2];
|
int _rightEyeRotationIndices[2];
|
||||||
|
QVector<float> _blendshapeIndices;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue