Merge pull request #592 from machinelevel/dev

Hand rework in preparation for adding send/receive hand data
This commit is contained in:
Philip Rosedale 2013-06-28 11:47:36 -07:00
commit c1d23f5f63
10 changed files with 293 additions and 73 deletions

View file

@ -1674,7 +1674,7 @@ void Application::update(float deltaTime) {
// Leap finger-sensing device
LeapManager::nextFrame();
_myAvatar.setLeapFingers(LeapManager::getFingerPositions());
_myAvatar.getHand().setLeapFingers(LeapManager::getFingerPositions());
// Read serial port interface devices
if (_serialHeadSensor.isActive()) {

View file

@ -13,6 +13,7 @@
#include "world.h"
#include "Application.h"
#include "Avatar.h"
#include "Hand.h"
#include "Head.h"
#include "Log.h"
#include "ui/TextRenderer.h"
@ -64,6 +65,7 @@ Avatar::Avatar(Agent* owningAgent) :
AvatarData(owningAgent),
_initialized(false),
_head(this),
_hand(this),
_ballSpringsInitialized(false),
_TEST_bigSphereRadius(0.5f),
_TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f),
@ -96,6 +98,7 @@ Avatar::Avatar(Agent* owningAgent) :
{
// give the pointer to our head to inherited _headData variable from AvatarData
_headData = &_head;
_handData = &_hand;
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
_driveKeys[i] = false;
@ -104,7 +107,6 @@ Avatar::Avatar(Agent* owningAgent) :
_skeleton.initialize();
initializeBodyBalls();
initializeLeapBalls();
_height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius;
@ -264,35 +266,22 @@ void Avatar::initializeBodyBalls() {
*/
}
void Avatar::initializeLeapBalls() {
_numLeapBalls = 0;
for (int b = 0; b < MAX_AVATAR_LEAP_BALLS; b++) {
_leapBall[b].parentJoint = AVATAR_JOINT_NULL;
_leapBall[b].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_leapBall[b].position = glm::vec3(0.0, 0.0, 0.0);
_leapBall[b].velocity = glm::vec3(0.0, 0.0, 0.0);
_leapBall[b].radius = 0.01;
_leapBall[b].touchForce = 0.0;
_leapBall[b].isCollidable = true;
_leapBall[b].jointTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
}
}
Avatar::~Avatar() {
_headData = NULL;
_handData = NULL;
delete _balls;
}
void Avatar::init() {
_head.init();
_hand.init();
_voxels.init();
_initialized = true;
}
void Avatar::reset() {
_head.reset();
_hand.reset();
}
// Update avatar head rotation with sensor data
@ -543,9 +532,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// update body balls
updateBodyBalls(deltaTime);
// update leap balls
updateLeapBalls(deltaTime);
// test for avatar collision response with the big sphere
if (usingBigSphereCollisionTest) {
updateCollisionWithSphere(_TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime);
@ -1167,23 +1153,6 @@ void Avatar::updateBodyBalls(float deltaTime) {
_bodyBall[BODY_BALL_HEAD_TOP].rotation * _skeleton.joint[BODY_BALL_HEAD_TOP].bindPosePosition;
}
void Avatar::setLeapFingers(const std::vector<glm::vec3>& fingerPositions) {
_numLeapBalls = fingerPositions.size(); // just to test
float unitScale = 0.001; // convert mm to meters
glm::vec3 offset(0.2, -0.2, -0.3); // place the hand in front of the face where we can see it
for (int b = 0; b < _numLeapBalls; b++) {
glm::vec3 pos = unitScale * fingerPositions[b] + offset;
_leapBall[b].rotation = _head.getOrientation();
_leapBall[b].position = _bodyBall[BODY_BALL_HEAD_BASE].position +
_head.getOrientation() * pos;
}
}
void Avatar::updateLeapBalls(float deltaTime) {
}
void Avatar::updateArmIKAndConstraints(float deltaTime) {
// determine the arm vector
@ -1306,30 +1275,7 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
}
}
}
// Draw the leap balls
for (int b = 0; b < _numLeapBalls; b++) {
float alpha = 1.0f;
if (alpha > 0.0f) {
// Render the body ball sphere
if (_owningAgent || true) {
glColor3f(SKIN_COLOR[0] + _leapBall[b].touchForce * 0.3f,
SKIN_COLOR[1] - _leapBall[b].touchForce * 0.2f,
SKIN_COLOR[2] - _leapBall[b].touchForce * 0.1f);
} else {
glColor4f(SKIN_COLOR[0] + _leapBall[b].touchForce * 0.3f,
SKIN_COLOR[1] - _leapBall[b].touchForce * 0.2f,
SKIN_COLOR[2] - _leapBall[b].touchForce * 0.1f,
alpha);
}
glColor4f(0.0, 0.4, 0.0, 1.0); // Just to test
glPushMatrix();
glTranslatef(_leapBall[b].position.x, _leapBall[b].position.y, _leapBall[b].position.z);
glutSolidSphere(_leapBall[b].radius, 20.0f, 20.0f);
glPopMatrix();
}
}
_hand.render(lookingInMirror);
} else {
// Render the body's voxels
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);

View file

@ -18,6 +18,7 @@
#include "InterfaceConfig.h"
#include "SerialInterface.h"
#include "Balls.h"
#include "Hand.h"
#include "Head.h"
#include "Skeleton.h"
#include "Transmitter.h"
@ -56,8 +57,6 @@ enum AvatarBodyBallID
NUM_AVATAR_BODY_BALLS
};
#define MAX_AVATAR_LEAP_BALLS 10
enum DriveKeys
{
FWD = 0,
@ -105,7 +104,6 @@ public:
void setGravity (glm::vec3 gravity);
void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction);
void setOrientation (const glm::quat& orientation);
void setLeapFingers (const std::vector<glm::vec3>& fingerPositions);
//getters
bool isInitialized () const { return _initialized;}
@ -115,8 +113,6 @@ public:
bool getIsNearInteractingOther () const { return _avatarTouch.getAbleToReachOtherAvatar();}
const glm::vec3& getHeadJointPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;}
const glm::vec3& getBallPosition (AvatarJointID j) const { return _bodyBall[j].position;}
int getNumLeapBalls () const { return _numLeapBalls;}
const glm::vec3& getLeapBallPosition (int which) const { return _leapBall[which].position;}
glm::vec3 getBodyRightDirection () const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getBodyUpDirection () const { return getOrientation() * IDENTITY_UP; }
glm::vec3 getBodyFrontDirection () const { return getOrientation() * IDENTITY_FRONT; }
@ -131,6 +127,7 @@ public:
float getAbsoluteHeadYaw () const;
float getAbsoluteHeadPitch () const;
Head& getHead () {return _head; }
Hand& getHand () {return _hand; }
glm::quat getOrientation () const;
glm::quat getWorldAlignedOrientation() const;
@ -180,6 +177,7 @@ private:
bool _initialized;
Head _head;
Hand _hand;
Skeleton _skeleton;
bool _ballSpringsInitialized;
float _TEST_bigSphereRadius;
@ -190,8 +188,6 @@ private:
float _bodyRollDelta;
glm::vec3 _movedHandOffset;
AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ];
AvatarBall _leapBall[ MAX_AVATAR_LEAP_BALLS ];
int _numLeapBalls;
AvatarMode _mode;
glm::vec3 _handHoldingPosition;
glm::vec3 _velocity;
@ -226,10 +222,8 @@ private:
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
void renderBody(bool lookingInMirror, bool renderAvatarBalls);
void initializeBodyBalls();
void initializeLeapBalls();
void resetBodyBalls();
void updateBodyBalls( float deltaTime );
void updateLeapBalls( float deltaTime );
void calculateBoneLengths();
void readSensors();
void updateHandMovementAndTouching(float deltaTime);

100
interface/src/Hand.cpp Executable file
View file

@ -0,0 +1,100 @@
//
// Hand.cpp
// interface
//
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <QImage>
#include <AgentList.h>
#include "Application.h"
#include "Avatar.h"
#include "Hand.h"
#include "Util.h"
#include "renderer/ProgramObject.h"
using namespace std;
Hand::Hand(Avatar* owningAvatar) :
HandData((AvatarData*)owningAvatar),
_owningAvatar(owningAvatar),
_renderAlpha(1.0),
_lookingInMirror(false),
_ballColor(0.0, 0.4, 0.0),
_position(0.0, 0.4, 0.0),
_orientation(0.0, 0.0, 0.0, 1.0)
{
}
void Hand::init() {
_numLeapBalls = 0;
for (int b = 0; b < MAX_AVATAR_LEAP_BALLS; b++) {
_leapBall[b].position = glm::vec3(0.0, 0.0, 0.0);
_leapBall[b].velocity = glm::vec3(0.0, 0.0, 0.0);
_leapBall[b].radius = 0.01;
_leapBall[b].touchForce = 0.0;
_leapBall[b].isCollidable = true;
}
}
void Hand::reset() {
}
void Hand::simulate(float deltaTime, bool isMine) {
}
void Hand::calculateGeometry() {
glm::vec3 offset(0.1, -0.1, -0.15); // place the hand in front of the face where we can see it
Head& head = _owningAvatar->getHead();
_position = head.getPosition() + head.getOrientation() * offset;
_orientation = head.getOrientation();
_numLeapBalls = _fingerPositions.size();
float unitScale = 0.001; // convert mm to meters
for (int b = 0; b < _numLeapBalls; b++) {
glm::vec3 pos = unitScale * _fingerPositions[b] + offset;
_leapBall[b].rotation = _orientation;
_leapBall[b].position = _position + _orientation * pos;
}
}
void Hand::render(bool lookingInMirror) {
_renderAlpha = 1.0;
_lookingInMirror = lookingInMirror;
calculateGeometry();
glEnable(GL_DEPTH_TEST);
glEnable(GL_RESCALE_NORMAL);
renderHandSpheres();
}
void Hand::renderHandSpheres() {
glPushMatrix();
// Draw the leap balls
for (int b = 0; b < _numLeapBalls; b++) {
float alpha = 1.0f;
if (alpha > 0.0f) {
glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, alpha); // Just to test
glPushMatrix();
glTranslatef(_leapBall[b].position.x, _leapBall[b].position.y, _leapBall[b].position.z);
glutSolidSphere(_leapBall[b].radius, 20.0f, 20.0f);
glPopMatrix();
}
}
glPopMatrix();
}
void Hand::setLeapFingers(const std::vector<glm::vec3>& fingerPositions) {
_fingerPositions = fingerPositions;
}

69
interface/src/Hand.h Executable file
View file

@ -0,0 +1,69 @@
//
// Hand.h
// interface
//
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef hifi_Hand_h
#define hifi_Hand_h
#include <glm/glm.hpp>
#include <AvatarData.h>
#include <HandData.h>
#include "Balls.h"
#include "world.h"
#include "InterfaceConfig.h"
#include "SerialInterface.h"
#include <SharedUtil.h>
class Avatar;
class ProgramObject;
class Hand : public HandData {
public:
Hand(Avatar* owningAvatar);
struct HandBall
{
glm::vec3 position; // the actual dynamic position of the ball at any given time
glm::quat rotation; // the rotation of the ball
glm::vec3 velocity; // the velocity of the ball
float radius; // the radius of the ball
bool isCollidable; // whether or not the ball responds to collisions
float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball
};
void init();
void reset();
void simulate(float deltaTime, bool isMine);
void render(bool lookingInMirror);
void setBallColor (glm::vec3 ballColor ) { _ballColor = ballColor; }
void setLeapFingers (const std::vector<glm::vec3>& fingerPositions);
// getters
int getNumLeapBalls () const { return _numLeapBalls;}
const glm::vec3& getLeapBallPosition (int which) const { return _leapBall[which].position;}
private:
// disallow copies of the Hand, copy of owning Avatar is disallowed too
Hand(const Hand&);
Hand& operator= (const Hand&);
Avatar* _owningAvatar;
float _renderAlpha;
bool _lookingInMirror;
glm::vec3 _ballColor;
glm::vec3 _position;
glm::quat _orientation;
int _numLeapBalls;
HandBall _leapBall[ MAX_AVATAR_LEAP_BALLS ];
// private methods
void renderHandSpheres();
void calculateGeometry();
};
#endif

View file

@ -51,6 +51,7 @@ public:
glm::quat getOrientation() const;
glm::quat getCameraOrientation (float pitchYawScale) const;
glm::vec3 getPosition() const { return _position; }
glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getUpDirection () const { return getOrientation() * IDENTITY_UP; }
glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }

54
libraries/avatars/src/AvatarData.cpp Normal file → Executable file
View file

@ -36,13 +36,15 @@ AvatarData::AvatarData(Agent* owningAgent) :
_wantColor(true),
_wantDelta(false),
_wantOcclusionCulling(false),
_headData(NULL)
_headData(NULL),
_handData(NULL)
{
}
AvatarData::~AvatarData() {
delete _headData;
delete _handData;
}
int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
@ -56,6 +58,10 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
if (!_headData) {
_headData = new HeadData(this);
}
// lazily allocate memory for HeadData in case we're not an Avatar instance
if (!_handData) {
_handData = new HandData(this);
}
// Body world position
memcpy(destinationBuffer, &_position, sizeof(float) * 3);
@ -118,6 +124,16 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState);
*destinationBuffer++ = bitItems;
// leap hand data
const std::vector<glm::vec3>& fingerPositions = _handData->getFingerPositions();
*destinationBuffer++ = (unsigned char)fingerPositions.size();
for (size_t i = 0; i < fingerPositions.size(); ++i)
{
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerPositions[i].x, 4);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerPositions[i].y, 4);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerPositions[i].z, 4);
}
return destinationBuffer - bufferStart;
}
@ -128,7 +144,12 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
if (!_headData) {
_headData = new HeadData(this);
}
// lazily allocate memory for HandData in case we're not an Avatar instance
if (!_handData) {
_handData = new HandData(this);
}
// increment to push past the packet header
sourceBuffer += sizeof(PACKET_HEADER_HEAD_DATA);
@ -205,6 +226,23 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// hand state, stored as a semi-nibble in the bitItems
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
// leap hand data
if (sourceBuffer - startPosition < numBytes) // safety check
{
std::vector<glm::vec3> fingerPositions = _handData->getFingerPositions();
unsigned int numFingers = *sourceBuffer++;
if (numFingers > MAX_AVATAR_LEAP_BALLS) // safety check
numFingers = 0;
fingerPositions.resize(numFingers);
for (size_t i = 0; i < numFingers; ++i)
{
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((uint16_t*) sourceBuffer, &(fingerPositions[i].x), 4);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((uint16_t*) sourceBuffer, &(fingerPositions[i].y), 4);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((uint16_t*) sourceBuffer, &(fingerPositions[i].z), 4);
}
_handData->setFingerPositions(fingerPositions);
}
return sourceBuffer - startPosition;
}
@ -214,6 +252,18 @@ glm::vec3 AvatarData::calculateCameraDirection() const {
}
// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc
int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) {
int16_t outVal = (int16_t)(scalar * (float)(1 << radix));
memcpy(buffer, &outVal, sizeof(uint16_t));
return sizeof(uint16_t);
}
int unpackFloatScalarFromSignedTwoByteFixed(uint16_t* byteFixedPointer, float* destinationPointer, int radix) {
*destinationPointer = *byteFixedPointer / (float)(1 << radix);
return sizeof(uint16_t);
}
int packFloatAngleToTwoByte(unsigned char* buffer, float angle) {
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);

7
libraries/avatars/src/AvatarData.h Normal file → Executable file
View file

@ -17,6 +17,7 @@
#include <AgentData.h>
#include "HeadData.h"
#include "HandData.h"
const int WANT_RESIN_AT_BIT = 0;
const int WANT_COLOR_AT_BIT = 1;
@ -97,6 +98,7 @@ public:
void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; }
void setHeadData(HeadData* headData) { _headData = headData; }
void setHandData(HandData* handData) { _handData = handData; }
protected:
glm::vec3 _position;
@ -131,6 +133,7 @@ protected:
bool _wantOcclusionCulling;
HeadData* _headData;
HandData* _handData;
private:
// privatize the copy constructor and assignment operator so they cannot be called
AvatarData(const AvatarData&);
@ -164,4 +167,8 @@ int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue);
int packFloatToByte(unsigned char* buffer, float value, float scaleBy);
int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy);
// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc
int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix);
int unpackFloatScalarFromSignedTwoByteFixed(uint16_t* byteFixedPointer, float* destinationPointer, int radix);
#endif /* defined(__hifi__AvatarData__) */

View file

@ -0,0 +1,15 @@
//
// HandData.cpp
// hifi
//
// Created by Stephen Birarda on 5/20/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "HandData.h"
HandData::HandData(AvatarData* owningAvatar) :
_owningAvatarData(owningAvatar)
{
}

View file

@ -0,0 +1,38 @@
//
// HandData.h
// hifi
//
// Created by Eric Johnston on 6/26/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__HandData__
#define __hifi__HandData__
#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#define MAX_AVATAR_LEAP_BALLS 10
class AvatarData;
class HandData {
public:
HandData(AvatarData* owningAvatar);
const std::vector<glm::vec3>& getFingerPositions() const { return _fingerPositions; }
void setFingerPositions(const std::vector<glm::vec3>& fingerPositions) { _fingerPositions = fingerPositions; }
friend class AvatarData;
protected:
std::vector<glm::vec3> _fingerPositions;
AvatarData* _owningAvatarData;
private:
// privatize copy ctor and assignment operator so copies of this object cannot be made
HandData(const HandData&);
HandData& operator= (const HandData&);
};
#endif /* defined(__hifi__HandData__) */