mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
Merge pull request #717 from machinelevel/dev4
Rave glove demo: Greatly improved Leap handling
This commit is contained in:
commit
84328057ba
7 changed files with 323 additions and 150 deletions
|
@ -2103,10 +2103,8 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
// Leap finger-sensing device
|
// Leap finger-sensing device
|
||||||
LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked());
|
LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked());
|
||||||
LeapManager::nextFrame();
|
|
||||||
_myAvatar.getHand().setRaveGloveActive(_testRaveGlove->isChecked());
|
_myAvatar.getHand().setRaveGloveActive(_testRaveGlove->isChecked());
|
||||||
_myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots());
|
LeapManager::nextFrame(_myAvatar);
|
||||||
_myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals());
|
|
||||||
|
|
||||||
// Read serial port interface devices
|
// Read serial port interface devices
|
||||||
if (_serialHeadSensor.isActive()) {
|
if (_serialHeadSensor.isActive()) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "LeapManager.h"
|
#include "LeapManager.h"
|
||||||
|
#include "avatar/Avatar.h"
|
||||||
#include <Leap.h>
|
#include <Leap.h>
|
||||||
#include <dlfcn.h> // needed for RTLD_LAZY
|
#include <dlfcn.h> // needed for RTLD_LAZY
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -16,48 +17,15 @@ bool LeapManager::_doFakeFingers = false;
|
||||||
Leap::Controller* LeapManager::_controller = NULL;
|
Leap::Controller* LeapManager::_controller = NULL;
|
||||||
HifiLeapListener* LeapManager::_listener = NULL;
|
HifiLeapListener* LeapManager::_listener = NULL;
|
||||||
|
|
||||||
namespace {
|
|
||||||
glm::vec3 fakeHandOffset(0.0f, 50.0f, 50.0f);
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
class HifiLeapListener : public Leap::Listener {
|
class HifiLeapListener : public Leap::Listener {
|
||||||
public:
|
public:
|
||||||
HifiLeapListener() {}
|
HifiLeapListener() {}
|
||||||
virtual ~HifiLeapListener() {}
|
virtual ~HifiLeapListener() {}
|
||||||
|
|
||||||
Leap::Frame lastFrame;
|
Leap::Frame lastFrame;
|
||||||
std::vector<glm::vec3> fingerTips;
|
|
||||||
std::vector<glm::vec3> fingerRoots;
|
|
||||||
std::vector<glm::vec3> handPositions;
|
|
||||||
std::vector<glm::vec3> handNormals;
|
|
||||||
|
|
||||||
virtual void onFrame(const Leap::Controller& controller) {
|
virtual void onFrame(const Leap::Controller& controller) {
|
||||||
#ifndef LEAP_STUBS
|
#ifndef LEAP_STUBS
|
||||||
Leap::Frame frame = controller.frame();
|
lastFrame = controller.frame();
|
||||||
int numFingers = frame.fingers().count();
|
|
||||||
fingerTips.resize(numFingers);
|
|
||||||
fingerRoots.resize(numFingers);
|
|
||||||
for (int i = 0; i < numFingers; ++i) {
|
|
||||||
const Leap::Finger& thisFinger = frame.fingers()[i];
|
|
||||||
const Leap::Vector pos = thisFinger.stabilizedTipPosition();
|
|
||||||
fingerTips[i] = glm::vec3(pos.x, pos.y, pos.z);
|
|
||||||
|
|
||||||
const Leap::Vector root = pos - thisFinger.direction() * thisFinger.length();
|
|
||||||
fingerRoots[i] = glm::vec3(root.x, root.y, root.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
int numHands = frame.hands().count();
|
|
||||||
handPositions.resize(numHands);
|
|
||||||
handNormals.resize(numHands);
|
|
||||||
for (int i = 0; i < numHands; ++i) {
|
|
||||||
const Leap::Hand& thisHand = frame.hands()[i];
|
|
||||||
const Leap::Vector pos = thisHand.palmPosition();
|
|
||||||
handPositions[i] = glm::vec3(pos.x, pos.y, pos.z);
|
|
||||||
|
|
||||||
const Leap::Vector norm = thisHand.palmNormal();
|
|
||||||
handNormals[i] = glm::vec3(norm.x, norm.y, norm.z);
|
|
||||||
}
|
|
||||||
lastFrame = frame;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +48,195 @@ void LeapManager::terminate() {
|
||||||
_controller = NULL;
|
_controller = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeapManager::nextFrame() {
|
void LeapManager::nextFrame(Avatar& avatar) {
|
||||||
|
// Apply the frame data directly to the avatar.
|
||||||
|
Hand& hand = avatar.getHand();
|
||||||
|
|
||||||
|
// If we actually get valid Leap data, this will be set to true;
|
||||||
|
bool gotRealData = false;
|
||||||
|
|
||||||
if (controllersExist()) {
|
if (controllersExist()) {
|
||||||
_listener->onFrame(*_controller);
|
_listener->onFrame(*_controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LEAP_STUBS
|
||||||
|
if (controllersExist()) {
|
||||||
|
gotRealData = true;
|
||||||
|
// First, see which palms and fingers are still valid.
|
||||||
|
Leap::Frame& frame = _listener->lastFrame;
|
||||||
|
|
||||||
|
// Note that this is O(n^2) at worst, but n is very small.
|
||||||
|
|
||||||
|
// After this many frames of no data, assume the digit is lost.
|
||||||
|
const int assumeLostAfterFrameCount = 10;
|
||||||
|
|
||||||
|
// Increment our frame data counters
|
||||||
|
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
||||||
|
PalmData& palm = hand.getPalms()[i];
|
||||||
|
palm.incrementFramesWithoutData();
|
||||||
|
if (palm.getFramesWithoutData() > assumeLostAfterFrameCount) {
|
||||||
|
palm.setActive(false);
|
||||||
|
}
|
||||||
|
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||||
|
FingerData& finger = palm.getFingers()[f];
|
||||||
|
finger.incrementFramesWithoutData();
|
||||||
|
if (finger.getFramesWithoutData() > assumeLostAfterFrameCount) {
|
||||||
|
finger.setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numLeapHands = frame.hands().count();
|
||||||
|
std::vector<PalmData*> palmAssignment(numLeapHands);
|
||||||
|
|
||||||
|
// Look for matches
|
||||||
|
for (size_t index = 0; index < numLeapHands; ++index) {
|
||||||
|
PalmData* takeoverCandidate = NULL;
|
||||||
|
palmAssignment[index] = NULL;
|
||||||
|
Leap::Hand leapHand = frame.hands()[index];
|
||||||
|
int id = leapHand.id();
|
||||||
|
if (leapHand.isValid()) {
|
||||||
|
for (size_t i = 0; i < hand.getNumPalms() && palmAssignment[index] == NULL; ++i) {
|
||||||
|
PalmData& palm = hand.getPalms()[i];
|
||||||
|
if (palm.getLeapID() == id) {
|
||||||
|
// Found hand with the same ID. We're set!
|
||||||
|
palmAssignment[index] = &palm;
|
||||||
|
palm.resetFramesWithoutData();
|
||||||
|
}
|
||||||
|
else if (palm.getFramesWithoutData() > assumeLostAfterFrameCount) {
|
||||||
|
takeoverCandidate = &palm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (palmAssignment[index] == NULL) {
|
||||||
|
palmAssignment[index] = takeoverCandidate;
|
||||||
|
}
|
||||||
|
if (palmAssignment[index] == NULL) {
|
||||||
|
palmAssignment[index] = &hand.addNewPalm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the assignments
|
||||||
|
for (size_t index = 0; index < numLeapHands; ++index) {
|
||||||
|
if (palmAssignment[index]) {
|
||||||
|
Leap::Hand leapHand = frame.hands()[index];
|
||||||
|
PalmData& palm = *(palmAssignment[index]);
|
||||||
|
|
||||||
|
palm.resetFramesWithoutData();
|
||||||
|
palm.setLeapID(leapHand.id());
|
||||||
|
palm.setActive(true);
|
||||||
|
const Leap::Vector pos = leapHand.palmPosition();
|
||||||
|
const Leap::Vector normal = leapHand.palmNormal();
|
||||||
|
palm.setRawPosition(glm::vec3(pos.x, pos.y, pos.z));
|
||||||
|
palm.setRawNormal(glm::vec3(normal.x, normal.y, normal.z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for fingers per palm
|
||||||
|
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
||||||
|
PalmData& palm = hand.getPalms()[i];
|
||||||
|
if (palm.isActive()) {
|
||||||
|
Leap::Hand leapHand = frame.hand(palm.getLeapID());
|
||||||
|
if (leapHand.isValid()) {
|
||||||
|
int numLeapFingers = leapHand.fingers().count();
|
||||||
|
std::vector<FingerData*> fingerAssignment(numLeapFingers);
|
||||||
|
|
||||||
|
|
||||||
|
// Look for matches
|
||||||
|
for (size_t index = 0; index < numLeapFingers; ++index) {
|
||||||
|
FingerData* takeoverCandidate = NULL;
|
||||||
|
fingerAssignment[index] = NULL;
|
||||||
|
Leap::Finger leapFinger = leapHand.fingers()[index];
|
||||||
|
int id = leapFinger.id();
|
||||||
|
if (leapFinger.isValid()) {
|
||||||
|
for (size_t f = 0; f < palm.getNumFingers() && fingerAssignment[index] == NULL; ++f) {
|
||||||
|
FingerData& finger = palm.getFingers()[f];
|
||||||
|
if (finger.getLeapID() == id) {
|
||||||
|
// Found hand with the same ID. We're set!
|
||||||
|
fingerAssignment[index] = &finger;
|
||||||
|
}
|
||||||
|
else if (finger.getFramesWithoutData() > assumeLostAfterFrameCount) {
|
||||||
|
takeoverCandidate = &finger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we didn't find a match, but we found an unused finger, us it.
|
||||||
|
if (fingerAssignment[index] == NULL) {
|
||||||
|
fingerAssignment[index] = takeoverCandidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the assignments
|
||||||
|
for (size_t index = 0; index < numLeapFingers; ++index) {
|
||||||
|
if (fingerAssignment[index]) {
|
||||||
|
Leap::Finger leapFinger = leapHand.fingers()[index];
|
||||||
|
FingerData& finger = *(fingerAssignment[index]);
|
||||||
|
|
||||||
|
finger.resetFramesWithoutData();
|
||||||
|
finger.setLeapID(leapFinger.id());
|
||||||
|
finger.setActive(true);
|
||||||
|
const Leap::Vector tip = leapFinger.stabilizedTipPosition();
|
||||||
|
const Leap::Vector root = tip - leapFinger.direction() * leapFinger.length();
|
||||||
|
finger.setRawTipPosition(glm::vec3(tip.x, tip.y, tip.z));
|
||||||
|
finger.setRawRootPosition(glm::vec3(root.x, root.y, root.z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!gotRealData) {
|
||||||
|
if (_doFakeFingers) {
|
||||||
|
// There's no real Leap data and we need to fake it.
|
||||||
|
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
||||||
|
static const glm::vec3 fakeHandOffsets[] = {
|
||||||
|
glm::vec3( -500.0f, 50.0f, 50.0f),
|
||||||
|
glm::vec3( 0.0f, 50.0f, 50.0f)
|
||||||
|
};
|
||||||
|
static const glm::vec3 fakeHandFingerMirrors[] = {
|
||||||
|
glm::vec3( -1.0f, 1.0f, 1.0f),
|
||||||
|
glm::vec3( 1.0f, 1.0f, 1.0f)
|
||||||
|
};
|
||||||
|
static const glm::vec3 fakeFingerPositions[] = {
|
||||||
|
glm::vec3( -60.0f, 0.0f, -40.0f),
|
||||||
|
glm::vec3( -20.0f, 0.0f, -60.0f),
|
||||||
|
glm::vec3( 20.0f, 0.0f, -60.0f),
|
||||||
|
glm::vec3( 60.0f, 0.0f, -40.0f),
|
||||||
|
glm::vec3( -50.0f, 0.0f, 30.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
PalmData& palm = hand.getPalms()[i];
|
||||||
|
palm.setActive(true);
|
||||||
|
// Simulated data
|
||||||
|
|
||||||
|
palm.setRawPosition(glm::vec3( 0.0f, 0.0f, 0.0f) + fakeHandOffsets[i]);
|
||||||
|
palm.setRawNormal(glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||||
|
FingerData& finger = palm.getFingers()[f];
|
||||||
|
finger.setActive(true);
|
||||||
|
const float tipScale = 1.5f;
|
||||||
|
const float rootScale = 0.75f;
|
||||||
|
glm::vec3 fingerPos = fakeFingerPositions[f] * fakeHandFingerMirrors[i];
|
||||||
|
finger.setRawTipPosition(fingerPos * tipScale + fakeHandOffsets[i]);
|
||||||
|
finger.setRawRootPosition(fingerPos * rootScale + fakeHandOffsets[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Just deactivate everything.
|
||||||
|
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
||||||
|
PalmData& palm = hand.getPalms()[i];
|
||||||
|
palm.setActive(false);
|
||||||
|
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||||
|
FingerData& finger = palm.getFingers()[f];
|
||||||
|
finger.setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hand.updateFingerTrails();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeapManager::enableFakeFingers(bool enable) {
|
void LeapManager::enableFakeFingers(bool enable) {
|
||||||
|
@ -98,77 +251,6 @@ bool LeapManager::controllersExist() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<glm::vec3>& LeapManager::getFingerTips() {
|
|
||||||
if (controllersExist()) {
|
|
||||||
return _listener->fingerTips;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
static std::vector<glm::vec3> stubData;
|
|
||||||
stubData.clear();
|
|
||||||
if (_doFakeFingers) {
|
|
||||||
// Simulated data
|
|
||||||
float scale = 1.5f;
|
|
||||||
stubData.push_back(glm::vec3( -60.0f, 0.0f, -40.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( -20.0f, 0.0f, -60.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( 20.0f, 0.0f, -60.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( 60.0f, 0.0f, -40.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( -50.0f, 0.0f, 30.0f) * scale + fakeHandOffset);
|
|
||||||
}
|
|
||||||
return stubData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<glm::vec3>& LeapManager::getFingerRoots() {
|
|
||||||
if (controllersExist()) {
|
|
||||||
return _listener->fingerRoots;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
static std::vector<glm::vec3> stubData;
|
|
||||||
stubData.clear();
|
|
||||||
if (_doFakeFingers) {
|
|
||||||
// Simulated data
|
|
||||||
float scale = 0.75f;
|
|
||||||
stubData.push_back(glm::vec3( -60.0f, 0.0f, -40.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( -20.0f, 0.0f, -60.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( 20.0f, 0.0f, -60.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( 60.0f, 0.0f, -40.0f) * scale + fakeHandOffset);
|
|
||||||
stubData.push_back(glm::vec3( -50.0f, 0.0f, 30.0f) * scale + fakeHandOffset);
|
|
||||||
}
|
|
||||||
return stubData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<glm::vec3>& LeapManager::getHandPositions() {
|
|
||||||
if (controllersExist()) {
|
|
||||||
return _listener->handPositions;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
static std::vector<glm::vec3> stubData;
|
|
||||||
stubData.clear();
|
|
||||||
if (_doFakeFingers) {
|
|
||||||
// Simulated data
|
|
||||||
glm::vec3 handOffset(0.0f, 50.0f, 50.0f);
|
|
||||||
stubData.push_back(glm::vec3( 0.0f, 0.0f, 0.0f) + fakeHandOffset);
|
|
||||||
}
|
|
||||||
return stubData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<glm::vec3>& LeapManager::getHandNormals() {
|
|
||||||
if (controllersExist()) {
|
|
||||||
return _listener->handNormals;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
static std::vector<glm::vec3> stubData;
|
|
||||||
stubData.clear();
|
|
||||||
if (_doFakeFingers) {
|
|
||||||
// Simulated data
|
|
||||||
stubData.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
|
|
||||||
}
|
|
||||||
return stubData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LeapManager::statusString() {
|
std::string LeapManager::statusString() {
|
||||||
std::stringstream leapString;
|
std::stringstream leapString;
|
||||||
#ifndef LEAP_STUBS
|
#ifndef LEAP_STUBS
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
class Avatar;
|
||||||
class HifiLeapListener;
|
class HifiLeapListener;
|
||||||
namespace Leap {
|
namespace Leap {
|
||||||
class Controller;
|
class Controller;
|
||||||
|
@ -20,7 +21,7 @@ namespace Leap {
|
||||||
|
|
||||||
class LeapManager {
|
class LeapManager {
|
||||||
public:
|
public:
|
||||||
static void nextFrame(); // called once per frame to get new Leap data
|
static void nextFrame(Avatar& avatar); // called once per frame to get new Leap data
|
||||||
static bool controllersExist(); // Returns true if there's at least one active Leap plugged in
|
static bool controllersExist(); // Returns true if there's at least one active Leap plugged in
|
||||||
static void enableFakeFingers(bool enable); // put fake data in if there's no Leap plugged in
|
static void enableFakeFingers(bool enable); // put fake data in if there's no Leap plugged in
|
||||||
static const std::vector<glm::vec3>& getFingerTips();
|
static const std::vector<glm::vec3>& getFingerTips();
|
||||||
|
|
|
@ -95,6 +95,7 @@ void Hand::render(bool lookingInMirror) {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_RESCALE_NORMAL);
|
glEnable(GL_RESCALE_NORMAL);
|
||||||
|
|
||||||
|
renderFingerTrails();
|
||||||
renderHandSpheres();
|
renderHandSpheres();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,44 +174,35 @@ void Hand::renderHandSpheres() {
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hand::setLeapFingers(const std::vector<glm::vec3>& fingerTips,
|
void Hand::renderFingerTrails() {
|
||||||
const std::vector<glm::vec3>& fingerRoots) {
|
// Draw the finger root cones
|
||||||
// TODO: add id-checking here to increase finger stability
|
|
||||||
|
|
||||||
size_t fingerIndex = 0;
|
|
||||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||||
PalmData& palm = getPalms()[i];
|
PalmData& palm = getPalms()[i];
|
||||||
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
if (palm.isActive()) {
|
||||||
FingerData& finger = palm.getFingers()[f];
|
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||||
if (fingerIndex < fingerTips.size()) {
|
FingerData& finger = palm.getFingers()[f];
|
||||||
finger.setActive(true);
|
int numPositions = finger.getTrailNumPositions();
|
||||||
finger.setRawTipPosition(fingerTips[fingerIndex]);
|
if (numPositions > 0) {
|
||||||
finger.setRawRootPosition(fingerRoots[fingerIndex]);
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
fingerIndex++;
|
for (int t = 0; t < numPositions; ++t)
|
||||||
}
|
{
|
||||||
else {
|
const glm::vec3& center = finger.getTrailPosition(t);
|
||||||
finger.setActive(false);
|
const float halfWidth = 0.001f;
|
||||||
|
const glm::vec3 edgeDirection(1.0f, 0.0f, 0.0f);
|
||||||
|
glm::vec3 edge0 = center + edgeDirection * halfWidth;
|
||||||
|
glm::vec3 edge1 = center - edgeDirection * halfWidth;
|
||||||
|
float alpha = 1.0f - ((float)t / (float)(numPositions - 1));
|
||||||
|
glColor4f(1.0f, 0.0f, 0.0f, alpha);
|
||||||
|
glVertex3fv((float*)&edge0);
|
||||||
|
glVertex3fv((float*)&edge1);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hand::setLeapHands(const std::vector<glm::vec3>& handPositions,
|
|
||||||
const std::vector<glm::vec3>& handNormals) {
|
|
||||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
|
||||||
PalmData& palm = getPalms()[i];
|
|
||||||
if (i < handPositions.size()) {
|
|
||||||
palm.setActive(true);
|
|
||||||
palm.setRawPosition(handPositions[i]);
|
|
||||||
palm.setRawNormal(handNormals[i]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
palm.setActive(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Hand::updateFingerParticles(float deltaTime) {
|
void Hand::updateFingerParticles(float deltaTime) {
|
||||||
|
|
||||||
if (!_particleSystemInitialized) {
|
if (!_particleSystemInitialized) {
|
||||||
|
|
|
@ -42,10 +42,6 @@ public:
|
||||||
void render(bool lookingInMirror);
|
void render(bool lookingInMirror);
|
||||||
|
|
||||||
void setBallColor (glm::vec3 ballColor ) { _ballColor = ballColor; }
|
void setBallColor (glm::vec3 ballColor ) { _ballColor = ballColor; }
|
||||||
void setLeapFingers (const std::vector<glm::vec3>& fingerTips,
|
|
||||||
const std::vector<glm::vec3>& fingerRoots);
|
|
||||||
void setLeapHands (const std::vector<glm::vec3>& handPositions,
|
|
||||||
const std::vector<glm::vec3>& handNormals);
|
|
||||||
void updateFingerParticles(float deltaTime);
|
void updateFingerParticles(float deltaTime);
|
||||||
void setRaveGloveActive(bool active) { _isRaveGloveActive = active; }
|
void setRaveGloveActive(bool active) { _isRaveGloveActive = active; }
|
||||||
|
|
||||||
|
@ -74,6 +70,7 @@ private:
|
||||||
// private methods
|
// private methods
|
||||||
void renderRaveGloveStage();
|
void renderRaveGloveStage();
|
||||||
void renderHandSpheres();
|
void renderHandSpheres();
|
||||||
|
void renderFingerTrails();
|
||||||
void calculateGeometry();
|
void calculateGeometry();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,22 @@ HandData::HandData(AvatarData* owningAvatar) :
|
||||||
_baseOrientation(0.0f, 0.0f, 0.0f, 1.0f),
|
_baseOrientation(0.0f, 0.0f, 0.0f, 1.0f),
|
||||||
_owningAvatarData(owningAvatar)
|
_owningAvatarData(owningAvatar)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 2; ++i) {
|
// Start with two palms
|
||||||
_palms.push_back(PalmData(this));
|
addNewPalm();
|
||||||
}
|
addNewPalm();
|
||||||
|
}
|
||||||
|
|
||||||
|
PalmData& HandData::addNewPalm() {
|
||||||
|
_palms.push_back(PalmData(this));
|
||||||
|
return _palms.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
PalmData::PalmData(HandData* owningHandData) :
|
PalmData::PalmData(HandData* owningHandData) :
|
||||||
_rawPosition(0, 0, 0),
|
_rawPosition(0, 0, 0),
|
||||||
_rawNormal(0, 1, 0),
|
_rawNormal(0, 1, 0),
|
||||||
_isActive(false),
|
_isActive(false),
|
||||||
|
_leapID(LEAPID_INVALID),
|
||||||
|
_numFramesWithoutData(0),
|
||||||
_owningHandData(owningHandData)
|
_owningHandData(owningHandData)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) {
|
for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) {
|
||||||
|
@ -33,9 +40,13 @@ FingerData::FingerData(PalmData* owningPalmData, HandData* owningHandData) :
|
||||||
_tipRawPosition(0, 0, 0),
|
_tipRawPosition(0, 0, 0),
|
||||||
_rootRawPosition(0, 0, 0),
|
_rootRawPosition(0, 0, 0),
|
||||||
_isActive(false),
|
_isActive(false),
|
||||||
|
_leapID(LEAPID_INVALID),
|
||||||
|
_numFramesWithoutData(0),
|
||||||
_owningPalmData(owningPalmData),
|
_owningPalmData(owningPalmData),
|
||||||
_owningHandData(owningHandData)
|
_owningHandData(owningHandData)
|
||||||
{
|
{
|
||||||
|
const int standardTrailLength = 30;
|
||||||
|
setTrailLength(standardTrailLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) {
|
void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) {
|
||||||
|
@ -80,3 +91,66 @@ void HandData::decodeRemoteData(const std::vector<glm::vec3>& fingerVectors) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandData::setFingerTrailLength(unsigned int length) {
|
||||||
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||||
|
PalmData& palm = getPalms()[i];
|
||||||
|
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||||
|
FingerData& finger = palm.getFingers()[f];
|
||||||
|
finger.setTrailLength(length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandData::updateFingerTrails() {
|
||||||
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||||
|
PalmData& palm = getPalms()[i];
|
||||||
|
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
||||||
|
FingerData& finger = palm.getFingers()[f];
|
||||||
|
finger.updateTrail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerData::setTrailLength(unsigned int length) {
|
||||||
|
_tipTrailPositions.resize(length);
|
||||||
|
_tipTrailCurrentStartIndex = 0;
|
||||||
|
_tipTrailCurrentValidLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FingerData::updateTrail() {
|
||||||
|
if (_tipTrailPositions.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_isActive) {
|
||||||
|
// Add the next point in the trail.
|
||||||
|
_tipTrailCurrentStartIndex--;
|
||||||
|
if (_tipTrailCurrentStartIndex < 0)
|
||||||
|
_tipTrailCurrentStartIndex = _tipTrailPositions.size() - 1;
|
||||||
|
|
||||||
|
_tipTrailPositions[_tipTrailCurrentStartIndex] = getTipPosition();
|
||||||
|
|
||||||
|
if (_tipTrailCurrentValidLength < _tipTrailPositions.size())
|
||||||
|
_tipTrailCurrentValidLength++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// It's not active, so just shorten the trail.
|
||||||
|
if (_tipTrailCurrentValidLength > 0)
|
||||||
|
_tipTrailCurrentValidLength--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int FingerData::getTrailNumPositions() {
|
||||||
|
return _tipTrailCurrentValidLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::vec3& FingerData::getTrailPosition(int index) {
|
||||||
|
if (index >= _tipTrailCurrentValidLength) {
|
||||||
|
static glm::vec3 zero(0,0,0);
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
int posIndex = (index + _tipTrailCurrentStartIndex) % _tipTrailCurrentValidLength;
|
||||||
|
return _tipTrailPositions[posIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class FingerData;
|
||||||
class PalmData;
|
class PalmData;
|
||||||
|
|
||||||
const int NUM_FINGERS_PER_HAND = 5;
|
const int NUM_FINGERS_PER_HAND = 5;
|
||||||
|
const int LEAPID_INVALID = -1;
|
||||||
|
|
||||||
class HandData {
|
class HandData {
|
||||||
public:
|
public:
|
||||||
|
@ -39,6 +40,10 @@ public:
|
||||||
|
|
||||||
std::vector<PalmData>& getPalms() { return _palms; }
|
std::vector<PalmData>& getPalms() { return _palms; }
|
||||||
size_t getNumPalms() { return _palms.size(); }
|
size_t getNumPalms() { return _palms.size(); }
|
||||||
|
PalmData& addNewPalm();
|
||||||
|
|
||||||
|
void setFingerTrailLength(unsigned int length);
|
||||||
|
void updateFingerTrails();
|
||||||
|
|
||||||
// Use these for sending and receiving hand data
|
// Use these for sending and receiving hand data
|
||||||
void encodeRemoteData(std::vector<glm::vec3>& fingerVectors);
|
void encodeRemoteData(std::vector<glm::vec3>& fingerVectors);
|
||||||
|
@ -65,15 +70,31 @@ public:
|
||||||
const glm::vec3& getTipRawPosition() const { return _tipRawPosition; }
|
const glm::vec3& getTipRawPosition() const { return _tipRawPosition; }
|
||||||
const glm::vec3& getRootRawPosition() const { return _rootRawPosition; }
|
const glm::vec3& getRootRawPosition() const { return _rootRawPosition; }
|
||||||
bool isActive() const { return _isActive; }
|
bool isActive() const { return _isActive; }
|
||||||
|
int getLeapID() const { return _leapID; }
|
||||||
|
|
||||||
void setActive(bool active) { _isActive = active; }
|
void setActive(bool active) { _isActive = active; }
|
||||||
|
void setLeapID(int id) { _leapID = id; }
|
||||||
void setRawTipPosition(const glm::vec3& pos) { _tipRawPosition = pos; }
|
void setRawTipPosition(const glm::vec3& pos) { _tipRawPosition = pos; }
|
||||||
void setRawRootPosition(const glm::vec3& pos) { _rootRawPosition = pos; }
|
void setRawRootPosition(const glm::vec3& pos) { _rootRawPosition = pos; }
|
||||||
|
void setTrailLength(unsigned int length);
|
||||||
|
void updateTrail();
|
||||||
|
|
||||||
|
int getTrailNumPositions();
|
||||||
|
const glm::vec3& getTrailPosition(int index);
|
||||||
|
|
||||||
|
void incrementFramesWithoutData() { _numFramesWithoutData++; }
|
||||||
|
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
|
||||||
|
int getFramesWithoutData() const { return _numFramesWithoutData; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 _tipRawPosition;
|
glm::vec3 _tipRawPosition;
|
||||||
glm::vec3 _rootRawPosition;
|
glm::vec3 _rootRawPosition;
|
||||||
bool _isActive; // This has current valid data
|
bool _isActive; // This has current valid data
|
||||||
|
int _leapID; // the Leap's serial id for this tracked object
|
||||||
|
int _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost.
|
||||||
|
std::vector<glm::vec3> _tipTrailPositions;
|
||||||
|
int _tipTrailCurrentStartIndex;
|
||||||
|
int _tipTrailCurrentValidLength;
|
||||||
PalmData* _owningPalmData;
|
PalmData* _owningPalmData;
|
||||||
HandData* _owningHandData;
|
HandData* _owningHandData;
|
||||||
};
|
};
|
||||||
|
@ -86,19 +107,27 @@ public:
|
||||||
const glm::vec3& getRawPosition() const { return _rawPosition; }
|
const glm::vec3& getRawPosition() const { return _rawPosition; }
|
||||||
const glm::vec3& getRawNormal() const { return _rawNormal; }
|
const glm::vec3& getRawNormal() const { return _rawNormal; }
|
||||||
bool isActive() const { return _isActive; }
|
bool isActive() const { return _isActive; }
|
||||||
|
int getLeapID() const { return _leapID; }
|
||||||
|
|
||||||
std::vector<FingerData>& getFingers() { return _fingers; }
|
std::vector<FingerData>& getFingers() { return _fingers; }
|
||||||
size_t getNumFingers() { return _fingers.size(); }
|
size_t getNumFingers() { return _fingers.size(); }
|
||||||
|
|
||||||
void setActive(bool active) { _isActive = active; }
|
void setActive(bool active) { _isActive = active; }
|
||||||
|
void setLeapID(int id) { _leapID = id; }
|
||||||
void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; }
|
void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; }
|
||||||
void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; }
|
void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; }
|
||||||
|
|
||||||
|
void incrementFramesWithoutData() { _numFramesWithoutData++; }
|
||||||
|
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
|
||||||
|
int getFramesWithoutData() const { return _numFramesWithoutData; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<FingerData> _fingers;
|
std::vector<FingerData> _fingers;
|
||||||
glm::vec3 _rawPosition;
|
glm::vec3 _rawPosition;
|
||||||
glm::vec3 _rawNormal;
|
glm::vec3 _rawNormal;
|
||||||
bool _isActive; // This has current valid data
|
bool _isActive; // This has current valid data
|
||||||
|
int _leapID; // the Leap's serial id for this tracked object
|
||||||
|
int _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost.
|
||||||
HandData* _owningHandData;
|
HandData* _owningHandData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue