From fe9ab0a2136032905af7f06197a38bb2bdf726c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 29 Apr 2013 14:11:33 -0700 Subject: [PATCH] improved collisions --- interface/src/Avatar.cpp | 144 +++++++++++++++----------- interface/src/Avatar.h | 188 ++++++++++++++++------------------ interface/src/AvatarTouch.cpp | 6 +- interface/src/AvatarTouch.h | 2 + 4 files changed, 177 insertions(+), 163 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 24af81dfdf..21fa44e651 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -109,8 +109,6 @@ Avatar::Avatar(bool isMine) { _head.noise = 0; _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); _usingBodySprings = true; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; _renderYaw = 0.0; _renderPitch = 0.0; _sphere = NULL; @@ -156,8 +154,6 @@ Avatar::Avatar(const Avatar &otherAvatar) { _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; _movedHandOffset = otherAvatar._movedHandOffset; _usingBodySprings = otherAvatar._usingBodySprings; - _springForce = otherAvatar._springForce; - _springVelocityDecay = otherAvatar._springVelocityDecay; _orientation.set( otherAvatar._orientation ); _sphere = NULL; @@ -293,6 +289,7 @@ void Avatar::setMousePressed( bool d ) { _mousePressed = d; } + void Avatar::simulate(float deltaTime) { // update balls @@ -318,14 +315,13 @@ void Avatar::simulate(float deltaTime) { float closestDistance = 10000.0f; AgentList* agentList = AgentList::getInstance(); - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); // check for collisions with other avatars and respond updateCollisionWithOtherAvatar(otherAvatar, deltaTime ); - + // test other avatar hand position for proximity glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); @@ -419,10 +415,24 @@ void Avatar::simulate(float deltaTime) { // decay velocity _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); - // - // Update Head information - // + // update head information + updateHead(deltaTime); + // calculate speed, and use that to determine walking vs. standing + _speed = glm::length( _velocity ); + float rotationalSpeed = fabs( _bodyYawDelta ); + + if ( _speed + rotationalSpeed > 0.2 ) { + _mode = AVATAR_MODE_WALKING; + } else { + _mode = AVATAR_MODE_INTERACTING; + } +} + + + + +void Avatar::updateHead(float deltaTime) { if (!_head.noise) { // Decay back toward center _headPitch *= (1.0f - DECAY * 2 * deltaTime); @@ -515,17 +525,12 @@ void Avatar::simulate(float deltaTime) { const float AUDIO_AVERAGING_SECS = 0.05; _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; - - _speed = glm::length( _velocity ); - float rotationalSpeed = fabs( _bodyYawDelta ); - - if ( _speed + rotationalSpeed > 0.2 ) { - _mode = AVATAR_MODE_WALKING; - } else { - _mode = AVATAR_MODE_INTERACTING; - } } + + + + float Avatar::getHeight() { return _height; } @@ -539,23 +544,21 @@ void Avatar::updateCollisionWithSphere( glm::vec3 position, float radius, float float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); if ( distanceToBigSphere < myBodyApproximateBoundingRadius + radius ) { for (int b = 0; b < NUM_AVATAR_BONES; b++) { - if ( _bone[b].isCollidable ) { - glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - position); - float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); - float combinedRadius = _bone[b].radius + radius; - - if ( distanceToBigSphereCenter < combinedRadius ) { - jointCollision = true; - if (distanceToBigSphereCenter > 0.0) { - glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; - - float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; - - _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; - _velocity += collisionForce * 100.0f * deltaTime; - _bone[b].springyPosition = position + directionVector * combinedRadius; - } + glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - position); + float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); + float combinedRadius = _bone[b].radius + radius; + + if ( distanceToBigSphereCenter < combinedRadius ) { + jointCollision = true; + if (distanceToBigSphereCenter > 0.0) { + glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + + float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); + glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + + _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; + _velocity += collisionForce * 100.0f * deltaTime; + _bone[b].springyPosition = position + directionVector * combinedRadius; } } } @@ -577,40 +580,63 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); 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 ); + // loop through the bones of each avatar to check for every possible collision for (int b=1; b_bone[o].isCollidable ) { glm::vec3 vectorBetweenJoints(_bone[b].springyPosition - otherAvatar->_bone[o].springyPosition); float distanceBetweenJoints = glm::length(vectorBetweenJoints); - - // to avoid divide by zero - if ( distanceBetweenJoints > 0.0 ) { + + if ( distanceBetweenJoints > 0.0 ) { // to avoid divide by zero 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; + // push balls away from each other and apply friction + glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime; + + + float ballMomentum = COLLISION_BALL_FRICTION * deltaTime; + if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;} + + + _bone[b].springyVelocity += ballPushForce; + otherAvatar->_bone[o].springyVelocity -= ballPushForce; - // apply fruction to _velocity - float momentum = 1.0 - COLLISION_FRICTION * deltaTime; - if ( momentum < 0.0 ) { momentum = 0.0;} - _velocity *= momentum; - } - } - } - } - } - } - } -} + _bone[b].springyVelocity *= 0.9; + otherAvatar->_bone[o].springyVelocity *= 0.9; + + // accumulate forces and frictions to the velocities of avatar bodies + bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime; + bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime; + if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;} + + }// check for collision + } // to avoid divide by zero + } // o loop + } // collidable + } // b loop + } // collidable + + + //apply forces and frictions on the bodies of both avatars + _velocity += bodyPushForce; + otherAvatar->_velocity -= bodyPushForce; + _velocity *= bodyMomentum; + otherAvatar->_velocity *= bodyMomentum; + + } // bounding sphere collision +} //method + + void Avatar::setDisplayingHead( bool displayingHead ) { @@ -1069,20 +1095,20 @@ void Avatar::updateBodySprings( float deltaTime ) { if ( length > 0.0f ) { glm::vec3 springDirection = springVector / length; - float force = ( length - _bone[b].length ) * _springForce * deltaTime; + float force = (length - _bone[b].length) * BODY_SPRING_FORCE * deltaTime; _bone[b].springyVelocity -= springDirection * force; if ( _bone[b].parent != AVATAR_BONE_NULL ) { - _bone[ _bone[b].parent ].springyVelocity += springDirection * force; + _bone[_bone[b].parent].springyVelocity += springDirection * force; } } - _bone[b].springyVelocity += ( _bone[b].position - _bone[b].springyPosition ) * _bone[b].springBodyTightness * deltaTime; + _bone[b].springyVelocity += (_bone[b].position - _bone[b].springyPosition) * _bone[b].springBodyTightness * deltaTime; - float decay = 1.0 - _springVelocityDecay * deltaTime; + float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; - if ( decay > 0.0 ) { + if (decay > 0.0) { _bone[b].springyVelocity *= decay; } else { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 8f5a7fe41d..0f252af378 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -9,36 +9,16 @@ #ifndef __interface__avatar__ #define __interface__avatar__ -#include -#include - -#include "world.h" -#include "AvatarTouch.h" - -#include "InterfaceConfig.h" -#include "SerialInterface.h" - #include #include -#include //looks like we might not need this - +#include +#include +#include "world.h" +#include "AvatarTouch.h" +#include "InterfaceConfig.h" +#include "SerialInterface.h" #include "Balls.h" -const bool AVATAR_GRAVITY = true; -const float DECAY = 0.1; -const float THRUST_MAG = 1200.0; -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_FRICTION = 0.5; -const float COLLISION_RADIUS_SCALAR = 1.8; -const float COLLISION_BALL_FORCE = 0.1; -const float COLLISION_BODY_FORCE = 3.0; - -const float MY_HAND_HOLDING_PULL = 0.2; -const float YOUR_HAND_HOLDING_PULL = 1.0; - enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; enum DriveKeys @@ -54,22 +34,6 @@ enum DriveKeys MAX_DRIVE_KEYS }; -/* -#define FWD 0 -#define BACK 1 -#define LEFT 2 -#define RIGHT 3 -#define UP 4 -#define DOWN 5 -#define ROT_LEFT 6 -#define ROT_RIGHT 7 -#define MAX_DRIVE_KEYS 8 -*/ - -//#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes! - - - enum AvatarMode { AVATAR_MODE_STANDING = 0, @@ -108,62 +72,6 @@ enum AvatarBoneID NUM_AVATAR_BONES }; -struct AvatarBone -{ - AvatarBoneID parent; // which bone is this bone connected to? - glm::vec3 position; // the position at the "end" of the bone - in global space - 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::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 - float pitch; // the pitch Euler angle of the bone rotation off the parent - float roll; // the roll Euler angle of the bone rotation off the parent - Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll - float length; // the length of the bone - float radius; // used for detecting collisions for certain physical effects - bool isCollidable; // when false, the bone position will not register a collision -}; - -struct AvatarHead -{ - float pitchRate; - float yawRate; - float rollRate; - float noise; - float eyeballPitch[2]; - float eyeballYaw [2]; - float eyebrowPitch[2]; - float eyebrowRoll [2]; - float eyeballScaleX; - float eyeballScaleY; - float eyeballScaleZ; - float interPupilDistance; - float interBrowDistance; - float nominalPupilSize; - float pupilSize; - float mouthPitch; - float mouthYaw; - float mouthWidth; - float mouthHeight; - float leanForward; - float leanSideways; - float pitchTarget; - float yawTarget; - float noiseEnvelope; - float pupilConverge; - float scale; - int eyeContact; - float browAudioLift; - eyeContactTargets eyeContactTarget; - - // Sound loudness information - float lastLoudness; - float averageLoudness; - float audioAttack; -}; - class Avatar : public AvatarData { public: @@ -234,8 +142,87 @@ public: // Find out what the local gravity vector is at this location glm::vec3 getGravity(glm::vec3 pos); - + private: + + const bool AVATAR_GRAVITY = true; + const float DECAY = 0.1; + const float THRUST_MAG = 1200.0; + 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 MY_HAND_HOLDING_PULL = 0.2; + const float YOUR_HAND_HOLDING_PULL = 1.0; + const float BODY_SPRING_FORCE = 6.0f; + const float BODY_SPRING_DECAY = 16.0f; + + //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; + + const float COLLISION_RADIUS_SCALAR = 1.8; + const float COLLISION_BALL_FORCE = 0.6; + const float COLLISION_BODY_FORCE = 6.0; + const float COLLISION_BALL_FRICTION = 200.0; + const float COLLISION_BODY_FRICTION = 0.5; + + struct AvatarBone + { + AvatarBoneID parent; // which bone is this bone connected to? + glm::vec3 position; // the position at the "end" of the bone - in global space + 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::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 + float pitch; // the pitch Euler angle of the bone rotation off the parent + float roll; // the roll Euler angle of the bone rotation off the parent + Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll + float length; // the length of the bone + float radius; // used for detecting collisions for certain physical effects + bool isCollidable; // when false, the bone position will not register a collision + }; + + struct AvatarHead + { + float pitchRate; + float yawRate; + float rollRate; + float noise; + float eyeballPitch[2]; + float eyeballYaw [2]; + float eyebrowPitch[2]; + float eyebrowRoll [2]; + float eyeballScaleX; + float eyeballScaleY; + float eyeballScaleZ; + float interPupilDistance; + float interBrowDistance; + float nominalPupilSize; + float pupilSize; + float mouthPitch; + float mouthYaw; + float mouthWidth; + float mouthHeight; + float leanForward; + float leanSideways; + float pitchTarget; + float yawTarget; + float noiseEnvelope; + float pupilConverge; + float scale; + int eyeContact; + float browAudioLift; + eyeContactTargets eyeContactTarget; + + // Sound loudness information + float lastLoudness; + float averageLoudness; + float audioAttack; + }; + AvatarHead _head; bool _isMine; glm::vec3 _TEST_bigSpherePosition; @@ -244,8 +231,6 @@ private: float _bodyYawDelta; bool _usingBodySprings; glm::vec3 _movedHandOffset; - float _springVelocityDecay; - float _springForce; glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion AvatarBone _bone[ NUM_AVATAR_BONES ]; AvatarMode _mode; @@ -277,6 +262,7 @@ private: void updateBodySprings( float deltaTime ); void calculateBoneLengths(); void readSensors(); + void updateHead( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); void updateCollisionWithOtherAvatar( Avatar * other, float deltaTime ); }; diff --git a/interface/src/AvatarTouch.cpp b/interface/src/AvatarTouch.cpp index ad4f0ccf33..41e040c382 100644 --- a/interface/src/AvatarTouch.cpp +++ b/interface/src/AvatarTouch.cpp @@ -56,8 +56,8 @@ void AvatarTouch::simulate (float deltaTime) { glm::vec3 v = _yourHandPosition - _myHandPosition; for (int p=0; p