mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 16:53:16 +02:00
Rave glove: stabilization of Leap hands
This commit is contained in:
parent
262851346c
commit
b8cf4a9775
3 changed files with 108 additions and 89 deletions
|
@ -54,15 +54,6 @@ void LeapManager::nextFrame(Avatar& avatar) {
|
||||||
|
|
||||||
// If we actually get valid Leap data, this will be set to true;
|
// If we actually get valid Leap data, this will be set to true;
|
||||||
bool gotRealData = false;
|
bool gotRealData = false;
|
||||||
// First, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controllersExist()) {
|
if (controllersExist()) {
|
||||||
_listener->onFrame(*_controller);
|
_listener->onFrame(*_controller);
|
||||||
|
@ -70,57 +61,70 @@ void LeapManager::nextFrame(Avatar& avatar) {
|
||||||
|
|
||||||
#ifndef LEAP_STUBS
|
#ifndef LEAP_STUBS
|
||||||
if (controllersExist()) {
|
if (controllersExist()) {
|
||||||
// Performance note:
|
gotRealData = true;
|
||||||
// This is a first pass.
|
|
||||||
// Once all of this is stable, perfoamance may be improved ysing std::map or another
|
|
||||||
// associative container to match serialized Leap ID's with available fingers.
|
|
||||||
// That will make this code shorter and more efficient.
|
|
||||||
|
|
||||||
// First, see which palms and fingers are still valid.
|
// First, see which palms and fingers are still valid.
|
||||||
Leap::Frame& frame = _listener->lastFrame;
|
Leap::Frame& frame = _listener->lastFrame;
|
||||||
|
|
||||||
// Note that this is O(n^2) at worst, but n is very small.
|
// 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();
|
size_t numLeapHands = frame.hands().count();
|
||||||
std::vector<PalmData*> palmAssignment(numLeapHands);
|
std::vector<PalmData*> palmAssignment(numLeapHands);
|
||||||
|
|
||||||
// Look for matches
|
// Look for matches
|
||||||
for (size_t index = 0; index < numLeapHands; ++index) {
|
for (size_t index = 0; index < numLeapHands; ++index) {
|
||||||
|
PalmData* takeoverCandidate = NULL;
|
||||||
palmAssignment[index] = NULL;
|
palmAssignment[index] = NULL;
|
||||||
Leap::Hand leapHand = frame.hands()[index];
|
Leap::Hand leapHand = frame.hands()[index];
|
||||||
int id = leapHand.id();
|
int id = leapHand.id();
|
||||||
if (leapHand.isValid()) {
|
if (leapHand.isValid()) {
|
||||||
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
for (size_t i = 0; i < hand.getNumPalms() && palmAssignment[index] == NULL; ++i) {
|
||||||
PalmData& palm = hand.getPalms()[i];
|
PalmData& palm = hand.getPalms()[i];
|
||||||
if (palm.getLeapID() == id) {
|
if (palm.getLeapID() == id) {
|
||||||
// Found hand with the same ID. We're set!
|
// Found hand with the same ID. We're set!
|
||||||
palmAssignment[index] = &palm;
|
palmAssignment[index] = &palm;
|
||||||
palm.setActive(true);
|
palm.resetFramesWithoutData();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Fill empty slots
|
|
||||||
for (size_t index = 0; index < numLeapHands; ++index) {
|
|
||||||
if (palmAssignment[index] == NULL) {
|
|
||||||
Leap::Hand leapHand = frame.hands()[index];
|
|
||||||
if (leapHand.isValid()) {
|
|
||||||
for (size_t i = 0; i < hand.getNumPalms() && palmAssignment[index] == NULL; ++i) {
|
|
||||||
PalmData& palm = hand.getPalms()[i];
|
|
||||||
if (!palm.isActive()) {
|
|
||||||
// Found a free hand to use.
|
|
||||||
palmAssignment[index] = &palm;
|
|
||||||
palm.setActive(true);
|
|
||||||
palm.setLeapID(leapHand.id());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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
|
// Apply the assignments
|
||||||
for (size_t index = 0; index < numLeapHands; ++index) {
|
for (size_t index = 0; index < numLeapHands; ++index) {
|
||||||
if (palmAssignment[index]) {
|
if (palmAssignment[index]) {
|
||||||
Leap::Hand leapHand = frame.hands()[index];
|
Leap::Hand leapHand = frame.hands()[index];
|
||||||
PalmData& palm = *(palmAssignment[index]);
|
PalmData& palm = *(palmAssignment[index]);
|
||||||
|
|
||||||
|
palm.resetFramesWithoutData();
|
||||||
|
palm.setLeapID(leapHand.id());
|
||||||
|
palm.setActive(true);
|
||||||
const Leap::Vector pos = leapHand.palmPosition();
|
const Leap::Vector pos = leapHand.palmPosition();
|
||||||
const Leap::Vector normal = leapHand.palmNormal();
|
const Leap::Vector normal = leapHand.palmNormal();
|
||||||
palm.setRawPosition(glm::vec3(pos.x, pos.y, pos.z));
|
palm.setRawPosition(glm::vec3(pos.x, pos.y, pos.z));
|
||||||
|
@ -128,59 +132,58 @@ void LeapManager::nextFrame(Avatar& avatar) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t numLeapFingers = frame.fingers().count();
|
// Look for fingers per palm
|
||||||
std::vector<FingerData*> fingerAssignment(numLeapFingers);
|
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
||||||
// Look for matches
|
PalmData& palm = hand.getPalms()[i];
|
||||||
for (size_t index = 0; index < numLeapFingers; ++index) {
|
if (palm.isActive()) {
|
||||||
fingerAssignment[index] = NULL;
|
Leap::Hand leapHand = frame.hand(palm.getLeapID());
|
||||||
Leap::Finger leapFinger = frame.fingers()[index];
|
if (leapHand.isValid()) {
|
||||||
int id = leapFinger.id();
|
int numLeapFingers = leapHand.fingers().count();
|
||||||
if (leapFinger.isValid()) {
|
std::vector<FingerData*> fingerAssignment(numLeapFingers);
|
||||||
for (size_t i = 0; i < hand.getNumPalms(); ++i) {
|
|
||||||
PalmData& palm = hand.getPalms()[i];
|
|
||||||
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
|
// Look for matches
|
||||||
FingerData& finger = palm.getFingers()[f];
|
for (size_t index = 0; index < numLeapFingers; ++index) {
|
||||||
if (finger.getLeapID() == id) {
|
FingerData* takeoverCandidate = NULL;
|
||||||
// Found finger with the same ID. We're set!
|
fingerAssignment[index] = NULL;
|
||||||
fingerAssignment[index] = &finger;
|
Leap::Finger leapFinger = leapHand.fingers()[index];
|
||||||
finger.setActive(true);
|
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!
|
||||||
// Fill empty slots
|
fingerAssignment[index] = &finger;
|
||||||
for (size_t index = 0; index < numLeapFingers; ++index) {
|
}
|
||||||
if (fingerAssignment[index] == NULL) {
|
else if (finger.getFramesWithoutData() > assumeLostAfterFrameCount) {
|
||||||
Leap::Finger leapFinger = frame.fingers()[index];
|
takeoverCandidate = &finger;
|
||||||
if (leapFinger.isValid()) {
|
}
|
||||||
for (size_t i = 0; i < hand.getNumPalms() && fingerAssignment[index] == NULL; ++i) {
|
}
|
||||||
PalmData& palm = hand.getPalms()[i];
|
// If we didn't find a match, but we found an unused finger, us it.
|
||||||
for (size_t f = 0; f < palm.getNumFingers() && fingerAssignment[index] == NULL; ++f) {
|
if (fingerAssignment[index] == NULL) {
|
||||||
FingerData& finger = palm.getFingers()[f];
|
fingerAssignment[index] = takeoverCandidate;
|
||||||
if (!finger.isActive()) {
|
|
||||||
// Found a free finger to use.
|
|
||||||
fingerAssignment[index] = &finger;
|
|
||||||
finger.setActive(true);
|
|
||||||
finger.setLeapID(leapFinger.id());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Apply the assignments
|
|
||||||
for (size_t index = 0; index < numLeapFingers; ++index) {
|
|
||||||
if (fingerAssignment[index]) {
|
|
||||||
Leap::Finger leapFinger = frame.fingers()[index];
|
|
||||||
FingerData& finger = *(fingerAssignment[index]);
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gotRealData = true;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!gotRealData) {
|
if (!gotRealData) {
|
||||||
|
|
|
@ -13,18 +13,19 @@ 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) {
|
}
|
||||||
_palms.push_back(PalmData(this));
|
|
||||||
}
|
PalmData& HandData::addNewPalm() {
|
||||||
const int standardTrailLength = 30;
|
_palms.push_back(PalmData(this));
|
||||||
setFingerTrailLength(standardTrailLength);
|
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(-1),
|
_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) {
|
||||||
|
@ -36,10 +37,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(-1),
|
_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) {
|
||||||
|
|
|
@ -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,7 @@ 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 setFingerTrailLength(unsigned int length);
|
||||||
void updateFingerTrails();
|
void updateFingerTrails();
|
||||||
|
@ -79,12 +81,17 @@ public:
|
||||||
|
|
||||||
int getTrailNumPositions();
|
int getTrailNumPositions();
|
||||||
const glm::vec3& getTrailPosition(int index);
|
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 _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;
|
std::vector<glm::vec3> _tipTrailPositions;
|
||||||
int _tipTrailCurrentStartIndex;
|
int _tipTrailCurrentStartIndex;
|
||||||
int _tipTrailCurrentValidLength;
|
int _tipTrailCurrentValidLength;
|
||||||
|
@ -110,12 +117,17 @@ public:
|
||||||
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 _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