diff --git a/eve/src/main.cpp b/eve/src/main.cpp index b4e6675ca0..d0ac737e2d 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -121,7 +121,7 @@ int main(int argc, const char* argv[]) { // put her hand out so somebody can shake it eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, - 0.25, + 0.32, // this is the same as the pelvis standing height (as of 4/26/13) eve.getPosition()[2] + 0.1)); // read eve's audio data AudioInjector eveAudioInjector("eve.raw"); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index d8f65c3e0b..2594bb8a0a 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -50,23 +50,22 @@ Avatar::Avatar(bool isMine) { _orientation.setToIdentity(); - _velocity = glm::vec3( 0.0, 0.0, 0.0 ); - _thrust = glm::vec3( 0.0, 0.0, 0.0 ); - _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); - _bodyYaw = -90.0; - _bodyPitch = 0.0; - _bodyRoll = 0.0; - _bodyYawDelta = 0.0; - _mousePressed = false; - _mode = AVATAR_MODE_STANDING; - _isMine = isMine; - _maxArmLength = 0.0; - //_transmitterTimer = 0; - _transmitterHz = 0.0; - _transmitterPackets = 0; - _speed = 0.0; + _velocity = glm::vec3( 0.0, 0.0, 0.0 ); + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); + _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); + _bodyYaw = -90.0; + _bodyPitch = 0.0; + _bodyRoll = 0.0; + _bodyYawDelta = 0.0; + _mousePressed = false; + _mode = AVATAR_MODE_STANDING; + _isMine = isMine; + _maxArmLength = 0.0; + _transmitterHz = 0.0; + _transmitterPackets = 0; + _speed = 0.0; _pelvisStandingHeight = 0.0f; - + _displayingHead = true; _TEST_bigSphereRadius = 0.3f; _TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f ); @@ -329,11 +328,7 @@ void Avatar::simulate(float deltaTime) { Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); // check for collisions with other avatars and respond - updateAvatarCollisionDetectionAndResponse(otherAvatar->getPosition(), - 0.1, - 0.1, - otherAvatar->getBodyUpDirection(), - deltaTime); + updateCollisionWithOtherAvatar(otherAvatar, deltaTime ); // test other avatar hand position for proximity glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); @@ -382,12 +377,8 @@ void Avatar::simulate(float deltaTime) { } if (usingBigSphereCollisionTest) { - // test for avatar collision response (using a big sphere :) - updateAvatarCollisionDetectionAndResponse(_TEST_bigSpherePosition, - _TEST_bigSphereRadius, - _TEST_bigSphereRadius, - glm::vec3( 0.0, 1.0, 0.0 ), - deltaTime); + // test for avatar collision response with the big sphere + updateCollisionWithSphere( _TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime ); } if ( AVATAR_GRAVITY ) { @@ -541,31 +532,22 @@ void Avatar::simulate(float deltaTime) { } } -float Avatar::getGirth() { - return COLLISION_BODY_RADIUS; -} - float Avatar::getHeight() { - return COLLISION_HEIGHT; + return _height; } -// This is a workspace for testing avatar body collision detection and response -void Avatar::updateAvatarCollisionDetectionAndResponse(glm::vec3 collisionPosition, - float collisionGirth, - float collisionHeight, - glm::vec3 collisionUpVector, - float deltaTime) { - + +void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ) { float myBodyApproximateBoundingRadius = 1.0f; - glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition); + glm::vec3 vectorFromMyBodyToBigSphere(_position - position); bool jointCollision = false; float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); - if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth ) { + if ( distanceToBigSphere < myBodyApproximateBoundingRadius + radius ) { for (int b = 0; b < NUM_AVATAR_BONES; b++) { - glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - collisionPosition); + glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - position); float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); - float combinedRadius = _bone[b].radius + collisionGirth; + float combinedRadius = _bone[b].radius + radius; if ( distanceToBigSphereCenter < combinedRadius ) { jointCollision = true; @@ -577,7 +559,7 @@ void Avatar::updateAvatarCollisionDetectionAndResponse(glm::vec3 collisionPositi _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; _velocity += collisionForce * 100.0f * deltaTime; - _bone[b].springyPosition = collisionPosition + directionVector * combinedRadius; + _bone[b].springyPosition = position + directionVector * combinedRadius; } } } @@ -591,6 +573,50 @@ void Avatar::updateAvatarCollisionDetectionAndResponse(glm::vec3 collisionPositi } } + +//detect collisions with other avatars and respond +void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTime ) { + + // check if the bounding spheres of the two avatars are colliding + glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); + if ( glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF ) { + + // loop through the bones of each avatar to check for every possible collision + for (int b=1; b_bone[o].springyPosition); + float distanceBetweenJoints = glm::length(vectorBetweenJoints); + + // to avoid divide by zero + if ( distanceBetweenJoints > 0.0 ) { + float combinedRadius = _bone[b].radius + otherAvatar->_bone[o].radius; + + // check for collision + if ( distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { + glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; + + // push ball away from colliding other ball and puch avatar body (_velocity) as well + _bone[b].springyVelocity += directionVector * COLLISION_BALL_FORCE * deltaTime; + _velocity += directionVector * COLLISION_BODY_FORCE * deltaTime; + + // apply fruction to _velocity + float momentum = 1.0 - COLLISION_FRICTION * deltaTime; + if ( momentum < 0.0 ) { momentum = 0.0;} + _velocity *= momentum; + } + } + } + } + } +} + + +void Avatar::setDisplayingHead( bool displayingHead ) { + _displayingHead = displayingHead; +} + + void Avatar::render(bool lookingInMirror) { /* @@ -618,8 +644,10 @@ void Avatar::render(bool lookingInMirror) { renderBody(); // render head - renderHead(lookingInMirror); - + if (_displayingHead) { + renderHead(lookingInMirror); + } + // if this is my avatar, then render my interactions with the other avatar if ( _isMine ) { @@ -959,12 +987,22 @@ void Avatar::initializeSkeleton() { calculateBoneLengths(); _pelvisStandingHeight = - _bone[ AVATAR_BONE_PELVIS_SPINE ].length + - _bone[ AVATAR_BONE_LEFT_THIGH ].length + + _bone[ AVATAR_BONE_LEFT_FOOT ].radius + _bone[ AVATAR_BONE_LEFT_SHIN ].length + - _bone[ AVATAR_BONE_LEFT_FOOT ].length + - _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; - + _bone[ AVATAR_BONE_LEFT_THIGH ].length + + _bone[ AVATAR_BONE_PELVIS_SPINE ].length; + //printf( "_pelvisStandingHeight = %f\n", _pelvisStandingHeight ); + + _height = + ( + _pelvisStandingHeight + + _bone[ AVATAR_BONE_MID_SPINE ].length + + _bone[ AVATAR_BONE_CHEST_SPINE].length + + _bone[ AVATAR_BONE_NECK ].length + + _bone[ AVATAR_BONE_HEAD ].length + + _bone[ AVATAR_BONE_HEAD ].radius + ); + // generate world positions updateSkeleton(); } @@ -1131,25 +1169,27 @@ void Avatar::renderBody() { // Render bone positions as spheres for (int b = 0; b < NUM_AVATAR_BONES; b++) { - //renderBoneAsBlock( (AvatarBoneID)b); - //render bone orientation - //renderOrientationDirections( _bone[b].springyPosition, _bone[b].orientation, _bone[b].radius * 2.0 ); - - if ( _usingBodySprings ) { - glColor3fv( skinColor ); - glPushMatrix(); - glTranslatef( _bone[b].springyPosition.x, _bone[b].springyPosition.y, _bone[b].springyPosition.z ); - glutSolidSphere( _bone[b].radius, 20.0f, 20.0f ); - glPopMatrix(); - } - else { - glColor3fv( skinColor ); - glPushMatrix(); - glTranslatef( _bone[b].position.x, _bone[b].position.y, _bone[b].position.z ); - glutSolidSphere( _bone[b].radius, 20.0f, 20.0f ); - glPopMatrix(); - } + if ( b != AVATAR_BONE_HEAD ) { // the head is rendered as a special case in "renderHead" + + //render bone orientation + //renderOrientationDirections( _bone[b].springyPosition, _bone[b].orientation, _bone[b].radius * 2.0 ); + + if ( _usingBodySprings ) { + glColor3fv( skinColor ); + glPushMatrix(); + glTranslatef( _bone[b].springyPosition.x, _bone[b].springyPosition.y, _bone[b].springyPosition.z ); + glutSolidSphere( _bone[b].radius, 20.0f, 20.0f ); + glPopMatrix(); + } + else { + glColor3fv( skinColor ); + glPushMatrix(); + glTranslatef( _bone[b].position.x, _bone[b].position.y, _bone[b].position.z ); + glutSolidSphere( _bone[b].radius, 20.0f, 20.0f ); + glPopMatrix(); + } + } } // Render lines connecting the bone positions @@ -1194,18 +1234,6 @@ void Avatar::renderBody() { } } -void Avatar::renderBoneAsBlock( AvatarBoneID b ) { - glColor3fv( skinColor ); - glPushMatrix(); - glTranslatef( _bone[b].springyPosition.x, _bone[b].springyPosition.y, _bone[b].springyPosition.z ); - glScalef( _bone[b].radius, _bone[b].length, _bone[b].radius ); - glRotatef(_bone[b].yaw, 0, 1, 0 ); - glRotatef(_bone[b].pitch, 1, 0, 0 ); - glRotatef(_bone[b].roll, 0, 0, 1 ); - glutSolidCube(1.0); - glPopMatrix(); -} - void Avatar::SetNewHeadTarget(float pitch, float yaw) { _head.pitchTarget = pitch; _head.yawTarget = yaw; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 6afb65c904..ab1f993bf5 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -32,11 +32,29 @@ const float YAW_MAG = 500.0; //JJV - changed from 300.0; const float TEST_YAW_DECAY = 5.0; const float LIN_VEL_DECAY = 5.0; -const float COLLISION_BODY_RADIUS = 0.1; -const float COLLISION_HEIGHT = 1.5; +const float COLLISION_FRICTION = 0.5; +const float COLLISION_RADIUS_SCALAR = 1.8; +const float COLLISION_BALL_FORCE = 0.1; +const float COLLISION_BODY_FORCE = 3.0; enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; + + +enum DriveKeys +{ + FWD = 0, + BACK, + LEFT, + RIGHT, + UP, + DOWN, + ROT_LEFT, + ROT_RIGHT, + MAX_DRIVE_KEYS +}; + +/* #define FWD 0 #define BACK 1 #define LEFT 2 @@ -46,8 +64,9 @@ enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; #define ROT_LEFT 6 #define ROT_RIGHT 7 #define MAX_DRIVE_KEYS 8 +*/ -#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! +//#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! @@ -89,16 +108,8 @@ enum AvatarBoneID NUM_AVATAR_BONES }; -struct AvatarCollisionElipsoid -{ - bool colliding; - glm::vec3 position; - float girth; - float height; - glm::vec3 upVector; -}; -struct AvatarHandHolding +struct AvatarHandHolding //think of this as one half of a distributed spring :) { glm::vec3 position; glm::vec3 velocity; @@ -111,7 +122,7 @@ struct AvatarBone glm::vec3 position; // the position at the "end" of the bone glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) - glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) + glm::vec3 springyVelocity; // used for special effects ( the velocity of the springy position) float springBodyTightness; // how tightly the springy position tries to stay on the position glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) float yaw; // the yaw Euler angle of the bone rotation off the parent @@ -181,6 +192,8 @@ public: float getBodyYaw() {return _bodyYaw;}; void addBodyYaw(float y) {_bodyYaw += y;}; + bool getIsNearInteractingOther() { return _interactingOtherIsNearby; } + float getAbsoluteHeadYaw() const; void setLeanForward(float dist); void setLeanSideways(float dist); @@ -208,6 +221,7 @@ public: void setHandMovementValues( glm::vec3 movement ); void updateHandMovement( float deltaTime ); void updateArmIKAndConstraints( float deltaTime ); + void setDisplayingHead( bool displayingHead ); float getAverageLoudness() {return _head.averageLoudness;}; void setAverageLoudness(float al) {_head.averageLoudness = al;}; @@ -260,25 +274,20 @@ private: Avatar* _interactingOther; bool _interactingOtherIsNearby; float _pelvisStandingHeight; + float _height; Balls* _balls; AvatarTouch _avatarTouch; + bool _displayingHead; // should be false if in first-person view - // private methods... - void initializeSkeleton(); - void updateSkeleton(); - void initializeBodySprings(); - void updateBodySprings( float deltaTime ); - void calculateBoneLengths(); - void readSensors(); - void renderBoneAsBlock( AvatarBoneID b ); - void updateAvatarCollisionDetectionAndResponse - ( - glm::vec3 collisionPosition, - float collisionGirth, - float collisionHeight, - glm::vec3 collisionUpVector, - float deltaTime - ); + // private methods... + void initializeSkeleton(); + void updateSkeleton(); + void initializeBodySprings(); + void updateBodySprings( float deltaTime ); + void calculateBoneLengths(); + void readSensors(); + void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); + void updateCollisionWithOtherAvatar( Avatar * other, float deltaTime ); }; #endif diff --git a/interface/src/main.cpp b/interface/src/main.cpp index b4d1aae220..aec92245e2 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -742,9 +742,14 @@ void display(void) myCamera.setTightness ( 100.0f ); } else { + //float firstPersonPitch = 20.0f; + //float firstPersonUpShift = 0.0f; + //float firstPersonDistance = 0.0f; + //float firstPersonTightness = 100.0f; + float firstPersonPitch = 20.0f; float firstPersonUpShift = 0.1f; - float firstPersonDistance = 0.0f; + float firstPersonDistance = 0.4f; float firstPersonTightness = 100.0f; float thirdPersonPitch = 0.0f; @@ -753,14 +758,44 @@ void display(void) float thirdPersonTightness = 8.0f; if ( USING_FIRST_PERSON_EFFECT ) { + float ff = 0.0; + float min = 0.1; + float max = 0.5; + + if ( myAvatar.getIsNearInteractingOther()){ + if ( myAvatar.getSpeed() < max ) { + + float s = (myAvatar.getSpeed()- min)/max ; + ff = 1.0 - s; + } + } + + /* + if ( ff < 0.8 ) { + myAvatar.setDisplayingHead( true ); + } else { + myAvatar.setDisplayingHead( false ); + } + */ + + //printf( "ff = %f\n", ff ); + + myCamera.setPitch ( thirdPersonPitch + ff * ( firstPersonPitch - thirdPersonPitch )); + myCamera.setUpShift ( thirdPersonUpShift + ff * ( firstPersonUpShift - thirdPersonUpShift )); + myCamera.setDistance ( thirdPersonDistance + ff * ( firstPersonDistance - thirdPersonDistance )); + myCamera.setTightness ( thirdPersonTightness + ff * ( firstPersonTightness - thirdPersonTightness )); + + + + // this version uses a ramp-up/ramp-down timer in the camera to determine shift between first and thirs-person view + /* if ( myAvatar.getSpeed() < 0.02 ) { if (myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { myCamera.setMode(CAMERA_MODE_FIRST_PERSON); } - printf( "myCamera.getModeShift() = %f\n", myCamera.getModeShift()); - + //printf( "myCamera.getModeShift() = %f\n", myCamera.getModeShift()); myCamera.setPitch ( thirdPersonPitch + myCamera.getModeShift() * ( firstPersonPitch - thirdPersonPitch )); myCamera.setUpShift ( thirdPersonUpShift + myCamera.getModeShift() * ( firstPersonUpShift - thirdPersonUpShift )); myCamera.setDistance ( thirdPersonDistance + myCamera.getModeShift() * ( firstPersonDistance - thirdPersonDistance )); @@ -770,13 +805,14 @@ void display(void) myCamera.setMode(CAMERA_MODE_THIRD_PERSON); } - printf( "myCamera.getModeShift() = %f\n", myCamera.getModeShift()); - + //printf( "myCamera.getModeShift() = %f\n", myCamera.getModeShift()); myCamera.setPitch ( firstPersonPitch + myCamera.getModeShift() * ( thirdPersonPitch - firstPersonPitch )); myCamera.setUpShift ( firstPersonUpShift + myCamera.getModeShift() * ( thirdPersonUpShift - firstPersonUpShift )); myCamera.setDistance ( firstPersonDistance + myCamera.getModeShift() * ( thirdPersonDistance - firstPersonDistance )); myCamera.setTightness ( firstPersonTightness + myCamera.getModeShift() * ( thirdPersonTightness - firstPersonTightness )); } + */ + } else { myCamera.setPitch (thirdPersonPitch ); myCamera.setUpShift (thirdPersonUpShift );