mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 19:03:07 +02:00
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:
commit
821cbe610c
5 changed files with 151 additions and 58 deletions
|
@ -5,19 +5,89 @@
|
||||||
// Created by Clément Brisset on 7/18/14.
|
// Created by Clément Brisset on 7/18/14.
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// 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.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
var LEFT = 0;
|
var laserPointer = (function () {
|
||||||
var RIGHT = 1;
|
|
||||||
var LEFT_HAND_FLAG = 1;
|
|
||||||
var RIGHT_HAND_FLAG = 2;
|
|
||||||
|
|
||||||
function update() {
|
var NUM_FINGERs = 4, // Excluding thumb
|
||||||
var state = ((Controller.getTriggerValue(LEFT) > 0.9) ? LEFT_HAND_FLAG : 0) +
|
fingers = [
|
||||||
((Controller.getTriggerValue(RIGHT) > 0.9) ? RIGHT_HAND_FLAG : 0);
|
[ "LeftHandIndex", "LeftHandMiddle", "LeftHandRing", "LeftHandPinky" ],
|
||||||
MyAvatar.setHandState(state);
|
[ "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);
|
||||||
|
|
|
@ -282,43 +282,64 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
||||||
// render pointing lasers
|
// render pointing lasers
|
||||||
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
|
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
|
||||||
float laserLength = 50.0f;
|
float laserLength = 50.0f;
|
||||||
if (_handState == HAND_STATE_LEFT_POINTING ||
|
glm::vec3 position;
|
||||||
_handState == HAND_STATE_BOTH_POINTING) {
|
glm::quat rotation;
|
||||||
int leftIndex = _skeletonModel.getLeftHandJointIndex();
|
bool havePosition, haveRotation;
|
||||||
glm::vec3 leftPosition;
|
|
||||||
glm::quat leftRotation;
|
if (_handState & LEFT_HAND_POINTING_FLAG) {
|
||||||
_skeletonModel.getJointPositionInWorldFrame(leftIndex, leftPosition);
|
|
||||||
_skeletonModel.getJointRotationInWorldFrame(leftIndex, leftRotation);
|
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||||
glPushMatrix(); {
|
int leftIndexTip = getJointIndex("LeftHandIndex4");
|
||||||
glTranslatef(leftPosition.x, leftPosition.y, leftPosition.z);
|
int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
|
||||||
float angle = glm::degrees(glm::angle(leftRotation));
|
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftIndexTip, position);
|
||||||
glm::vec3 axis = glm::axis(leftRotation);
|
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftIndexTipJoint, rotation);
|
||||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
} else {
|
||||||
glBegin(GL_LINES);
|
int leftHand = _skeletonModel.getLeftHandJointIndex();
|
||||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftHand, position);
|
||||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftHand, rotation);
|
||||||
glVertex3f(0.0f, laserLength, 0.0f);
|
}
|
||||||
glEnd();
|
|
||||||
} glPopMatrix();
|
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) {
|
if (_handState & RIGHT_HAND_POINTING_FLAG) {
|
||||||
int rightIndex = _skeletonModel.getRightHandJointIndex();
|
|
||||||
glm::vec3 rightPosition;
|
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||||
glm::quat rightRotation;
|
int rightIndexTip = getJointIndex("RightHandIndex4");
|
||||||
_skeletonModel.getJointPositionInWorldFrame(rightIndex, rightPosition);
|
int rightIndexTipJoint = getJointIndex("RightHandIndex3");
|
||||||
_skeletonModel.getJointRotationInWorldFrame(rightIndex, rightRotation);
|
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightIndexTip, position);
|
||||||
glPushMatrix(); {
|
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightIndexTipJoint, rotation);
|
||||||
glTranslatef(rightPosition.x, rightPosition.y, rightPosition.z);
|
} else {
|
||||||
float angle = glm::degrees(glm::angle(rightRotation));
|
int rightHand = _skeletonModel.getRightHandJointIndex();
|
||||||
glm::vec3 axis = glm::axis(rightRotation);
|
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightHand, position);
|
||||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightHand, rotation);
|
||||||
glBegin(GL_LINES);
|
}
|
||||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
|
||||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
if (havePosition && haveRotation) {
|
||||||
glVertex3f(0.0f, laserLength, 0.0f);
|
glPushMatrix(); {
|
||||||
glEnd();
|
glTranslatef(position.x, position.y, position.z);
|
||||||
} glPopMatrix();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,15 +21,6 @@
|
||||||
|
|
||||||
class ModelItemID;
|
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 {
|
class MyAvatar : public Avatar {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
||||||
|
|
|
@ -188,7 +188,11 @@ QByteArray AvatarData::toByteArray() {
|
||||||
// key state
|
// key state
|
||||||
setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState);
|
setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState);
|
||||||
// hand state
|
// 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
|
// faceshift state
|
||||||
if (_headData->_isFaceshiftConnected) {
|
if (_headData->_isFaceshiftConnected) {
|
||||||
setAtBit(bitItems, IS_FACESHIFT_CONNECTED);
|
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
|
// key state, stored as a semi-nibble in the bitItems
|
||||||
_keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT);
|
_keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT);
|
||||||
// hand state, stored as a semi-nibble in the bitItems
|
// hand state, stored as a semi-nibble plus a bit in the bitItems
|
||||||
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
|
_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);
|
_headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED);
|
||||||
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);
|
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);
|
||||||
|
|
|
@ -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_FACESHIFT_CONNECTED = 4; // 5th bit
|
||||||
const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit
|
const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit
|
||||||
const int HAS_REFERENTIAL = 6; // 7th 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 MAX_AVATAR_SCALE = 1000.0f;
|
||||||
static const float MIN_AVATAR_SCALE = .005f;
|
static const float MIN_AVATAR_SCALE = .005f;
|
||||||
|
|
Loading…
Reference in a new issue