mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:44:21 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into modelserver
This commit is contained in:
commit
62eb8335e9
14 changed files with 361 additions and 57 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -46,5 +46,9 @@ interface/resources/visage/*
|
|||
interface/external/faceplus/*
|
||||
!interface/external/faceplus/readme.txt
|
||||
|
||||
# Ignore PrioVR
|
||||
interface/external/priovr/*
|
||||
!interface/external/priovr/readme.txt
|
||||
|
||||
# Ignore interfaceCache for Linux users
|
||||
interface/interfaceCache/
|
||||
|
|
42
cmake/modules/FindPrioVR.cmake
Normal file
42
cmake/modules/FindPrioVR.cmake
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Try to find the PrioVT library
|
||||
#
|
||||
# You must provide a PRIOVR_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# PRIOVR_FOUND - system found PrioVR
|
||||
# PRIOVR_INCLUDE_DIRS - the PrioVR include directory
|
||||
# PRIOVR_LIBRARIES - Link this to use PrioVR
|
||||
#
|
||||
# Created on 5/12/2014 by Andrzej Kapolka
|
||||
# Copyright (c) 2014 High Fidelity
|
||||
#
|
||||
|
||||
if (PRIOVR_LIBRARIES AND PRIOVR_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(PRIOVR_FOUND TRUE)
|
||||
else (PRIOVR_LIBRARIES AND PRIOVR_INCLUDE_DIRS)
|
||||
find_path(PRIOVR_INCLUDE_DIRS yei_skeletal_api.h ${PRIOVR_ROOT_DIR}/include)
|
||||
|
||||
if (WIN32)
|
||||
find_library(PRIOVR_LIBRARIES Skeletal_API.lib ${PRIOVR_ROOT_DIR}/lib)
|
||||
endif (WIN32)
|
||||
|
||||
if (PRIOVR_INCLUDE_DIRS AND PRIOVR_LIBRARIES)
|
||||
set(PRIOVR_FOUND TRUE)
|
||||
endif (PRIOVR_INCLUDE_DIRS AND PRIOVR_LIBRARIES)
|
||||
|
||||
if (PRIOVR_FOUND)
|
||||
if (NOT PRIOVR_FIND_QUIETLY)
|
||||
message(STATUS "Found PrioVR... ${PRIOVR_LIBRARIES}")
|
||||
endif (NOT PRIOVR_FIND_QUIETLY)
|
||||
else ()
|
||||
if (PRIOVR_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find PrioVR")
|
||||
endif (PRIOVR_FIND_REQUIRED)
|
||||
endif ()
|
||||
|
||||
# show the PRIOVR_INCLUDE_DIRS and PRIOVR_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
||||
|
||||
endif (PRIOVR_LIBRARIES AND PRIOVR_INCLUDE_DIRS)
|
|
@ -15,6 +15,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake
|
|||
set(FACEPLUS_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/faceplus")
|
||||
set(FACESHIFT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/faceshift")
|
||||
set(LIBOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/oculus")
|
||||
set(PRIOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/priovr")
|
||||
set(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense")
|
||||
set(VISAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/visage")
|
||||
|
||||
|
@ -134,6 +135,7 @@ link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}")
|
|||
find_package(Faceplus)
|
||||
find_package(Faceshift)
|
||||
find_package(LibOVR)
|
||||
find_package(PrioVR)
|
||||
find_package(Sixense)
|
||||
find_package(Visage)
|
||||
find_package(ZLIB)
|
||||
|
@ -184,6 +186,13 @@ if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
|||
target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}")
|
||||
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
|
||||
# and with PrioVR library
|
||||
if (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
|
||||
add_definitions(-DHAVE_PRIOVR)
|
||||
include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}")
|
||||
target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}")
|
||||
endif (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
|
||||
|
||||
# and with qxmpp for chat
|
||||
if (QXMPP_FOUND AND NOT DISABLE_QXMPP)
|
||||
add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
|
||||
|
|
16
interface/external/priovr/readme.txt
vendored
Normal file
16
interface/external/priovr/readme.txt
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
Instructions for adding the PrioVR driver to Interface
|
||||
Andrzej Kapolka, May 12, 2014
|
||||
|
||||
1. Download and install the YEI drivers from https://www.yeitechnology.com/yei-3-space-sensor-software-suite. If using
|
||||
Window 8+, follow the workaround instructions at http://forum.yeitechnology.com/viewtopic.php?f=3&t=24.
|
||||
|
||||
2. Get the PrioVR skeleton API, open ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/ThreeSpace_API_2.sln
|
||||
in Visual Studio, and build it.
|
||||
|
||||
3. Copy ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Skeletal_API/yei_skeletal_api.h to interface/external/priovr/include,
|
||||
ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Debug/Skeletal_API.lib to interface/external/priovr/lib, and
|
||||
ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Debug/*.dll to your path.
|
||||
|
||||
4. Delete your build directory, run cmake and build, and you should be all set.
|
||||
|
|
@ -1982,6 +1982,7 @@ void Application::update(float deltaTime) {
|
|||
_myAvatar->updateLookAtTargetAvatar();
|
||||
updateMyAvatarLookAtPosition();
|
||||
_sixenseManager.update(deltaTime);
|
||||
_prioVR.update();
|
||||
updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
_avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them...
|
||||
|
@ -2751,6 +2752,9 @@ void Application::displayOverlay() {
|
|||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
||||
}
|
||||
|
||||
// give external parties a change to hook in
|
||||
emit renderingOverlay();
|
||||
|
||||
_overlays.render2D();
|
||||
|
||||
glPopMatrix();
|
||||
|
@ -3059,6 +3063,8 @@ void Application::resetSensors() {
|
|||
OculusManager::reset();
|
||||
}
|
||||
|
||||
_prioVR.reset();
|
||||
|
||||
QCursor::setPos(_mouseX, _mouseY);
|
||||
_myAvatar->reset();
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "avatar/MyAvatar.h"
|
||||
#include "devices/Faceplus.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/PrioVR.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "devices/Visage.h"
|
||||
#include "models/ModelTreeRenderer.h"
|
||||
|
@ -194,6 +195,7 @@ public:
|
|||
Visage* getVisage() { return &_visage; }
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
SixenseManager* getSixenseManager() { return &_sixenseManager; }
|
||||
PrioVR* getPrioVR() { return &_prioVR; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
|
||||
|
@ -267,6 +269,9 @@ signals:
|
|||
/// Fired when we're rendering in-world interface elements; allows external parties to hook in.
|
||||
void renderingInWorldInterface();
|
||||
|
||||
/// Fired when we're rendering the overlay.
|
||||
void renderingOverlay();
|
||||
|
||||
/// Fired when the import window is closed
|
||||
void importDone();
|
||||
|
||||
|
@ -442,6 +447,7 @@ private:
|
|||
Visage _visage;
|
||||
|
||||
SixenseManager _sixenseManager;
|
||||
PrioVR _prioVR;
|
||||
|
||||
Camera _myCamera; // My view onto the world
|
||||
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||
|
|
|
@ -111,7 +111,7 @@ void MyAvatar::reset() {
|
|||
void MyAvatar::update(float deltaTime) {
|
||||
Head* head = getHead();
|
||||
head->relaxLean(deltaTime);
|
||||
updateFromFaceTracker(deltaTime);
|
||||
updateFromTrackers(deltaTime);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) {
|
||||
// Faceshift drive is enabled, set the avatar drive based on the head position
|
||||
moveWithLean();
|
||||
|
@ -234,26 +234,33 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
void MyAvatar::updateFromFaceTracker(float deltaTime) {
|
||||
void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||
glm::vec3 estimatedPosition, estimatedRotation;
|
||||
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
estimatedPosition = tracker->getHeadTranslation();
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
|
||||
|
||||
// Rotate the body if the head is turned beyond the screen
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
|
||||
const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
|
||||
const float TRACKER_MIN_YAW_TURN = 15.0f;
|
||||
const float TRACKER_MAX_YAW_TURN = 50.0f;
|
||||
if ( (fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) &&
|
||||
(fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN) ) {
|
||||
if (estimatedRotation.y > 0.0f) {
|
||||
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
} else {
|
||||
_bodyYawDelta += (estimatedRotation.y + TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
}
|
||||
if (Application::getInstance()->getPrioVR()->isActive()) {
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation()));
|
||||
estimatedRotation.x *= -1.0f;
|
||||
estimatedRotation.z *= -1.0f;
|
||||
|
||||
} else {
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
estimatedPosition = tracker->getHeadTranslation();
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate the body if the head is turned beyond the screen
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
|
||||
const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
|
||||
const float TRACKER_MIN_YAW_TURN = 15.0f;
|
||||
const float TRACKER_MAX_YAW_TURN = 50.0f;
|
||||
if ( (fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) &&
|
||||
(fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN) ) {
|
||||
if (estimatedRotation.y > 0.0f) {
|
||||
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
} else {
|
||||
_bodyYawDelta += (estimatedRotation.y + TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -271,6 +278,14 @@ void MyAvatar::updateFromFaceTracker(float deltaTime) {
|
|||
head->setDeltaYaw(estimatedRotation.y * magnifyFieldOfView);
|
||||
head->setDeltaRoll(estimatedRotation.z);
|
||||
|
||||
// the priovr can give us exact lean
|
||||
if (Application::getInstance()->getPrioVR()->isActive()) {
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getTorsoRotation()));
|
||||
head->setLeanSideways(eulers.z);
|
||||
head->setLeanForward(eulers.x);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = 0.5f;
|
||||
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
void reset();
|
||||
void update(float deltaTime);
|
||||
void simulate(float deltaTime);
|
||||
void updateFromFaceTracker(float deltaTime);
|
||||
void updateFromTrackers(float deltaTime);
|
||||
void moveWithLean();
|
||||
|
||||
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE);
|
||||
|
|
|
@ -33,14 +33,28 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
return; // only simulate for own avatar
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
PrioVR* prioVR = Application::getInstance()->getPrioVR();
|
||||
if (prioVR->isActive()) {
|
||||
for (int i = 0; i < prioVR->getJointRotations().size(); i++) {
|
||||
int humanIKJointIndex = prioVR->getHumanIKJointIndices().at(i);
|
||||
if (humanIKJointIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex);
|
||||
if (jointIndex != -1) {
|
||||
setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// find the left and rightmost active palms
|
||||
int leftPalmIndex, rightPalmIndex;
|
||||
Hand* hand = _owningAvatar->getHand();
|
||||
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
|
||||
|
||||
const float HAND_RESTORATION_RATE = 0.25f;
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const float HAND_RESTORATION_RATE = 0.25f;
|
||||
if (leftPalmIndex == -1) {
|
||||
// palms are not yet set, use mouse
|
||||
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
|
||||
|
@ -186,7 +200,7 @@ void SkeletonModel::updateJointState(int index) {
|
|||
}
|
||||
|
||||
void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
if (!_owningAvatar->isMyAvatar()) {
|
||||
if (!_owningAvatar->isMyAvatar() || Application::getInstance()->getPrioVR()->isActive()) {
|
||||
return;
|
||||
}
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
|
|
117
interface/src/devices/PrioVR.cpp
Normal file
117
interface/src/devices/PrioVR.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// PrioVR.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/12/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
#include <FBXReader.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "PrioVR.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
const unsigned int SERIAL_LIST[] = { 0x00000001, 0x00000000, 0x00000008, 0x00000009, 0x0000000A,
|
||||
0x0000000C, 0x0000000D, 0x0000000E, 0x00000004, 0x00000005, 0x00000010, 0x00000011 };
|
||||
const unsigned char AXIS_LIST[] = { 9, 43, 37, 37, 37, 13, 13, 13, 52, 52, 28, 28 };
|
||||
const int LIST_LENGTH = sizeof(SERIAL_LIST) / sizeof(SERIAL_LIST[0]);
|
||||
|
||||
const char* JOINT_NAMES[] = { "Neck", "Spine", "LeftArm", "LeftForeArm", "LeftHand", "RightArm",
|
||||
"RightForeArm", "RightHand", "LeftUpLeg", "LeftLeg", "RightUpLeg", "RightLeg" };
|
||||
|
||||
#ifdef HAVE_PRIOVR
|
||||
static int indexOfHumanIKJoint(const char* jointName) {
|
||||
for (int i = 0;; i++) {
|
||||
QByteArray humanIKJoint = HUMANIK_JOINTS[i];
|
||||
if (humanIKJoint.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
if (humanIKJoint == jointName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PrioVR::PrioVR() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
char jointsDiscovered[LIST_LENGTH];
|
||||
_skeletalDevice = yei_setUpPrioVRSensors(0x00000000, const_cast<unsigned int*>(SERIAL_LIST),
|
||||
const_cast<unsigned char*>(AXIS_LIST), jointsDiscovered, LIST_LENGTH, YEI_TIMESTAMP_SYSTEM);
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
_jointRotations.resize(LIST_LENGTH);
|
||||
for (int i = 0; i < LIST_LENGTH; i++) {
|
||||
_humanIKJointIndices.append(jointsDiscovered[i] ? indexOfHumanIKJoint(JOINT_NAMES[i]) : -1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PrioVR::~PrioVR() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (_skeletalDevice) {
|
||||
yei_stopStreaming(_skeletalDevice);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
glm::quat PrioVR::getHeadRotation() const {
|
||||
const int HEAD_ROTATION_INDEX = 0;
|
||||
return _jointRotations.size() > HEAD_ROTATION_INDEX ? _jointRotations.at(HEAD_ROTATION_INDEX) : glm::quat();
|
||||
}
|
||||
|
||||
glm::quat PrioVR::getTorsoRotation() const {
|
||||
const int TORSO_ROTATION_INDEX = 1;
|
||||
return _jointRotations.size() > TORSO_ROTATION_INDEX ? _jointRotations.at(TORSO_ROTATION_INDEX) : glm::quat();
|
||||
}
|
||||
|
||||
void PrioVR::update() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
unsigned int timestamp;
|
||||
yei_getLastStreamDataAll(_skeletalDevice, (char*)_jointRotations.data(),
|
||||
_jointRotations.size() * sizeof(glm::quat), ×tamp);
|
||||
|
||||
// convert to our expected coordinate system
|
||||
for (int i = 0; i < _jointRotations.size(); i++) {
|
||||
_jointRotations[i].y *= -1.0f;
|
||||
_jointRotations[i].z *= -1.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrioVR::reset() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
connect(Application::getInstance(), SIGNAL(renderingOverlay()), SLOT(renderCalibrationCountdown()));
|
||||
_calibrationCountdownStarted = QDateTime::currentDateTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrioVR::renderCalibrationCountdown() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
const int COUNTDOWN_SECONDS = 3;
|
||||
int secondsRemaining = COUNTDOWN_SECONDS - _calibrationCountdownStarted.secsTo(QDateTime::currentDateTime());
|
||||
if (secondsRemaining == 0) {
|
||||
yei_tareSensors(_skeletalDevice);
|
||||
Application::getInstance()->disconnect(this);
|
||||
return;
|
||||
}
|
||||
static TextRenderer textRenderer(MONO_FONT_FAMILY, 18, QFont::Bold, false, TextRenderer::OUTLINE_EFFECT, 2);
|
||||
QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "...";
|
||||
textRenderer.draw((Application::getInstance()->getGLWidget()->width() - textRenderer.computeWidth(text.constData())) / 2,
|
||||
Application::getInstance()->getGLWidget()->height() / 2,
|
||||
text);
|
||||
#endif
|
||||
}
|
62
interface/src/devices/PrioVR.h
Normal file
62
interface/src/devices/PrioVR.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// PrioVR.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/12/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_PrioVR_h
|
||||
#define hifi_PrioVR_h
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#ifdef HAVE_PRIOVR
|
||||
extern "C" {
|
||||
#include <yei_skeletal_api.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Handles interaction with the PrioVR skeleton tracking suit.
|
||||
class PrioVR : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PrioVR();
|
||||
virtual ~PrioVR();
|
||||
|
||||
bool isActive() const { return !_jointRotations.isEmpty(); }
|
||||
|
||||
glm::quat getHeadRotation() const;
|
||||
glm::quat getTorsoRotation() const;
|
||||
|
||||
const QVector<int>& getHumanIKJointIndices() const { return _humanIKJointIndices; }
|
||||
const QVector<glm::quat>& getJointRotations() const { return _jointRotations; }
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
private slots:
|
||||
|
||||
void renderCalibrationCountdown();
|
||||
|
||||
private:
|
||||
#ifdef HAVE_PRIOVR
|
||||
YEI_Device_Id _skeletalDevice;
|
||||
#endif
|
||||
|
||||
QVector<int> _humanIKJointIndices;
|
||||
QVector<glm::quat> _jointRotations;
|
||||
|
||||
QDateTime _calibrationCountdownStarted;
|
||||
};
|
||||
|
||||
#endif // hifi_PrioVR_h
|
|
@ -55,7 +55,8 @@ Visage::Visage() :
|
|||
Visage::~Visage() {
|
||||
#ifdef HAVE_VISAGE
|
||||
_tracker->stop();
|
||||
delete _tracker;
|
||||
// deleting the tracker crashes windows; disable for now
|
||||
//delete _tracker;
|
||||
delete _data;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -577,6 +577,25 @@ const char* FACESHIFT_BLENDSHAPES[] = {
|
|||
""
|
||||
};
|
||||
|
||||
const char* HUMANIK_JOINTS[] = {
|
||||
"RightHand",
|
||||
"RightForeArm",
|
||||
"RightArm",
|
||||
"Head",
|
||||
"LeftArm",
|
||||
"LeftForeArm",
|
||||
"LeftHand",
|
||||
"Spine",
|
||||
"Hips",
|
||||
"RightUpLeg",
|
||||
"LeftUpLeg",
|
||||
"RightLeg",
|
||||
"LeftLeg",
|
||||
"RightFoot",
|
||||
"LeftFoot",
|
||||
""
|
||||
};
|
||||
|
||||
class FBXModel {
|
||||
public:
|
||||
QString name;
|
||||
|
@ -1012,10 +1031,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
QString jointHeadName = processID(getString(joints.value("jointHead", "jointHead")));
|
||||
QString jointLeftHandName = processID(getString(joints.value("jointLeftHand", "jointLeftHand")));
|
||||
QString jointRightHandName = processID(getString(joints.value("jointRightHand", "jointRightHand")));
|
||||
QVariantList jointLeftFingerNames = joints.values("jointLeftFinger");
|
||||
QVariantList jointRightFingerNames = joints.values("jointRightFinger");
|
||||
QVariantList jointLeftFingertipNames = joints.values("jointLeftFingertip");
|
||||
QVariantList jointRightFingertipNames = joints.values("jointRightFingertip");
|
||||
QString jointEyeLeftID;
|
||||
QString jointEyeRightID;
|
||||
QString jointNeckID;
|
||||
|
@ -1024,10 +1039,16 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
QString jointHeadID;
|
||||
QString jointLeftHandID;
|
||||
QString jointRightHandID;
|
||||
QVector<QString> jointLeftFingerIDs(jointLeftFingerNames.size());
|
||||
QVector<QString> jointRightFingerIDs(jointRightFingerNames.size());
|
||||
QVector<QString> jointLeftFingertipIDs(jointLeftFingertipNames.size());
|
||||
QVector<QString> jointRightFingertipIDs(jointRightFingertipNames.size());
|
||||
|
||||
QVector<QString> humanIKJointNames;
|
||||
for (int i = 0;; i++) {
|
||||
QByteArray jointName = HUMANIK_JOINTS[i];
|
||||
if (jointName.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
humanIKJointNames.append(processID(getString(joints.value(jointName, jointName))));
|
||||
}
|
||||
QVector<QString> humanIKJointIDs(humanIKJointNames.size());
|
||||
|
||||
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
|
||||
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
|
||||
|
@ -1091,7 +1112,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
} else {
|
||||
name = getID(object.properties);
|
||||
}
|
||||
int index;
|
||||
if (name == jointEyeLeftName || name == "EyeL" || name == "joint_Leye") {
|
||||
jointEyeLeftID = getID(object.properties);
|
||||
|
||||
|
@ -1115,19 +1135,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
|
||||
} else if (name == jointRightHandName) {
|
||||
jointRightHandID = getID(object.properties);
|
||||
|
||||
} else if ((index = jointLeftFingerNames.indexOf(name)) != -1) {
|
||||
jointLeftFingerIDs[index] = getID(object.properties);
|
||||
|
||||
} else if ((index = jointRightFingerNames.indexOf(name)) != -1) {
|
||||
jointRightFingerIDs[index] = getID(object.properties);
|
||||
|
||||
} else if ((index = jointLeftFingertipNames.indexOf(name)) != -1) {
|
||||
jointLeftFingertipIDs[index] = getID(object.properties);
|
||||
|
||||
} else if ((index = jointRightFingertipNames.indexOf(name)) != -1) {
|
||||
jointRightFingertipIDs[index] = getID(object.properties);
|
||||
}
|
||||
int humanIKJointIndex = humanIKJointNames.indexOf(name);
|
||||
if (humanIKJointIndex != -1) {
|
||||
humanIKJointIDs[humanIKJointIndex] = getID(object.properties);
|
||||
}
|
||||
|
||||
glm::vec3 translation;
|
||||
// NOTE: the euler angles as supplied by the FBX file are in degrees
|
||||
glm::vec3 rotationOffset;
|
||||
|
@ -1352,7 +1365,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
} else if (type.contains("bump") || type.contains("normal")) {
|
||||
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
} else if (type.contains("specular")) {
|
||||
} else if (type.contains("specular") || type.contains("reflection")) {
|
||||
specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
} else if (type == "lcl rotation") {
|
||||
|
@ -1514,11 +1527,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
geometry.headJointIndex = modelIDs.indexOf(jointHeadID);
|
||||
geometry.leftHandJointIndex = modelIDs.indexOf(jointLeftHandID);
|
||||
geometry.rightHandJointIndex = modelIDs.indexOf(jointRightHandID);
|
||||
geometry.leftFingerJointIndices = getIndices(jointLeftFingerIDs, modelIDs);
|
||||
geometry.rightFingerJointIndices = getIndices(jointRightFingerIDs, modelIDs);
|
||||
geometry.leftFingertipJointIndices = getIndices(jointLeftFingertipIDs, modelIDs);
|
||||
geometry.rightFingertipJointIndices = getIndices(jointRightFingertipIDs, modelIDs);
|
||||
|
||||
|
||||
foreach (const QString& id, humanIKJointIDs) {
|
||||
geometry.humanIKJointIndices.append(modelIDs.indexOf(id));
|
||||
}
|
||||
|
||||
// extract the translation component of the neck transform
|
||||
if (geometry.neckJointIndex != -1) {
|
||||
const glm::mat4& transform = geometry.joints.at(geometry.neckJointIndex).transform;
|
||||
|
|
|
@ -30,6 +30,9 @@ typedef QList<FBXNode> FBXNodeList;
|
|||
/// The names of the blendshapes expected by Faceshift, terminated with an empty string.
|
||||
extern const char* FACESHIFT_BLENDSHAPES[];
|
||||
|
||||
/// The names of the joints in the Maya HumanIK rig, terminated with an empty string.
|
||||
extern const char* HUMANIK_JOINTS[];
|
||||
|
||||
class Extents {
|
||||
public:
|
||||
/// set minimum and maximum to FLT_MAX and -FLT_MAX respectively
|
||||
|
@ -199,11 +202,7 @@ public:
|
|||
int leftHandJointIndex;
|
||||
int rightHandJointIndex;
|
||||
|
||||
QVector<int> leftFingerJointIndices;
|
||||
QVector<int> rightFingerJointIndices;
|
||||
|
||||
QVector<int> leftFingertipJointIndices;
|
||||
QVector<int> rightFingertipJointIndices;
|
||||
QVector<int> humanIKJointIndices;
|
||||
|
||||
glm::vec3 palmDirection;
|
||||
|
||||
|
|
Loading…
Reference in a new issue