Merge pull request #3975 from ctrlaltdavid/20212

CR for Job #20212 - Operate laser pointer with hands controlled by Leap Motion
This commit is contained in:
Brad Hefta-Gaub 2014-12-19 09:55:45 -08:00
commit 821cbe610c
5 changed files with 151 additions and 58 deletions

View file

@ -5,19 +5,89 @@
// Created by Clément Brisset on 7/18/14.
// Copyright 2014 High Fidelity, Inc.
//
// If using Hydra controllers, pulling the triggers makes laser pointers emanate from the respective hands.
// If using a Leap Motion or similar to control your avatar's hands and fingers, pointing with your index fingers makes
// laser pointers emanate from the respective index fingers.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var LEFT = 0;
var RIGHT = 1;
var LEFT_HAND_FLAG = 1;
var RIGHT_HAND_FLAG = 2;
var laserPointer = (function () {
function update() {
var state = ((Controller.getTriggerValue(LEFT) > 0.9) ? LEFT_HAND_FLAG : 0) +
((Controller.getTriggerValue(RIGHT) > 0.9) ? RIGHT_HAND_FLAG : 0);
MyAvatar.setHandState(state);
}
var NUM_FINGERs = 4, // Excluding thumb
fingers = [
[ "LeftHandIndex", "LeftHandMiddle", "LeftHandRing", "LeftHandPinky" ],
[ "RightHandIndex", "RightHandMiddle", "RightHandRing", "RightHandPinky" ]
];
Script.update.connect(update);
function isHandPointing(hand) {
var MINIMUM_TRIGGER_PULL = 0.9;
return Controller.getTriggerValue(hand) > MINIMUM_TRIGGER_PULL;
}
function isFingerPointing(hand) {
// Index finger is pointing if final two bones of middle, ring, and pinky fingers are > 90 degrees w.r.t. index finger
var pointing,
indexDirection,
otherDirection,
f;
pointing = true;
indexDirection = Vec3.subtract(
MyAvatar.getJointPosition(fingers[hand][0] + "4"),
MyAvatar.getJointPosition(fingers[hand][0] + "2")
);
for (f = 1; f < NUM_FINGERs; f += 1) {
otherDirection = Vec3.subtract(
MyAvatar.getJointPosition(fingers[hand][f] + "4"),
MyAvatar.getJointPosition(fingers[hand][f] + "2")
);
pointing = pointing && Vec3.dot(indexDirection, otherDirection) < 0;
}
return pointing;
}
function update() {
var LEFT_HAND = 0,
RIGHT_HAND = 1,
LEFT_HAND_POINTING_FLAG = 1,
RIGHT_HAND_POINTING_FLAG = 2,
FINGER_POINTING_FLAG = 4,
handState;
handState = 0;
if (isHandPointing(LEFT_HAND)) {
handState += LEFT_HAND_POINTING_FLAG;
}
if (isHandPointing(RIGHT_HAND)) {
handState += RIGHT_HAND_POINTING_FLAG;
}
if (handState === 0) {
if (isFingerPointing(LEFT_HAND)) {
handState += LEFT_HAND_POINTING_FLAG;
}
if (isFingerPointing(RIGHT_HAND)) {
handState += RIGHT_HAND_POINTING_FLAG;
}
if (handState !== 0) {
handState += FINGER_POINTING_FLAG;
}
}
MyAvatar.setHandState(handState);
}
return {
update: update
};
}());
Script.update.connect(laserPointer.update);

View file

@ -282,43 +282,64 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
// render pointing lasers
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
float laserLength = 50.0f;
if (_handState == HAND_STATE_LEFT_POINTING ||
_handState == HAND_STATE_BOTH_POINTING) {
int leftIndex = _skeletonModel.getLeftHandJointIndex();
glm::vec3 leftPosition;
glm::quat leftRotation;
_skeletonModel.getJointPositionInWorldFrame(leftIndex, leftPosition);
_skeletonModel.getJointRotationInWorldFrame(leftIndex, leftRotation);
glPushMatrix(); {
glTranslatef(leftPosition.x, leftPosition.y, leftPosition.z);
float angle = glm::degrees(glm::angle(leftRotation));
glm::vec3 axis = glm::axis(leftRotation);
glRotatef(angle, axis.x, axis.y, axis.z);
glBegin(GL_LINES);
glColor3f(laserColor.x, laserColor.y, laserColor.z);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, laserLength, 0.0f);
glEnd();
} glPopMatrix();
glm::vec3 position;
glm::quat rotation;
bool havePosition, haveRotation;
if (_handState & LEFT_HAND_POINTING_FLAG) {
if (_handState & IS_FINGER_POINTING_FLAG) {
int leftIndexTip = getJointIndex("LeftHandIndex4");
int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftIndexTip, position);
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftIndexTipJoint, rotation);
} else {
int leftHand = _skeletonModel.getLeftHandJointIndex();
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftHand, position);
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftHand, rotation);
}
if (havePosition && haveRotation) {
glPushMatrix(); {
glTranslatef(position.x, position.y, position.z);
float angle = glm::degrees(glm::angle(rotation));
glm::vec3 axis = glm::axis(rotation);
glRotatef(angle, axis.x, axis.y, axis.z);
glBegin(GL_LINES);
glColor3f(laserColor.x, laserColor.y, laserColor.z);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, laserLength, 0.0f);
glEnd();
} glPopMatrix();
}
}
if (_handState == HAND_STATE_RIGHT_POINTING ||
_handState == HAND_STATE_BOTH_POINTING) {
int rightIndex = _skeletonModel.getRightHandJointIndex();
glm::vec3 rightPosition;
glm::quat rightRotation;
_skeletonModel.getJointPositionInWorldFrame(rightIndex, rightPosition);
_skeletonModel.getJointRotationInWorldFrame(rightIndex, rightRotation);
glPushMatrix(); {
glTranslatef(rightPosition.x, rightPosition.y, rightPosition.z);
float angle = glm::degrees(glm::angle(rightRotation));
glm::vec3 axis = glm::axis(rightRotation);
glRotatef(angle, axis.x, axis.y, axis.z);
glBegin(GL_LINES);
glColor3f(laserColor.x, laserColor.y, laserColor.z);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, laserLength, 0.0f);
glEnd();
} glPopMatrix();
if (_handState & RIGHT_HAND_POINTING_FLAG) {
if (_handState & IS_FINGER_POINTING_FLAG) {
int rightIndexTip = getJointIndex("RightHandIndex4");
int rightIndexTipJoint = getJointIndex("RightHandIndex3");
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightIndexTip, position);
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightIndexTipJoint, rotation);
} else {
int rightHand = _skeletonModel.getRightHandJointIndex();
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightHand, position);
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightHand, rotation);
}
if (havePosition && haveRotation) {
glPushMatrix(); {
glTranslatef(position.x, position.y, position.z);
float angle = glm::degrees(glm::angle(rotation));
glm::vec3 axis = glm::axis(rotation);
glRotatef(angle, axis.x, axis.y, axis.z);
glBegin(GL_LINES);
glColor3f(laserColor.x, laserColor.y, laserColor.z);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, laserLength, 0.0f);
glEnd();
} glPopMatrix();
}
}
}

View file

@ -21,15 +21,6 @@
class ModelItemID;
enum AvatarHandState
{
HAND_STATE_NULL = 0,
HAND_STATE_LEFT_POINTING,
HAND_STATE_RIGHT_POINTING,
HAND_STATE_BOTH_POINTING,
NUM_HAND_STATES
};
class MyAvatar : public Avatar {
Q_OBJECT
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)

View file

@ -188,7 +188,11 @@ QByteArray AvatarData::toByteArray() {
// key state
setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState);
// hand state
setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState);
bool isFingerPointing = _handState & IS_FINGER_POINTING_FLAG;
setSemiNibbleAt(bitItems, HAND_STATE_START_BIT, _handState & ~IS_FINGER_POINTING_FLAG);
if (isFingerPointing) {
setAtBit(bitItems, HAND_STATE_FINGER_POINTING_BIT);
}
// faceshift state
if (_headData->_isFaceshiftConnected) {
setAtBit(bitItems, IS_FACESHIFT_CONNECTED);
@ -439,8 +443,9 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// key state, stored as a semi-nibble in the bitItems
_keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT);
// hand state, stored as a semi-nibble in the bitItems
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
// hand state, stored as a semi-nibble plus a bit in the bitItems
_handState = getSemiNibbleAt(bitItems, HAND_STATE_START_BIT)
+ (oneAtBit(bitItems, HAND_STATE_FINGER_POINTING_BIT) ? IS_FINGER_POINTING_FLAG : 0);
_headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED);
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);

View file

@ -82,6 +82,12 @@ const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits
const int IS_FACESHIFT_CONNECTED = 4; // 5th bit
const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit
const int HAS_REFERENTIAL = 6; // 7th bit
const int HAND_STATE_FINGER_POINTING_BIT = 7; // 8th bit
const char HAND_STATE_NULL = 0;
const char LEFT_HAND_POINTING_FLAG = 1;
const char RIGHT_HAND_POINTING_FLAG = 2;
const char IS_FINGER_POINTING_FLAG = 4;
static const float MAX_AVATAR_SCALE = 1000.0f;
static const float MIN_AVATAR_SCALE = .005f;