mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-17 04:10:10 +02:00
Added dde face tracker class
This commit is contained in:
parent
38741aed73
commit
bbb52fc4aa
2 changed files with 210 additions and 0 deletions
|
@ -9,4 +9,173 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "DdeFaceTracker.h"
|
||||
|
||||
static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555;
|
||||
|
||||
static const int NUM_EXPRESSION = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSION) * sizeof(float) + sizeof(int);
|
||||
static const int MAX_NAME_SIZE = 31;
|
||||
|
||||
struct Packet{
|
||||
//roughly in mm
|
||||
float focal_length[1];
|
||||
float translation[3];
|
||||
|
||||
//quaternion
|
||||
float rotation[4];
|
||||
|
||||
//blendshape coefficients ranging between -0.2 and 1.5
|
||||
float expressions[NUM_EXPRESSION];
|
||||
|
||||
//avatar id selected on the UI
|
||||
int avatar_id;
|
||||
|
||||
//client name, arbitrary length
|
||||
char name[MAX_NAME_SIZE + 1];
|
||||
};
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker() :
|
||||
_lastReceiveTimestamp(0),
|
||||
_reset(false)
|
||||
{
|
||||
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)));
|
||||
|
||||
bindTo(DDE_FEATURE_POINT_SERVER_PORT);
|
||||
}
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||
_lastReceiveTimestamp(0),
|
||||
_reset(false)
|
||||
{
|
||||
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
|
||||
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError)));
|
||||
connect(&_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(socketStateChanged(QAbstractSocket::SocketState)));
|
||||
|
||||
bindTo(host, port);
|
||||
}
|
||||
|
||||
DdeFaceTracker::~DdeFaceTracker() {
|
||||
if(_udpSocket.isOpen())
|
||||
_udpSocket.close();
|
||||
}
|
||||
|
||||
void DdeFaceTracker::init() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::reset() {
|
||||
_reset = true;
|
||||
}
|
||||
|
||||
void DdeFaceTracker::update() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::bindTo(quint16 port) {
|
||||
bindTo(QHostAddress::Any, port);
|
||||
}
|
||||
|
||||
void DdeFaceTracker::bindTo(const QHostAddress& host, quint16 port) {
|
||||
if(_udpSocket.isOpen()) {
|
||||
_udpSocket.close();
|
||||
}
|
||||
_udpSocket.bind(host, port);
|
||||
}
|
||||
|
||||
bool DdeFaceTracker::isActive() const {
|
||||
static const int ACTIVE_TIMEOUT_USECS = 3000000; //3 secs
|
||||
return (usecTimestampNow() - _lastReceiveTimestamp < ACTIVE_TIMEOUT_USECS);
|
||||
}
|
||||
|
||||
//private slots and methods
|
||||
void DdeFaceTracker::socketErrorOccurred(QAbstractSocket::SocketError socketError) {
|
||||
qDebug() << "[Error] DDE Face Tracker Socket Error: " << _udpSocket.errorString();
|
||||
}
|
||||
|
||||
void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState) {
|
||||
QString state;
|
||||
switch(socketState) {
|
||||
case QAbstractSocket::BoundState:
|
||||
state = "Bounded";
|
||||
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;
|
||||
}
|
||||
qDebug() << "[Info] DDE Face Tracker Socket: " << socketState;
|
||||
}
|
||||
|
||||
void DdeFaceTracker::readPendingDatagrams() {
|
||||
QByteArray buffer;
|
||||
while (_udpSocket.hasPendingDatagrams()) {
|
||||
buffer.resize(_udpSocket.pendingDatagramSize());
|
||||
_udpSocket.readDatagram(buffer.data(), buffer.size());
|
||||
}
|
||||
decodePacket(buffer);
|
||||
}
|
||||
|
||||
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||
if(buffer.size() > MIN_PACKET_SIZE) {
|
||||
Packet 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) {
|
||||
memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
|
||||
memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
|
||||
_reset = false;
|
||||
}
|
||||
|
||||
// Compute relative translation
|
||||
float DAMPING_FACTOR = 40;
|
||||
translation -= _referenceTranslation;
|
||||
translation /= DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
||||
// Compute relative rotation
|
||||
rotation = glm::inverse(_referenceRotation) * rotation;
|
||||
|
||||
// copy values
|
||||
_headTranslation = translation;
|
||||
_headRotation = rotation;
|
||||
|
||||
// Set blendshapes
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
qDebug() << "[Error] DDE Face Tracker Decode Error";
|
||||
}
|
||||
_lastReceiveTimestamp = usecTimestampNow();
|
||||
}
|
||||
|
|
|
@ -12,4 +12,45 @@
|
|||
#ifndef hifi_DdeFaceTracker_h
|
||||
#define hifi_DdeFaceTracker_h
|
||||
|
||||
#include <QUdpSocket>
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
class DdeFaceTracker : public FaceTracker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DdeFaceTracker();
|
||||
DdeFaceTracker(const QHostAddress& host, quint16 port);
|
||||
~DdeFaceTracker();
|
||||
|
||||
//initialization
|
||||
void init();
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
//sockets
|
||||
void bindTo(quint16 port);
|
||||
void bindTo(const QHostAddress& host, quint16 port);
|
||||
bool isActive() const;
|
||||
|
||||
private slots:
|
||||
|
||||
//sockets
|
||||
void socketErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||
void readPendingDatagrams();
|
||||
void socketStateChanged(QAbstractSocket::SocketState socketState);
|
||||
|
||||
private:
|
||||
void decodePacket(const QByteArray& buffer);
|
||||
|
||||
// sockets
|
||||
QUdpSocket _udpSocket;
|
||||
quint64 _lastReceiveTimestamp;
|
||||
|
||||
bool _reset;
|
||||
glm::vec3 _referenceTranslation;
|
||||
glm::quat _referenceRotation;
|
||||
};
|
||||
|
||||
#endif // hifi_DdeFaceTracker_h
|
Loading…
Reference in a new issue