From 2ef45e85121833890f3db93e0f4c598d47435e05 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 23 Apr 2013 11:15:11 -0700 Subject: [PATCH] Avatar head rotation, audio loudness (for facial animation) and hand state (grabbing or not) now sent in broadcast data. --- interface/src/Head.cpp | 72 ++++++++++++++-------------- interface/src/Head.h | 16 +------ libraries/avatars/src/AvatarData.cpp | 38 +++++++++++++++ libraries/avatars/src/AvatarData.h | 40 ++++++++++++++-- 4 files changed, 109 insertions(+), 57 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index f6a3392027..38543c3441 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -75,9 +75,9 @@ Head::Head(bool isMine) { _head.interPupilDistance = 0.6; _head.interBrowDistance = 0.75; _head.nominalPupilSize = 0.10; - _head.yaw = 0.0; - _head.pitch = 0.0; - _head.roll = 0.0; + //_head.yaw = 0.0; + //_head.pitch = 0.0; + //_head.roll = 0.0; _head.pitchRate = 0.0; _head.yawRate = 0.0; _head.rollRate = 0.0; @@ -106,7 +106,6 @@ Head::Head(bool isMine) { _head.eyeContactTarget = LEFT_EYE; _head.scale = 1.0; _head.audioAttack = 0.0; - _head.loudness = 0.0; _head.averageLoudness = 0.0; _head.lastLoudness = 0.0; _head.browAudioLift = 0.0; @@ -176,9 +175,9 @@ Head::Head(const Head &otherAvatar) { _head.interPupilDistance = otherAvatar._head.interPupilDistance; _head.interBrowDistance = otherAvatar._head.interBrowDistance; _head.nominalPupilSize = otherAvatar._head.nominalPupilSize; - _head.yaw = otherAvatar._head.yaw; - _head.pitch = otherAvatar._head.pitch; - _head.roll = otherAvatar._head.roll; + //_head.yaw = otherAvatar._head.yaw; + //_head.pitch = otherAvatar._head.pitch; + //_head.roll = otherAvatar._head.roll; _head.yawRate = otherAvatar._head.yawRate; _head.pitchRate = otherAvatar._head.pitchRate; _head.rollRate = otherAvatar._head.rollRate; @@ -207,7 +206,6 @@ Head::Head(const Head &otherAvatar) { _head.eyeContactTarget = otherAvatar._head.eyeContactTarget; _head.scale = otherAvatar._head.scale; _head.audioAttack = otherAvatar._head.audioAttack; - _head.loudness = otherAvatar._head.loudness; _head.averageLoudness = otherAvatar._head.averageLoudness; _head.lastLoudness = otherAvatar._head.lastLoudness; _head.browAudioLift = otherAvatar._head.browAudioLift; @@ -234,7 +232,7 @@ Head* Head::clone() const { } void Head::reset() { - _head.pitch = _head.yaw = _head.roll = 0; + _headPitch = _headYaw = _headRoll = 0; _head.leanForward = _head.leanSideways = 0; } @@ -269,12 +267,12 @@ void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, glm:: const float MAX_YAW = 85; const float MIN_YAW = -85; - if ((_head.pitch < MAX_PITCH) && (_head.pitch > MIN_PITCH)) + if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); - if ((_head.yaw < MAX_YAW) && (_head.yaw > MIN_YAW)) + if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime); addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE); @@ -489,15 +487,15 @@ void Head::simulate(float deltaTime) { if (!_head.noise) { // Decay back toward center - _head.pitch *= (1.0f - DECAY*2*deltaTime); - _head.yaw *= (1.0f - DECAY*2*deltaTime); - _head.roll *= (1.0f - DECAY*2*deltaTime); + _headPitch *= (1.0f - DECAY*2*deltaTime); + _headYaw *= (1.0f - DECAY*2*deltaTime); + _headRoll *= (1.0f - DECAY*2*deltaTime); } else { // Move toward new target - _head.pitch += (_head.pitchTarget - _head.pitch)*10*deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; - _head.yaw += (_head.yawTarget - _head.yaw )*10*deltaTime; // (1.f - DECAY*deltaTime); - _head.roll *= (1.f - DECAY*deltaTime); + _headPitch += (_head.pitchTarget - _headPitch)*10*deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; + _headYaw += (_head.yawTarget - _headYaw )*10*deltaTime; // (1.f - DECAY*deltaTime); + _headRoll *= (1.f - DECAY*deltaTime); } _head.leanForward *= (1.f - DECAY*30.f*deltaTime); @@ -539,15 +537,15 @@ void Head::simulate(float deltaTime) { if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; - _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_head.pitch + eye_target_pitch_adjust; - _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_head.yaw + eye_target_yaw_adjust; + _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; + _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; } if (_head.noise) { - _head.pitch += (randFloat() - 0.5)*0.2*_head.noiseEnvelope; - _head.yaw += (randFloat() - 0.5)*0.3*_head.noiseEnvelope; + _headPitch += (randFloat() - 0.5)*0.2*_head.noiseEnvelope; + _headYaw += (randFloat() - 0.5)*0.3*_head.noiseEnvelope; //PupilSize += (randFloat() - 0.5)*0.001*NoiseEnvelope; if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; @@ -557,7 +555,7 @@ void Head::simulate(float deltaTime) { if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5)*10; } - if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _head.pitch) < 1.0) && (fabs(_head.yawTarget - _head.yaw) < 1.0)) { + if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) { SetNewHeadTarget((randFloat()-0.5)*20.0, (randFloat()-0.5)*45.0); } @@ -724,12 +722,14 @@ void Head::renderHead(int lookingInMirror) { glScalef( 0.03, 0.03, 0.03 ); if (lookingInMirror) { - glRotatef(_bodyYaw - _head.yaw, 0, 1, 0); + glRotatef(_bodyYaw - _headYaw, 0, 1, 0); + glRotatef(_bodyPitch + _headPitch, 1, 0, 0); + glRotatef(_bodyRoll - _headRoll, 0, 0, 1); } else { - glRotatef(_bodyYaw + _head.yaw, 0, 1, 0); + glRotatef(_bodyYaw + _headYaw, 0, 1, 0); + glRotatef(_bodyPitch + _headPitch, 1, 0, 0); + glRotatef(_bodyRoll + _headRoll, 0, 0, 1); } - glRotatef(_bodyPitch + _head.pitch, 1, 0, 0); - glRotatef(_bodyRoll + _head.roll, 0, 0, 1); glScalef(2.0, 2.0, 2.0); glColor3fv(skinColor); @@ -749,8 +749,8 @@ void Head::renderHead(int lookingInMirror) { glPopMatrix(); // _eyebrows - _head.audioAttack = 0.9*_head.audioAttack + 0.1*fabs(_head.loudness - _head.lastLoudness); - _head.lastLoudness = _head.loudness; + _head.audioAttack = 0.9*_head.audioAttack + 0.1*fabs(_audioLoudness - _head.lastLoudness); + _head.lastLoudness = _audioLoudness; const float BROW_LIFT_THRESHOLD = 100; if (_head.audioAttack > BROW_LIFT_THRESHOLD) @@ -813,7 +813,7 @@ void Head::renderHead(int lookingInMirror) { glPushMatrix(); { glRotatef(_head.eyeballPitch[1], 1, 0, 0); - glRotatef(_head.eyeballYaw[1] + _head.yaw + _head.pupilConverge, 0, 1, 0); + glRotatef(_head.eyeballYaw[1] + _headYaw + _head.pupilConverge, 0, 1, 0); glTranslatef(0,0,.35); glRotatef(-75,1,0,0); glScalef(1.0, 0.4, 1.0); @@ -839,7 +839,7 @@ void Head::renderHead(int lookingInMirror) { glPushMatrix(); { glRotatef(_head.eyeballPitch[0], 1, 0, 0); - glRotatef(_head.eyeballYaw[0] + _head.yaw - _head.pupilConverge, 0, 1, 0); + glRotatef(_head.eyeballYaw[0] + _headYaw - _head.pupilConverge, 0, 1, 0); glTranslatef(0, 0, .35); glRotatef(-75, 1, 0, 0); glScalef(1.0, 0.4, 1.0); @@ -1137,18 +1137,19 @@ void Head::updateHandMovement() { _bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement; + setHandState(_mousePressed); + //if holding hands, add a pull to the hand... if ( _usingBodySprings ) { if ( _closestOtherAvatar != -1 ) { if ( _mousePressed ) { - - + glm::vec3 handToHandVector( _otherAvatarHandPosition[ _closestOtherAvatar ]); handToHandVector -= _bone[ AVATAR_BONE_RIGHT_HAND ].position; //_bone[ AVATAR_BONE_RIGHT_HAND ].springyVelocity -= handPull; _bone[ AVATAR_BONE_RIGHT_HAND ].position = _otherAvatarHandPosition[ _closestOtherAvatar ]; - } + } } } @@ -1278,7 +1279,7 @@ void Head::renderBody() { } } - if (( _usingBodySprings ) && ( _mousePressed )) { + if (( _usingBodySprings ) && ( getHandState() )) { glColor4f( 1.0, 1.0, 0.5, 0.5 ); glPushMatrix(); glTranslatef @@ -1306,9 +1307,6 @@ void Head::renderBoneAsBlock( AvatarBoneID b ) { glPopMatrix(); } - - - void Head::SetNewHeadTarget(float pitch, float yaw) { _head.pitchTarget = pitch; _head.yawTarget = yaw; diff --git a/interface/src/Head.h b/interface/src/Head.h index 72ac2c1ec4..b20614dd75 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -100,9 +100,6 @@ struct AvatarBone struct AvatarHead { - float pitch; - float yaw; - float roll; float pitchRate; float yawRate; float rollRate; @@ -134,7 +131,7 @@ struct AvatarHead eyeContactTargets eyeContactTarget; // Sound loudness information - float loudness, lastLoudness; + float lastLoudness; float averageLoudness; float audioAttack; }; @@ -150,9 +147,6 @@ class Head : public AvatarData { void reset(); void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); void setNoise (float mag) { _head.noise = mag; } - void setPitch(float p) {_head.pitch = p; } - void setYaw(float y) {_head.yaw = y; } - void setRoll(float r) {_head.roll = r; }; void setScale(float s) {_head.scale = s; }; void setRenderYaw(float y) {_renderYaw = y;} void setRenderPitch(float p) {_renderPitch = p;} @@ -160,13 +154,7 @@ class Head : public AvatarData { float getRenderPitch() {return _renderPitch;} void setLeanForward(float dist); void setLeanSideways(float dist); - void addHeadPitch(float p) {_head.pitch -= p; } - void addHeadYaw(float y){_head.yaw -= y; } - void addHeadRoll(float r){_head.roll += r; } void addLean(float x, float z); - float getHeadPitch() {return _head.pitch;} - float getHeadRoll() {return _head.roll;} - float getHeadYaw() {return _head.yaw;} float getLastMeasuredHeadYaw() {return _head.yawRate;} float getBodyYaw() {return _bodyYaw;}; void addBodyYaw(float y) {_bodyYaw += y;}; @@ -189,10 +177,8 @@ class Head : public AvatarData { void setHandMovementValues( glm::vec3 movement ); void updateHandMovement(); - float getLoudness() {return _head.loudness;}; float getAverageLoudness() {return _head.averageLoudness;}; void setAverageLoudness(float al) {_head.averageLoudness = al;}; - void setLoudness(float l) {_head.loudness = l;}; void SetNewHeadTarget(float, float); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d644937464..295348a098 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -34,9 +34,14 @@ int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPo } AvatarData::AvatarData() : + _handPosition(0,0,0), _bodyYaw(-90.0), _bodyPitch(0.0), _bodyRoll(0.0), + _headYaw(0), + _headPitch(0), + _headRoll(0), + _handState(0), _cameraPosition(0,0,0), _cameraDirection(0,0,0), _cameraUp(0,0,0), @@ -63,15 +68,31 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // that can pack any type given the number of bytes // and return the number of bytes to push the pointer + // Body world position memcpy(destinationBuffer, &_bodyPosition, sizeof(float) * 3); destinationBuffer += sizeof(float) * 3; + // Body rotation (NOTE: This needs to become a quaternion to save two bytes) destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyYaw); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyPitch); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyRoll); + // Head rotation (NOTE: This needs to become a quaternion to save two bytes) + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headYaw); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headPitch); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headRoll); + + // Hand Position memcpy(destinationBuffer, &_handPosition, sizeof(float) * 3); destinationBuffer += sizeof(float) * 3; + + // Hand State (0 = not grabbing, 1 = grabbing) + memcpy(destinationBuffer, &_handState, sizeof(char)); + destinationBuffer += sizeof(char); + + // Instantaneous audio loudness (used to drive facial animation) + memcpy(destinationBuffer, &_audioLoudness, sizeof(float)); + destinationBuffer += sizeof(float); // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); @@ -91,6 +112,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_cameraFarClip, sizeof(_cameraFarClip)); destinationBuffer += sizeof(_cameraFarClip); + return destinationBuffer - bufferStart; } @@ -102,16 +124,32 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* startPosition = sourceBuffer; + // Body world position memcpy(&_bodyPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; + // Body rotation (NOTE: This needs to become a quaternion to save two bytes) sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_bodyYaw); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_bodyPitch); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_bodyRoll); + + // Head rotation (NOTE: This needs to become a quaternion to save two bytes) + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headRoll); + // Hand Position memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; + // Hand State + memcpy(&_handState, sourceBuffer, sizeof(char)); + sourceBuffer += sizeof(char); + + // Instantaneous audio loudness (used to drive facial animation) + memcpy(&_audioLoudness, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); sourceBuffer += sizeof(_cameraPosition); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ea735c62fe..588390e59c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -27,16 +27,34 @@ public: int getBroadcastData(unsigned char* destinationBuffer); int parseData(unsigned char* sourceBuffer, int numBytes); + // Body Rotation float getBodyYaw(); - void setBodyYaw(float bodyYaw); - float getBodyPitch(); - void setBodyPitch(float bodyPitch); - float getBodyRoll(); + void setBodyYaw(float bodyYaw); + void setBodyPitch(float bodyPitch); void setBodyRoll(float bodyRoll); - // getters for camera details + // Head Rotation + void setHeadPitch(float p) {_headPitch = p; } + void setHeadYaw(float y) {_headYaw = y; } + void setHeadRoll(float r) {_headRoll = r; }; + float getHeadPitch() { return _headPitch; }; + float getHeadYaw() { return _headYaw; }; + float getHeadRoll() { return _headRoll; }; + void addHeadPitch(float p) {_headPitch -= p; } + void addHeadYaw(float y){_headYaw -= y; } + void addHeadRoll(float r){_headRoll += r; } + + // Hand State + void setHandState(char s) { _handState = s; }; + float getHandState() {return _handState; }; + + // Instantaneous audio loudness to drive mouth/facial animation + void setLoudness(float l) { _audioLoudness = l; }; + float getLoudness() {return _audioLoudness; }; + + // getters for camera details const glm::vec3& getCameraPosition() const { return _cameraPosition; }; const glm::vec3& getCameraDirection() const { return _cameraDirection; } const glm::vec3& getCameraUp() const { return _cameraUp; } @@ -60,10 +78,22 @@ protected: glm::vec3 _bodyPosition; glm::vec3 _handPosition; + // Body rotation float _bodyYaw; float _bodyPitch; float _bodyRoll; + + // Head rotation (relative to body) + float _headYaw; + float _headPitch; + float _headRoll; + // Audio loudness (used to drive facial animation) + float _audioLoudness; + + // Hand state (are we grabbing something or not) + char _handState; + // camera details for the avatar glm::vec3 _cameraPosition;