From 2a1bbcc1683a2b11f71ba10b004d424d5ef378d3 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 6 May 2013 12:35:52 -0700 Subject: [PATCH] improved avatar gravity code and moved source of gravity vector to main.cpp --- interface/src/Avatar.cpp | 181 ++++++++++++++++++--------------------- interface/src/Avatar.h | 7 +- interface/src/main.cpp | 27 ++++++ 3 files changed, 115 insertions(+), 100 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 3e4a8430e7..a1a93fbfe3 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -21,7 +21,9 @@ using namespace std; const bool BALLS_ON = false; -const bool AVATAR_GRAVITY = true; +const bool USING_AVATAR_GRAVITY = true; +const float GRAVITY_SCALE = 6.0f; +const float BOUNCE = 0.3f; const float DECAY = 0.1; const float THRUST_MAG = 1200.0; const float YAW_MAG = 500.0; @@ -145,6 +147,7 @@ Avatar::Avatar(bool isMine) { _interactingOther = NULL; _handHoldingPosition = glm::vec3(0.0f, 0.0f, 0.0f); _distanceToNearestAvatar = std::numeric_limits::max(); + _gravity = glm::vec3(0.0f, -1.0f, 0.0f); // default initializeSkeleton(); @@ -336,13 +339,13 @@ void Avatar::simulate(float deltaTime) { updateHandMovementAndTouching(deltaTime); - // apply gravity and collision wiht the ground/floor - if (AVATAR_GRAVITY) { - if ( _position.y > _pelvisStandingHeight + 0.01f) { - _velocity += glm::dvec3(getGravity(getPosition())) * (6.0 * deltaTime ); + // apply gravity and collision with the ground/floor + if (USING_AVATAR_GRAVITY) { + if (_position.y > _pelvisStandingHeight + 0.01f) { + _velocity += _gravity * (GRAVITY_SCALE * deltaTime); } else if (_position.y < _pelvisStandingHeight) { _position.y = _pelvisStandingHeight; - _velocity.y = 0.0; + _velocity.y = -_velocity.y * BOUNCE; } } @@ -387,16 +390,16 @@ void Avatar::simulate(float deltaTime) { _velocity += _thrust * deltaTime; // calculate speed - _speed = glm::length( _velocity ); + _speed = glm::length(_velocity); //pitch and roll the body as a function of forward speed and turning delta - float forwardComponentOfVelocity = glm::dot( _orientation.getFront(), _velocity ); + float forwardComponentOfVelocity = glm::dot(_orientation.getFront(), _velocity); _bodyPitch += BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity; _bodyRoll += BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta; // these forces keep the body upright... float tiltDecay = 1.0 - BODY_UPRIGHT_FORCE * deltaTime; - if ( tiltDecay < 0.0f ) { tiltDecay = 0.0f; } + if (tiltDecay < 0.0f) {tiltDecay = 0.0f;} _bodyPitch *= tiltDecay; _bodyRoll *= tiltDecay; @@ -404,7 +407,7 @@ void Avatar::simulate(float deltaTime) { _position += _velocity * deltaTime; // decay velocity - _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); + _velocity *= (1.0 - LIN_VEL_DECAY * deltaTime); // If someone is near, damp velocity as a function of closeness const float AVATAR_BRAKING_RANGE = 1.2f; @@ -419,7 +422,7 @@ void Avatar::simulate(float deltaTime) { updateHead(deltaTime); // use speed and angular velocity to determine walking vs. standing - if ( _speed + fabs( _bodyYawDelta ) > 0.2 ) { + if (_speed + fabs(_bodyYawDelta) > 0.2) { _mode = AVATAR_MODE_WALKING; } else { _mode = AVATAR_MODE_INTERACTING; @@ -449,7 +452,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { // if the avatar being simulated is mine, then loop through // all the other avatars for potential interactions... - if ( _isMine ) + if (_isMine) { // Reset detector for nearest avatar _distanceToNearestAvatar = std::numeric_limits::max(); @@ -463,24 +466,24 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { updateCollisionWithOtherAvatar(otherAvatar, deltaTime ); // test other avatar hand position for proximity - glm::vec3 v( _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position ); - v -= otherAvatar->getJointPosition( AVATAR_JOINT_RIGHT_SHOULDER ); + glm::vec3 v(_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position); + v -= otherAvatar->getJointPosition(AVATAR_JOINT_RIGHT_SHOULDER); - float distance = glm::length( v ); - if (distance < _distanceToNearestAvatar) { _distanceToNearestAvatar = distance; } + float distance = glm::length(v); + if (distance < _distanceToNearestAvatar) {_distanceToNearestAvatar = distance;} if (distance < _maxArmLength + _maxArmLength) { _interactingOther = otherAvatar; - if ( ! _avatarTouch.getAbleToReachOtherAvatar() ) { + if (! _avatarTouch.getAbleToReachOtherAvatar()) { //initialize _handHolding _handHoldingPosition = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position; _avatarTouch.setAbleToReachOtherAvatar(true); } - glm::vec3 vectorBetweenHands( _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position ); - vectorBetweenHands -= otherAvatar->getJointPosition( AVATAR_JOINT_RIGHT_FINGERTIPS ); + glm::vec3 vectorBetweenHands(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + vectorBetweenHands -= otherAvatar->getJointPosition(AVATAR_JOINT_RIGHT_FINGERTIPS); float distanceBetweenHands = glm::length(vectorBetweenHands); if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) { @@ -488,7 +491,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { } // if I am holding hands with another avatar, a force is applied - if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) { + if ((_handState == 1) || (_interactingOther->_handState == 1)) { // if the hands are close enough to grasp... if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) @@ -502,7 +505,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handHoldingPosition; // apply a force to the avatar body - if ( glm::length(vectorToOtherHand) > _maxArmLength * 0.9 ) { + if (glm::length(vectorToOtherHand) > _maxArmLength * 0.9) { _velocity += vectorToOtherHand; } } @@ -514,18 +517,18 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { // Set the vector we send for hand position to other people to be our right hand setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); - }//if ( _isMine ) + }//if (_isMine) //constrain right arm length and re-adjust elbow position as it bends - updateArmIKAndConstraints( deltaTime ); + updateArmIKAndConstraints(deltaTime); // set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints - if ( _interactingOther ) { + if (_interactingOther) { if (_isMine) { - _avatarTouch.setMyHandPosition ( _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position ); - _avatarTouch.setYourHandPosition( _interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position ); - _avatarTouch.setMyHandState ( _handState ); - _avatarTouch.setYourHandState ( _interactingOther->_handState ); + _avatarTouch.setMyHandPosition (_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + _avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + _avatarTouch.setMyHandState (_handState); + _avatarTouch.setYourHandState (_interactingOther->_handState); _avatarTouch.simulate(deltaTime); } } @@ -539,7 +542,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { void Avatar::updateHead(float deltaTime) { //apply the head lean values to the springy position... - if ( fabs( _head.leanSideways + _head.leanForward ) > 0.0f ) { + if (fabs( _head.leanSideways + _head.leanForward ) > 0.0f) { glm::vec3 headLean = _orientation.getRight() * _head.leanSideways + _orientation.getFront() * _head.leanForward; @@ -650,19 +653,19 @@ float Avatar::getHeight() { } -void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ) { +void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float deltaTime) { float myBodyApproximateBoundingRadius = 1.0f; glm::vec3 vectorFromMyBodyToBigSphere(_position - position); bool jointCollision = false; float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); - if ( distanceToBigSphere < myBodyApproximateBoundingRadius + radius ) { + if (distanceToBigSphere < myBodyApproximateBoundingRadius + radius) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { glm::vec3 vectorFromJointToBigSphereCenter(_joint[b].springyPosition - position); float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); float combinedRadius = _joint[b].radius + radius; - if ( distanceToBigSphereCenter < combinedRadius ) { + if (distanceToBigSphereCenter < combinedRadius) { jointCollision = true; if (distanceToBigSphereCenter > 0.0) { glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; @@ -677,7 +680,7 @@ void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float } } - if ( jointCollision ) { + if (jointCollision) { if (!_usingBodySprings) { _usingBodySprings = true; initializeBodySprings(); @@ -688,37 +691,37 @@ void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float //detect collisions with other avatars and respond -void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTime ) { +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 ) { + if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) { float bodyMomentum = 1.0f; - glm::vec3 bodyPushForce = glm::vec3( 0.0, 0.0, 0.0 ); + glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); // loop through the joints of each avatar to check for every possible collision for (int b=1; b_joint[o].isCollidable ) { + if (otherAvatar->_joint[o].isCollidable) { glm::vec3 vectorBetweenJoints(_joint[b].springyPosition - otherAvatar->_joint[o].springyPosition); float distanceBetweenJoints = glm::length(vectorBetweenJoints); - if ( distanceBetweenJoints > 0.0 ) { // to avoid divide by zero + if (distanceBetweenJoints > 0.0 ) { // to avoid divide by zero float combinedRadius = _joint[b].radius + otherAvatar->_joint[o].radius; // check for collision - if ( distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { + if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; // push balls away from each other and apply friction glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime; float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime; - if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;} + if (ballMomentum < 0.0 ) { ballMomentum = 0.0;} _joint[b].springyVelocity += ballPushForce; otherAvatar->_joint[o].springyVelocity -= ballPushForce; @@ -729,7 +732,7 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi // accumulate forces and frictions to apply to the velocities of avatar bodies bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime; bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime; - if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;} + if (bodyMomentum < 0.0 ) { bodyMomentum = 0.0;} }// check for collision } // to avoid divide by zero @@ -749,7 +752,7 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi } //method -void Avatar::setDisplayingHead( bool displayingHead ) { +void Avatar::setDisplayingHead(bool displayingHead ) { _displayingHead = displayingHead; } @@ -760,28 +763,33 @@ static TextRenderer* textRenderer() { } +void Avatar::setGravity(glm::vec3 gravity) { + _gravity = gravity; +} + + void Avatar::render(bool lookingInMirror) { // render a simple round on the ground projected down from the avatar's position - renderDiskShadow( _position, glm::vec3( 0.0f, 1.0f, 0.0f ), 0.1f, 0.2f ); + renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f ), 0.1f, 0.2f ); /* // show avatar position - glColor4f( 0.5f, 0.5f, 0.5f, 0.6 ); + glColor4f(0.5f, 0.5f, 0.5f, 0.6 ); glPushMatrix(); glTranslatef(_position.x, _position.y, _position.z); - glScalef( 0.03, 0.03, 0.03 ); - glutSolidSphere( 1, 10, 10 ); + glScalef(0.03, 0.03, 0.03 ); + glutSolidSphere(1, 10, 10 ); glPopMatrix(); */ - if ( usingBigSphereCollisionTest ) { + if (usingBigSphereCollisionTest ) { // show TEST big sphere - glColor4f( 0.5f, 0.6f, 0.8f, 0.7 ); + glColor4f(0.5f, 0.6f, 0.8f, 0.7 ); glPushMatrix(); glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z); - glScalef( _TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); - glutSolidSphere( 1, 20, 20 ); + glScalef(_TEST_bigSphereRadius, _TEST_bigSphereRadius, _TEST_bigSphereRadius ); + glutSolidSphere(1, 20, 20 ); glPopMatrix(); } @@ -794,7 +802,7 @@ void Avatar::render(bool lookingInMirror) { } // if this is my avatar, then render my interactions with the other avatar - if ( _isMine ) { + if (_isMine ) { _avatarTouch.render(); } @@ -855,7 +863,7 @@ void Avatar::renderHead(bool lookingInMirror) { glEnable(GL_RESCALE_NORMAL); // show head orientation - //renderOrientationDirections( _joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition, _joint[ AVATAR_JOINT_HEAD_BASE ].orientation, 0.2f ); + //renderOrientationDirections(_joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition, _joint[ AVATAR_JOINT_HEAD_BASE ].orientation, 0.2f ); glPushMatrix(); @@ -871,7 +879,7 @@ void Avatar::renderHead(bool lookingInMirror) { } glScalef - ( + ( _joint[ AVATAR_JOINT_HEAD_BASE ].radius, _joint[ AVATAR_JOINT_HEAD_BASE ].radius, _joint[ AVATAR_JOINT_HEAD_BASE ].radius @@ -883,15 +891,15 @@ void Avatar::renderHead(bool lookingInMirror) { //glRotatef(_bodyPitch + _headPitch, 1, 0, 0); //glRotatef(_bodyRoll - _headRoll, 0, 0, 1); // don't let body pitch and roll affect the head.. - glRotatef( _headPitch, 1, 0, 0); - glRotatef( -_headRoll, 0, 0, 1); + glRotatef( _headPitch, 1, 0, 0); + glRotatef(-_headRoll, 0, 0, 1); } else { glRotatef(_bodyYaw + _headYaw, 0, 1, 0); //glRotatef(_bodyPitch + _headPitch, 1, 0, 0); //glRotatef(_bodyRoll + _headRoll, 0, 0, 1); // don't let body pitch and roll affect the head.. - glRotatef( _headPitch, 1, 0, 0); - glRotatef( _headRoll, 0, 0, 1); + glRotatef(_headPitch, 1, 0, 0); + glRotatef(_headRoll, 0, 0, 1); } //glScalef(2.0, 2.0, 2.0); @@ -1020,7 +1028,7 @@ void Avatar::renderHead(bool lookingInMirror) { glPopMatrix(); } -void Avatar::setHandMovementValues( glm::vec3 handOffset ) { +void Avatar::setHandMovementValues(glm::vec3 handOffset ) { _movedHandOffset = handOffset; } @@ -1033,11 +1041,11 @@ void Avatar::initializeSkeleton() { for (int b=0; b 0.f) && - (pos.x < 10.f) && - (pos.z > 0.f) && - (pos.z < 10.f) && - (pos.y > 0.f) && - (pos.y < 3.f)) { - // If above ground plane, turn gravity on - return glm::vec3(0.f, -1.f, 0.f); - } else { - // If flying in space, turn gravity OFF - return glm::vec3(0.f, 0.f, 0.f); - } -} const char AVATAR_DATA_FILENAME[] = "avatar.ifd"; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d2570d1976..6fb8ee01ee 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -84,7 +84,7 @@ public: void reset(); void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); - void setNoise (float mag) { _head.noise = mag; } + void setNoise (float mag) {_head.noise = mag;} void setScale(float s) {_head.scale = s; }; void setRenderYaw(float y) {_renderYaw = y;} void setRenderPitch(float p) {_renderPitch = p;} @@ -93,6 +93,7 @@ public: float getLastMeasuredHeadYaw() const {return _head.yawRate;} float getBodyYaw() {return _bodyYaw;}; void addBodyYaw(float y) {_bodyYaw += y;}; + void setGravity(glm::vec3 gravity); bool getIsNearInteractingOther(); @@ -143,9 +144,6 @@ public: void processTransmitterData(unsigned char * packetData, int numBytes); float getTransmitterHz() { return _transmitterHz; }; - // Find out what the local gravity vector is at this location - glm::vec3 getGravity(glm::vec3 pos); - void writeAvatarDataToFile(); void readAvatarDataFromFile(); @@ -251,6 +249,7 @@ private: bool _displayingHead; // should be false if in first-person view bool _returnHeadToCenter; float _distanceToNearestAvatar; // How close is the nearest avatar? + glm::vec3 _gravity; // private methods... void initializeSkeleton(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 13654da2d0..8916fcd319 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -90,6 +90,8 @@ using namespace std; void reshape(int width, int height); // will be defined below void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below +glm::vec3 getGravity(glm::vec3 pos); //get the local gravity vector at this location in the universe + QApplication* app; bool enableNetworkThread = true; @@ -1703,6 +1705,7 @@ void idle(void) { } agentList->unlock(); + myAvatar.setGravity(getGravity(myAvatar.getPosition())); myAvatar.simulate(deltaTime); glutPostRedisplay(); @@ -1765,6 +1768,30 @@ void reshape(int width, int height) { glLoadIdentity(); } + + + + +//Find and return the gravity vector at this location +glm::vec3 getGravity(glm::vec3 pos) { + // + // For now, we'll test this with a simple global lookup, but soon we will add getting this + // from the domain/voxelserver (or something similar) + // + if ((pos.x > 0.f) && + (pos.x < 10.f) && + (pos.z > 0.f) && + (pos.z < 10.f) && + (pos.y > 0.f) && + (pos.y < 3.f)) { + // If above ground plane, turn gravity on + return glm::vec3(0.f, -1.f, 0.f); + } else { + // If flying in space, turn gravity OFF + return glm::vec3(0.f, 0.f, 0.f); + } +} + void mouseFunc(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) { if (state == GLUT_DOWN && !menu.mouseClick(x, y)) {