From f39050ae284519e9e3e72dc1d359664c72f6516b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Aug 2013 11:37:57 -0700 Subject: [PATCH 01/12] Enable lookat vectors by default and make them glow. --- interface/src/Menu.cpp | 2 +- interface/src/avatar/Head.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b435604d3f..6ded7cd939 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -165,7 +165,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::FrameTimer); - addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtVectors); + addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtVectors, 0, true); addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtIndicator, 0, true); addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::FirstPerson, Qt::Key_P, true); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 160510734f..7ee9a7f245 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -742,6 +742,8 @@ void Head::renderEyeBalls() { void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { + Application::getInstance()->getGlowEffect()->begin(); + glLineWidth(2.0); glBegin(GL_LINES); glColor4f(0.2f, 0.2f, 0.2f, 1.f); @@ -753,6 +755,8 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi glColor4f(1.0f, 1.0f, 1.0f, 0.f); glVertex3f(lookatPosition.x, lookatPosition.y, lookatPosition.z); glEnd(); + + Application::getInstance()->getGlowEffect()->end(); } void Head::updateHairPhysics(float deltaTime) { From f4109b3fb4fe0e5c0f25d241966ed6ef71715b57 Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Wed, 21 Aug 2013 13:24:54 -0700 Subject: [PATCH 02/12] Add MyAvatar subclass. For functions such as render() and simulate(), they have been edited so that there are MyAvatar and Avatar specific versions in their respective classes. isMyAvatar() has been removed. --- interface/src/Application.h | 5 +- interface/src/avatar/Avatar.cpp | 820 ++------------------------------ interface/src/avatar/Avatar.h | 126 ++--- interface/src/avatar/Hand.cpp | 2 +- 4 files changed, 69 insertions(+), 884 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 88cb86312f..75632d251f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -44,6 +44,7 @@ #include "Webcam.h" #include "PieMenu.h" #include "avatar/Avatar.h" +#include "avatar/MyAvatar.h" #include "avatar/HandControl.h" #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" @@ -106,7 +107,7 @@ public: void updateParticleSystem(float deltaTime); QGLWidget* getGLWidget() { return _glWidget; } - Avatar* getAvatar() { return &_myAvatar; } + MyAvatar* getAvatar() { return &_myAvatar; } Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } @@ -371,7 +372,7 @@ private: Oscilloscope _audioScope; - Avatar _myAvatar; // The rendered avatar of oneself + MyAvatar _myAvatar; // The rendered avatar of oneself Transmitter _myTransmitter; // Gets UDP data from transmitter app used to animate the avatar diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index e561720eaf..58e622032d 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -58,60 +58,44 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; -bool usingBigSphereCollisionTest = true; +const bool usingBigSphereCollisionTest = true; -float chatMessageScale = 0.0015; -float chatMessageHeight = 0.20; +const float chatMessageScale = 0.0015; +const float chatMessageHeight = 0.20; Avatar::Avatar(Node* owningNode) : AvatarData(owningNode), - _initialized(false), _head(this), _hand(this), _ballSpringsInitialized(false), _TEST_bigSphereRadius(0.5f), _TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f), - _mousePressed(false), - _bodyPitchDelta(0.0f), _bodyYawDelta(0.0f), - _bodyRollDelta(0.0f), + // _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), - _handHoldingPosition(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), - _shouldJump(false), _speed(0.0f), - _maxArmLength(0.0f), _leanScale(0.5f), - _pelvisStandingHeight(0.0f), + _pelvisFloatingHeight(0.0f), _scale(1.0f), - _distanceToNearestAvatar(std::numeric_limits::max()), - _gravity(0.0f, -1.0f, 0.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), _mouseRayOrigin(0.0f, 0.0f, 0.0f), _mouseRayDirection(0.0f, 0.0f, 0.0f), - _interactingOther(NULL), - _isMouseTurningRight(false), - _elapsedTimeMoving(0.0f), - _elapsedTimeStopped(0.0f), - _elapsedTimeSinceCollision(0.0f), - _lastCollisionPosition(0, 0, 0), - _speedBrakes(false), - _isThrustOn(false), _isCollisionsOn(true), _leadingAvatar(NULL), - _voxels(this) + _voxels(this), + _initialized(false), + _handHoldingPosition(0.0f, 0.0f, 0.0f), + _maxArmLength(0.0f), + _pelvisStandingHeight(0.0f) { // 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; - } - _skeleton.initialize(); initializeBodyBalls(); @@ -130,8 +114,6 @@ Avatar::Avatar(Node* owningNode) : } else { _balls = NULL; } - - _collisionRadius = _height * 0.125f; } @@ -289,85 +271,6 @@ void Avatar::init() { _initialized = true; } -void Avatar::reset() { - _head.reset(); - _hand.reset(); -} - -// Update avatar head rotation with sensor data -void Avatar::updateFromGyrosAndOrWebcam(bool gyroLook, - float pitchFromTouch) { - SerialInterface* gyros = Application::getInstance()->getSerialHeadSensor(); - Webcam* webcam = Application::getInstance()->getWebcam(); - glm::vec3 estimatedPosition, estimatedRotation; - if (gyros->isActive()) { - estimatedRotation = gyros->getEstimatedRotation(); - - } else if (webcam->isActive()) { - estimatedRotation = webcam->getEstimatedRotation(); - - } else if (_leadingAvatar) { - _head.getFace().clearFrame(); - return; - } else { - _head.setMousePitch(pitchFromTouch); - _head.setPitch(pitchFromTouch); - _head.getFace().clearFrame(); - return; - } - _head.setMousePitch(pitchFromTouch); - - if (webcam->isActive()) { - estimatedPosition = webcam->getEstimatedPosition(); - - // apply face data - _head.getFace().setFrameFromWebcam(); - - // compute and store the joint rotations - const JointVector& joints = webcam->getEstimatedJoints(); - _joints.clear(); - for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - if (joints.size() > i && joints[i].isValid) { - JointData data = { i, joints[i].rotation }; - _joints.push_back(data); - - if (i == AVATAR_JOINT_CHEST) { - // if we have a chest rotation, don't apply lean based on head - estimatedPosition = glm::vec3(); - } - } - } - } else { - _head.getFace().clearFrame(); - } - - // Set the rotation of the avatar's head (as seen by others, not affecting view frustum) - // to be scaled. Pitch is greater to emphasize nodding behavior / synchrony. - const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; - const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; - const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; - _head.setPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); - _head.setYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); - _head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); - _head.setCameraFollowsHead(gyroLook); - - // Update torso lean distance based on accelerometer data - const float TORSO_LENGTH = _scale * 0.5f; - const float MAX_LEAN = 45.0f; - _head.setLeanSideways(glm::clamp(glm::degrees(atanf(estimatedPosition.x * _leanScale / TORSO_LENGTH)), - -MAX_LEAN, MAX_LEAN)); - _head.setLeanForward(glm::clamp(glm::degrees(atanf(estimatedPosition.z * _leanScale / TORSO_LENGTH)), - -MAX_LEAN, MAX_LEAN)); -} - -float Avatar::getAbsoluteHeadYaw() const { - return glm::yaw(_head.getOrientation()); -} - -float Avatar::getAbsoluteHeadPitch() const { - return glm::pitch(_head.getOrientation()); -} - glm::quat Avatar::getOrientation() const { return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); } @@ -376,144 +279,6 @@ glm::quat Avatar::getWorldAlignedOrientation () const { return computeRotationFromBodyToWorldUp() * getOrientation(); } -glm::vec3 Avatar::getUprightHeadPosition() const { - return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, _pelvisToHeadLength, 0.0f); -} - -glm::vec3 Avatar::getUprightEyeLevelPosition() const { - const float EYE_UP_OFFSET = 0.36f; - glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; - return _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET + glm::vec3(0.0f, _pelvisToHeadLength, 0.0f); -} - -glm::vec3 Avatar::getEyePosition() { - const float EYE_UP_OFFSET = 0.36f; - const float EYE_FRONT_OFFSET = 0.8f; - - glm::quat orientation = getWorldAlignedOrientation(); - glm::vec3 up = orientation * IDENTITY_UP; - glm::vec3 front = orientation * IDENTITY_FRONT; - - float scale = _scale * BODY_BALL_RADIUS_HEAD_BASE; - - return getHead().getPosition() + up * scale * EYE_UP_OFFSET + front * scale * EYE_FRONT_OFFSET; -} - -void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) { - // - // Gather thrust information from keyboard and sensors to apply to avatar motion - // - glm::quat orientation = getHead().getCameraOrientation(); - glm::vec3 front = orientation * IDENTITY_FRONT; - glm::vec3 right = orientation * IDENTITY_RIGHT; - glm::vec3 up = orientation * IDENTITY_UP; - - const float THRUST_MAG_UP = 800.0f; - const float THRUST_MAG_DOWN = 300.f; - const float THRUST_MAG_FWD = 500.f; - const float THRUST_MAG_BACK = 300.f; - const float THRUST_MAG_LATERAL = 250.f; - const float THRUST_JUMP = 120.f; - - // Add Thrusts from keyboard - if (_driveKeys[FWD ]) {_thrust += _scale * THRUST_MAG_FWD * deltaTime * front;} - if (_driveKeys[BACK ]) {_thrust -= _scale * THRUST_MAG_BACK * deltaTime * front;} - if (_driveKeys[RIGHT ]) {_thrust += _scale * THRUST_MAG_LATERAL * deltaTime * right;} - if (_driveKeys[LEFT ]) {_thrust -= _scale * THRUST_MAG_LATERAL * deltaTime * right;} - if (_driveKeys[UP ]) {_thrust += _scale * THRUST_MAG_UP * deltaTime * up;} - if (_driveKeys[DOWN ]) {_thrust -= _scale * THRUST_MAG_DOWN * deltaTime * up;} - if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} - if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} - - // Add one time jumping force if requested - if (_shouldJump) { - _thrust += _scale * THRUST_JUMP * up; - _shouldJump = false; - } - - - // Add thrusts from leading avatar - const float FOLLOWING_RATE = 0.02f; - const float MIN_YAW = 5.0f; - const float MIN_PITCH = 1.0f; - const float PITCH_RATE = 0.1f; - const float MIN_YAW_BEFORE_PITCH = 30.0f; - - if (_leadingAvatar != NULL) { - glm::vec3 toTarget = _leadingAvatar->getPosition() - _position; - - if (glm::length(_position - _leadingAvatar->getPosition()) > _scale * _stringLength) { - _position += toTarget * FOLLOWING_RATE; - } else { - toTarget = _leadingAvatar->getHead().getLookAtPosition() - _head.getPosition(); - } - toTarget = glm::vec3(glm::dot(right, toTarget), - glm::dot(up , toTarget), - glm::dot(front, toTarget)); - - float yawAngle = angleBetween(-IDENTITY_FRONT, glm::vec3(toTarget.x, 0.f, toTarget.z)); - if (glm::abs(yawAngle) > MIN_YAW){ - if (IDENTITY_RIGHT.x * toTarget.x + IDENTITY_RIGHT.y * toTarget.y + IDENTITY_RIGHT.z * toTarget.z > 0) { - _bodyYawDelta -= yawAngle; - } else { - _bodyYawDelta += yawAngle; - } - } - - float pitchAngle = glm::abs(90.0f - angleBetween(IDENTITY_UP, toTarget)); - if (glm::abs(pitchAngle) > MIN_PITCH && yawAngle < MIN_YAW_BEFORE_PITCH){ - if (IDENTITY_UP.x * toTarget.x + IDENTITY_UP.y * toTarget.y + IDENTITY_UP.z * toTarget.z > 0) { - _head.setMousePitch(_head.getMousePitch() + PITCH_RATE * pitchAngle); - } else { - _head.setMousePitch(_head.getMousePitch() - PITCH_RATE * pitchAngle); - } - _head.setPitch(_head.getMousePitch()); - } - } - - - // Add thrusts from Transmitter - if (transmitter) { - transmitter->checkForLostTransmitter(); - glm::vec3 rotation = transmitter->getEstimatedRotation(); - const float TRANSMITTER_MIN_RATE = 1.f; - const float TRANSMITTER_MIN_YAW_RATE = 4.f; - const float TRANSMITTER_LATERAL_FORCE_SCALE = 5.f; - const float TRANSMITTER_FWD_FORCE_SCALE = 25.f; - const float TRANSMITTER_UP_FORCE_SCALE = 100.f; - const float TRANSMITTER_YAW_SCALE = 10.0f; - const float TRANSMITTER_LIFT_SCALE = 3.f; - const float TOUCH_POSITION_RANGE_HALF = 32767.f; - if (fabs(rotation.z) > TRANSMITTER_MIN_RATE) { - _thrust += rotation.z * TRANSMITTER_LATERAL_FORCE_SCALE * deltaTime * right; - } - if (fabs(rotation.x) > TRANSMITTER_MIN_RATE) { - _thrust += -rotation.x * TRANSMITTER_FWD_FORCE_SCALE * deltaTime * front; - } - if (fabs(rotation.y) > TRANSMITTER_MIN_YAW_RATE) { - _bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime; - } - if (transmitter->getTouchState()->state == 'D') { - _thrust += TRANSMITTER_UP_FORCE_SCALE * - (float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF * - TRANSMITTER_LIFT_SCALE * - deltaTime * - up; - } - } - - // Update speed brake status - const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f; - if ((glm::length(_thrust) == 0.0f) && _isThrustOn && (glm::length(_velocity) > MIN_SPEED_BRAKE_VELOCITY)) { - _speedBrakes = true; - } - - if (_speedBrakes && (glm::length(_velocity) < MIN_SPEED_BRAKE_VELOCITY)) { - _speedBrakes = false; - } - _isThrustOn = (glm::length(_thrust) > EPSILON); -} - void Avatar::follow(Avatar* leadingAvatar) { const float MAX_STRING_LENGTH = 2; @@ -535,55 +300,16 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 right = orientation * IDENTITY_RIGHT; - // Update movement timers - if (isMyAvatar()) { - _elapsedTimeSinceCollision += deltaTime; - const float VELOCITY_MOVEMENT_TIMER_THRESHOLD = 0.2f; - if (glm::length(_velocity) < VELOCITY_MOVEMENT_TIMER_THRESHOLD) { - _elapsedTimeMoving = 0.f; - _elapsedTimeStopped += deltaTime; - } else { - _elapsedTimeStopped = 0.f; - _elapsedTimeMoving += deltaTime; - } - } - if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) { follow(NULL); } - // Ajust, scale, position and lookAt position when following an other avatar - if (isMyAvatar() && _leadingAvatar && _newScale != _leadingAvatar->getScale()) { - _newScale = _leadingAvatar->getScale(); - } - - if (isMyAvatar() && _scale != _newScale) { - float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _newScale; - setScale(scale); - Application::getInstance()->getCamera()->setScale(scale); - } - - if (!isMyAvatar() && _scale != _newScale) { + if (_scale != _newScale) { setScale(_newScale); } - // Collect thrust forces from keyboard and devices - if (isMyAvatar()) { - updateThrust(deltaTime, transmitter); - } - // copy velocity so we can use it later for acceleration glm::vec3 oldVelocity = getVelocity(); - - if (isMyAvatar()) { - // calculate speed - _speed = glm::length(_velocity); - } - - //figure out if the mouse cursor is over any body spheres... - if (isMyAvatar()) { - checkForMouseRayTouching(); - } // update balls if (_balls) { @@ -632,42 +358,11 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer } // if this is not my avatar, then hand position comes from transmitted data - if (!isMyAvatar()) { - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handPosition; - } + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handPosition; //update the movement of the hand and process handshaking with other avatars... updateHandMovementAndTouching(deltaTime, enableHandMovement); _avatarTouch.simulate(deltaTime); - - if (isMyAvatar()) { - - // apply gravity - if (USING_AVATAR_GRAVITY) { - // For gravity, always move the avatar by the amount driven by gravity, so that the collision - // routines will detect it and collide every frame when pulled by gravity to a surface - // - const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f; - if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) { - _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); - } - } - - if (_isCollisionsOn) { - Camera* myCamera = Application::getInstance()->getCamera(); - - if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON) { - _collisionRadius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f)); - _collisionRadius *= COLLISION_RADIUS_SCALAR; - } else { - _collisionRadius = _height * .125f; - } - - updateCollisionWithEnvironment(deltaTime); - updateCollisionWithVoxels(deltaTime); - updateAvatarCollisions(deltaTime); - } - } // update body balls updateBodyBalls(deltaTime); @@ -678,93 +373,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer updateCollisionWithSphere(_TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime); } - - if (isMyAvatar()) { - - // add thrust to velocity - _velocity += _thrust * deltaTime; - - // update body yaw by body yaw delta - orientation = orientation * glm::quat(glm::radians( - glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); - // decay body rotation momentum - - const float BODY_SPIN_FRICTION = 7.5f; - float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime; - if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; } - _bodyPitchDelta *= bodySpinMomentum; - _bodyYawDelta *= bodySpinMomentum; - _bodyRollDelta *= bodySpinMomentum; - - float MINIMUM_ROTATION_RATE = 2.0f; - if (fabs(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { _bodyYawDelta = 0.f; } - if (fabs(_bodyRollDelta) < MINIMUM_ROTATION_RATE) { _bodyRollDelta = 0.f; } - if (fabs(_bodyPitchDelta) < MINIMUM_ROTATION_RATE) { _bodyPitchDelta = 0.f; } - - const float MAX_STATIC_FRICTION_VELOCITY = 0.5f; - const float STATIC_FRICTION_STRENGTH = _scale * 20.f; - applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_VELOCITY, STATIC_FRICTION_STRENGTH); - - const float LINEAR_DAMPING_STRENGTH = 1.0f; - const float SPEED_BRAKE_POWER = _scale * 10.0f; - const float SQUARED_DAMPING_STRENGTH = 0.2f; - if (_speedBrakes) { - applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH * SPEED_BRAKE_POWER, SQUARED_DAMPING_STRENGTH * SPEED_BRAKE_POWER); - } else { - applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH, SQUARED_DAMPING_STRENGTH); - } - - //pitch and roll the body as a function of forward speed and turning delta - const float BODY_PITCH_WHILE_WALKING = -20.0; - const float BODY_ROLL_WHILE_TURNING = 0.2; - float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity); - orientation = orientation * glm::quat(glm::radians(glm::vec3( - BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f, - BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta))); - - // these forces keep the body upright... - const float BODY_UPRIGHT_FORCE = _scale * 10.0; - float tiltDecay = BODY_UPRIGHT_FORCE * deltaTime; - if (tiltDecay > 1.0f) {tiltDecay = 1.0f;} - - // update the euler angles - setOrientation(orientation); - - //the following will be used to make the avatar upright no matter what gravity is - setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation); - - // Compute instantaneous acceleration - float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; - const float ACCELERATION_PITCH_DECAY = 0.4f; - const float ACCELERATION_YAW_DECAY = 0.4f; - const float ACCELERATION_PULL_THRESHOLD = 0.2f; - const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; - const int OCULUS_YAW_OFFSET_THRESHOLD = 10; - - // Decay HeadPitch as a function of acceleration, so that you look straight ahead when - // you start moving, but don't do this with an HMD like the Oculus. - if (!OculusManager::isConnected()) { - if (forwardAcceleration > ACCELERATION_PULL_THRESHOLD) { - _head.setPitch(_head.getPitch() * (1.f - forwardAcceleration * ACCELERATION_PITCH_DECAY * deltaTime)); - _head.setYaw(_head.getYaw() * (1.f - forwardAcceleration * ACCELERATION_YAW_DECAY * deltaTime)); - } - } else if (fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD - && fabs(_head.getYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { - // if we're wearing the oculus - // and this acceleration is above the pull threshold - // and the head yaw if off the body by more than OCULUS_YAW_OFFSET_THRESHOLD - - // match the body yaw to the oculus yaw - _bodyYaw = getAbsoluteHeadYaw(); - - // set the head yaw to zero for this draw - _head.setYaw(0); - - // correct the oculus yaw offset - OculusManager::updateYawOffset(); - } - } - //apply the head lean values to the ball positions... if (USING_HEAD_LEAN) { if (fabs(_head.getLeanSideways() + _head.getLeanForward()) > 0.0f) { @@ -795,11 +403,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); _head.setScale(_scale); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); - _head.simulate(deltaTime, isMyAvatar(), gyroCameraSensitivity); - _hand.simulate(deltaTime, isMyAvatar()); - - - + _head.simulate(deltaTime, false, gyroCameraSensitivity); + _hand.simulate(deltaTime, false); // use speed and angular velocity to determine walking vs. standing if (_speed + fabs(_bodyYawDelta) > 0.2) { @@ -816,35 +421,11 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer } -void Avatar::checkForMouseRayTouching() { - - for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - - glm::vec3 directionToBodySphere = glm::normalize(_bodyBall[b].position - _mouseRayOrigin); - float dot = glm::dot(directionToBodySphere, _mouseRayDirection); - - float range = _bodyBall[b].radius * MOUSE_RAY_TOUCH_RANGE; - - if (dot > (1.0f - range)) { - _bodyBall[b].touchForce = (dot - (1.0f - range)) / range; - } else { - _bodyBall[b].touchForce = 0.0; - } - } -} - void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction ) { _mouseRayOrigin = origin; _mouseRayDirection = direction; } -void Avatar::setOrientation(const glm::quat& orientation) { - glm::vec3 eulerAngles = safeEulerAngles(orientation); - _bodyPitch = eulerAngles.x; - _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; -} - void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovement) { glm::quat orientation = getOrientation(); @@ -863,127 +444,11 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement; } - if (isMyAvatar()) { - _avatarTouch.setMyBodyPosition(_position); - _avatarTouch.setMyOrientation(orientation); - - float closestDistance = std::numeric_limits::max(); - - _interactingOther = NULL; - - //loop through all the other avatars for potential interactions... - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - Avatar *otherAvatar = (Avatar *)node->getLinkedData(); - - // test whether shoulders are close enough to allow for reaching to touch hands - glm::vec3 v(_position - otherAvatar->_position); - float distance = glm::length(v); - if (distance < closestDistance) { - closestDistance = distance; - - if (distance < _scale * PERIPERSONAL_RADIUS) { - _interactingOther = otherAvatar; - } - } - } - } - - if (_interactingOther) { - - _avatarTouch.setHasInteractingOther(true); - _avatarTouch.setYourBodyPosition(_interactingOther->_position); - _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); - _avatarTouch.setYourOrientation (_interactingOther->getOrientation()); - _avatarTouch.setYourHandState (_interactingOther->_handState); - - //if hand-holding is initiated by either avatar, turn on hand-holding... - if (_avatarTouch.getHandsCloseEnoughToGrasp()) { - if ((_handState == HAND_STATE_GRASPING ) || (_interactingOther->_handState == HAND_STATE_GRASPING)) { - if (!_avatarTouch.getHoldingHands()) - { - _avatarTouch.setHoldingHands(true); - } - } - } - - glm::vec3 vectorFromMyHandToYourHand - ( - _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - ); - - float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand); - - /* - // if my arm can no longer reach the other hand, turn off hand-holding - if (!_avatarTouch.getAbleToReachOtherAvatar()) { - _avatarTouch.setHoldingHands(false); - } - if (distanceBetweenOurHands > _maxArmLength) { - _avatarTouch.setHoldingHands(false); - } - */ - - // if neither of us are grasping, turn off hand-holding - if ((_handState != HAND_STATE_GRASPING ) && (_interactingOther->_handState != HAND_STATE_GRASPING)) { - _avatarTouch.setHoldingHands(false); - } - - //if holding hands, apply the appropriate forces - if (_avatarTouch.getHoldingHands()) { - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += - ( - _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - ) * 0.5f; - - if (distanceBetweenOurHands > 0.3) { - float force = 10.0f * deltaTime; - if (force > 1.0f) {force = 1.0f;} - _velocity += vectorFromMyHandToYourHand * force; - } - } - } else { - _avatarTouch.setHasInteractingOther(false); - } - - // If there's a leap-interaction hand visible, use that as the endpoint - glm::vec3 rightMostHand; - bool anyHandsFound = false; - for (size_t i = 0; i < getHand().getPalms().size(); ++i) { - PalmData& palm = getHand().getPalms()[i]; - if (palm.isActive()) { - if (!anyHandsFound - || palm.getRawPosition().x > rightMostHand.x) { - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition(); - rightMostHand = palm.getRawPosition(); - } - anyHandsFound = true; - } - } - }//if (_isMine) - //constrain right arm length and re-adjust elbow position as it bends // NOTE - the following must be called on all avatars - not just _isMine if (enableHandMovement) { updateArmIKAndConstraints(deltaTime); } - - //Set right hand position and state to be transmitted, and also tell AvatarTouch about it - if (isMyAvatar()) { - setHandPosition(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); - - if (_mousePressed) { - _handState = HAND_STATE_GRASPING; - } else { - _handState = HAND_STATE_NULL; - } - - _avatarTouch.setMyHandState(_handState); - _avatarTouch.setMyHandPosition(_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); - } } void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float deltaTime) { @@ -1012,195 +477,13 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } -void Avatar::updateCollisionWithEnvironment(float deltaTime) { - glm::vec3 up = getBodyUpDirection(); - float radius = _collisionRadius; - const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; - const float ENVIRONMENT_SURFACE_DAMPING = 0.01; - const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; - glm::vec3 penetration; - if (Application::getInstance()->getEnvironment()->findCapsulePenetration( - _position - up * (_pelvisFloatingHeight - radius), - _position + up * (_height - _pelvisFloatingHeight + radius), radius, penetration)) { - _lastCollisionPosition = _position; - updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); - applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); - } -} - - -void Avatar::updateCollisionWithVoxels(float deltaTime) { - float radius = _collisionRadius; - const float VOXEL_ELASTICITY = 1.4f; - const float VOXEL_DAMPING = 0.0; - const float VOXEL_COLLISION_FREQUENCY = 0.5f; - glm::vec3 penetration; - if (Application::getInstance()->getVoxels()->findCapsulePenetration( - _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), - _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight + radius, 0.0f), radius, penetration)) { - _lastCollisionPosition = _position; - updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); - applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - } -} - -void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { - // - // Update the avatar in response to a hard collision. Position will be reset exactly - // to outside the colliding surface. Velocity will be modified according to elasticity. - // - // if elasticity = 1.0, collision is inelastic. - // if elasticity > 1.0, collision is elastic. - // - _position -= penetration; - static float HALTING_VELOCITY = 0.2f; - // cancel out the velocity component in the direction of penetration - float penetrationLength = glm::length(penetration); - if (penetrationLength > EPSILON) { - _elapsedTimeSinceCollision = 0.0f; - glm::vec3 direction = penetration / penetrationLength; - _velocity -= glm::dot(_velocity, direction) * direction * elasticity; - _velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f); - if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.f)) { - // If moving really slowly after a collision, and not applying forces, stop altogether - _velocity *= 0.f; - } - } -} - -void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { - // consider whether to have the collision make a sound - const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; - const float COLLISION_LOUDNESS = 1.f; - const float DURATION_SCALING = 0.004f; - const float NOISE_SCALING = 0.1f; - glm::vec3 velocity = _velocity; - glm::vec3 gravity = getGravity(); - - if (glm::length(gravity) > EPSILON) { - // If gravity is on, remove the effect of gravity on velocity for this - // frame, so that we are not constantly colliding with the surface - velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); - } - float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); - float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; - - if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { - // Volume is proportional to collision velocity - // Base frequency is modified upward by the angle of the collision - // Noise is a function of the angle of collision - // Duration of the sound is a function of both base frequency and velocity of impact - Application::getInstance()->getAudio()->startCollisionSound( - fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), - frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), - fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), - 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); - } -} - -void Avatar::updateAvatarCollisions(float deltaTime) { - - // Reset detector for nearest avatar - _distanceToNearestAvatar = std::numeric_limits::max(); - - // loop through all the other avatars for potential interactions... - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - Avatar *otherAvatar = (Avatar *)node->getLinkedData(); - - // 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) { - // apply forces from collision - applyCollisionWithOtherAvatar(otherAvatar, deltaTime); - } - // test other avatar hand position for proximity - glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position); - v -= otherAvatar->getPosition(); - - float distance = glm::length(v); - if (distance < _distanceToNearestAvatar) { - _distanceToNearestAvatar = distance; - } - } - } -} - -// detect collisions with other avatars and respond -void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) { - - glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); - - // loop through the body balls of each avatar to check for every possible collision - for (int b = 1; b < NUM_AVATAR_BODY_BALLS; b++) { - if (_bodyBall[b].isCollidable) { - - for (int o = b+1; o < NUM_AVATAR_BODY_BALLS; o++) { - if (otherAvatar->_bodyBall[o].isCollidable) { - - glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); - float distanceBetweenBalls = glm::length(vectorBetweenBalls); - - if (distanceBetweenBalls > 0.0) { // to avoid divide by zero - float combinedRadius = _bodyBall[b].radius + otherAvatar->_bodyBall[o].radius; - - // check for collision - if (distanceBetweenBalls < combinedRadius * COLLISION_RADIUS_SCALAR) { - glm::vec3 directionVector = vectorBetweenBalls / distanceBetweenBalls; - - // push balls away from each other and apply friction - float penetration = 1.0f - (distanceBetweenBalls / (combinedRadius * COLLISION_RADIUS_SCALAR)); - - glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * penetration * deltaTime; - bodyPushForce += directionVector * COLLISION_BODY_FORCE * penetration * deltaTime; - - _bodyBall[b].velocity += ballPushForce; - otherAvatar->_bodyBall[o].velocity -= ballPushForce; - - }// check for collision - } // to avoid divide by zero - } // o loop - } // collidable - } // b loop - } // collidable - - // apply force on the whole body - _velocity += bodyPushForce; -} - - static TextRenderer* textRenderer() { static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); return renderer; } -void Avatar::setGravity(glm::vec3 gravity) { - _gravity = gravity; - _head.setGravity(_gravity); - - // use the gravity to determine the new world up direction, if possible - float gravityLength = glm::length(gravity); - if (gravityLength > EPSILON) { - _worldUpDirection = _gravity / -gravityLength; - } else { - _worldUpDirection = DEFAULT_UP_DIRECTION; - } -} - void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { - if (isMyAvatar() && usingBigSphereCollisionTest) { - // show TEST big sphere - 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); - glPopMatrix(); - } - if (Application::getInstance()->getAvatar()->getHand().isRaveGloveActive()) { _hand.setRaveLights(RAVE_LIGHTS_AVATAR); } @@ -1212,25 +495,18 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { renderBody(lookingInMirror, renderAvatarBalls); // render sphere when far away - if (!isMyAvatar()) { - const float MAX_ANGLE = 10.f; - glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition(); - glm::vec3 delta = _height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f; - float angle = abs(angleBetween(toTarget + delta, toTarget - delta)); + const float MAX_ANGLE = 10.f; + glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition(); + glm::vec3 delta = _height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f; + float angle = abs(angleBetween(toTarget + delta, toTarget - delta)); - if (angle < MAX_ANGLE) { - glColor4f(0.5f, 0.8f, 0.8f, 1.f - angle / MAX_ANGLE); - glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); - glScalef(_height / 2.f, _height / 2.f, _height / 2.f); - glutSolidSphere(1.2f + _head.getAverageLoudness() * .0005f, 20, 20); - glPopMatrix(); - } - } - - // if this is my avatar, then render my interactions with the other avatar - if (isMyAvatar()) { - _avatarTouch.render(Application::getInstance()->getCamera()->getPosition()); + if (angle < MAX_ANGLE) { + glColor4f(0.5f, 0.8f, 0.8f, 1.f - angle / MAX_ANGLE); + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.z); + glScalef(_height / 2.f, _height / 2.f, _height / 2.f); + glutSolidSphere(1.2f + _head.getAverageLoudness() * .0005f, 20, 20); + glPopMatrix(); } // Render the balls @@ -1283,21 +559,6 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { } } -void Avatar::renderScreenTint(ScreenTintLayer layer, Camera& whichCamera) { - - if (layer == SCREEN_TINT_BEFORE_AVATARS) { - if (_hand.isRaveGloveActive()) { - _hand.renderRaveGloveStage(); - } - } - else if (layer == SCREEN_TINT_BEFORE_AVATARS) { - if (_hand.isRaveGloveActive()) { - // Restore the world lighting - Application::getInstance()->setupWorldLight(whichCamera); - } - } -} - void Avatar::resetBodyBalls() { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { @@ -1443,18 +704,12 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { } float Avatar::getBallRenderAlpha(int ball, bool lookingInMirror) const { - const float RENDER_OPAQUE_OUTSIDE = _scale * 0.25f; // render opaque if greater than this distance - const float DO_NOT_RENDER_INSIDE = _scale * 0.25f; // do not render if less than this distance - float distanceToCamera = glm::length(Application::getInstance()->getCamera()->getPosition() - _bodyBall[ball].position); - return (lookingInMirror || !isMyAvatar()) ? 1.0f : glm::clamp( - (distanceToCamera - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f); + return 1.0f; } void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { - if (isMyAvatar() && Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON) { - // Dont display body - } else if (_head.getFace().isFullFrame()) { + if (_head.getFace().isFullFrame()) { // Render the full-frame video float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror); if (alpha > 0.0f) { @@ -1479,18 +734,9 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { } } else if (alpha > 0.0f) { // Render the body ball sphere - if (!isMyAvatar() || b == BODY_BALL_RIGHT_ELBOW - || b == BODY_BALL_RIGHT_WRIST - || b == BODY_BALL_RIGHT_FINGERTIPS ) { - glColor3f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, - SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, - SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f); - } else { - glColor4f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, - SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, - SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f, - alpha); - } + glColor3f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, + SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, + SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f); if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE )) { @@ -1632,9 +878,9 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, glEnd(); } -void Avatar::setNewScale(const float scale) { - _newScale = scale; -} +// void Avatar::setNewScale(const float scale) { +// _newScale = scale; +// } void Avatar::setScale(const float scale) { _scale = scale; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 29a79047ed..80b25c52a9 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -58,6 +58,11 @@ const float BODY_BALL_RADIUS_RIGHT_KNEE = 0.025; const float BODY_BALL_RADIUS_RIGHT_HEEL = 0.025; const float BODY_BALL_RADIUS_RIGHT_TOES = 0.025; +extern const bool usingBigSphereCollisionTest; + +extern const float chatMessageScale; +extern const float chatMessageHeight; + enum AvatarBodyBallID { BODY_BALL_NULL = -1, @@ -121,85 +126,35 @@ enum ScreenTintLayer NUM_SCREEN_TINT_LAYERS }; +class MyAvatar; + class Avatar : public AvatarData { public: Avatar(Node* owningNode = NULL); ~Avatar(); void init(); - void reset(); void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity); - void updateThrust(float deltaTime, Transmitter * transmitter); void follow(Avatar* leadingAvatar); - void updateFromGyrosAndOrWebcam(bool gyroLook, - float pitchFromTouch); - void addBodyYaw(float bodyYaw) {_bodyYaw += bodyYaw;}; - void addBodyYawDelta(float bodyYawDelta) {_bodyYawDelta += bodyYawDelta;} void render(bool lookingInMirror, bool renderAvatarBalls); - void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera); //setters - void setMousePressed (bool mousePressed ) { _mousePressed = mousePressed;} - void setNoise (float mag ) { _head.noise = mag;} - void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;} - void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; }; void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);} - void setVelocity (const glm::vec3 velocity ) { _velocity = velocity; }; - void setLeanScale (float scale ) { _leanScale = scale;} - void setGravity (glm::vec3 gravity); void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction); - void setOrientation (const glm::quat& orientation); - void setNewScale (const float scale); - void setWantCollisionsOn (bool wantCollisionsOn ) { _isCollisionsOn = wantCollisionsOn; } //getters bool isInitialized () const { return _initialized;} - bool isMyAvatar () const { return _owningNode == NULL; } const Skeleton& getSkeleton () const { return _skeleton;} float getHeadYawRate () const { return _head.yawRate;} - float getBodyYaw () const { return _bodyYaw;} - 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;} - glm::vec3 getBodyRightDirection () const { return getOrientation() * IDENTITY_RIGHT; } - glm::vec3 getBodyUpDirection () const { return getOrientation() * IDENTITY_UP; } - glm::vec3 getBodyFrontDirection () const { return getOrientation() * IDENTITY_FRONT; } float getScale () const { return _scale;} - float getNewScale () const { return _newScale;} const glm::vec3& getVelocity () const { return _velocity;} - float getSpeed () const { return _speed;} - float getHeight () const { return _height;} - AvatarMode getMode () const { return _mode;} - float getLeanScale () const { return _leanScale;} - float getElapsedTimeStopped () const { return _elapsedTimeStopped;} - float getElapsedTimeMoving () const { return _elapsedTimeMoving;} - float getElapsedTimeSinceCollision() const { return _elapsedTimeSinceCollision;} - const glm::vec3& getLastCollisionPosition () const { return _lastCollisionPosition;} - float getAbsoluteHeadYaw () const; - float getAbsoluteHeadPitch () const; Head& getHead () {return _head; } Hand& getHand () {return _hand; } glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; - const glm::vec3& getMouseRayOrigin () const { return _mouseRayOrigin; } - const glm::vec3& getMouseRayDirection () const { return _mouseRayDirection; } - Avatar* getLeadingAvatar () const { return _leadingAvatar; } - glm::vec3 getGravity () const { return _gravity; } - - glm::vec3 getUprightHeadPosition() const; - glm::vec3 getUprightEyeLevelPosition() const; - glm::vec3 getEyePosition(); - - AvatarVoxelSystem* getVoxels() { return &_voxels; } - - // Set what driving keys are being pressed to control thrust levels - void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; - bool getDriveKeys(int key) { return _driveKeys[key]; }; - void jump() { _shouldJump = true; }; - // Set/Get update the thrust that will move the avatar around - void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; - glm::vec3 getThrust() { return _thrust; }; + AvatarVoxelSystem* getVoxels() { return &_voxels; } // get/set avatar data void saveData(QSettings* set); @@ -210,11 +165,9 @@ public: static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); -private: - // privatize copy constructor and assignment operator to avoid copying - Avatar(const Avatar&); - Avatar& operator= (const Avatar&); - + friend class MyAvatar; + +protected: struct AvatarBall { AvatarJointID parentJoint; // the skeletal joint that serves as a reference for determining the position @@ -230,77 +183,62 @@ private: float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; - bool _initialized; Head _head; Hand _hand; Skeleton _skeleton; bool _ballSpringsInitialized; float _TEST_bigSphereRadius; glm::vec3 _TEST_bigSpherePosition; - bool _mousePressed; - float _bodyPitchDelta; float _bodyYawDelta; - float _bodyRollDelta; glm::vec3 _movedHandOffset; - AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; + AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; AvatarMode _mode; - glm::vec3 _handHoldingPosition; glm::vec3 _velocity; glm::vec3 _thrust; - bool _shouldJump; float _speed; - float _maxArmLength; float _leanScale; - int _driveKeys[MAX_DRIVE_KEYS]; - float _pelvisStandingHeight; float _pelvisFloatingHeight; float _pelvisToHeadLength; float _scale; float _height; Balls* _balls; AvatarTouch _avatarTouch; - float _distanceToNearestAvatar; // How close is the nearest avatar? - glm::vec3 _gravity; glm::vec3 _worldUpDirection; glm::vec3 _mouseRayOrigin; glm::vec3 _mouseRayDirection; - Avatar* _interactingOther; - bool _isMouseTurningRight; - float _elapsedTimeMoving; // Timers to drive camera transitions when moving - float _elapsedTimeStopped; - float _elapsedTimeSinceCollision; - glm::vec3 _lastCollisionPosition; - bool _speedBrakes; - bool _isThrustOn; bool _isCollisionsOn; - float _collisionRadius; - Avatar* _leadingAvatar; float _stringLength; AvatarVoxelSystem _voxels; + + // protected methods... + glm::vec3 getBodyRightDirection () const { return getOrientation() * IDENTITY_RIGHT; } + glm::vec3 getBodyUpDirection () const { return getOrientation() * IDENTITY_UP; } + glm::vec3 getBodyFrontDirection () const { return getOrientation() * IDENTITY_FRONT; } + glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; + void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); + void updateBodyBalls( float deltaTime ); + void updateArmIKAndConstraints( float deltaTime ); + void setScale (const float scale); + +private: + // privatize copy constructor and assignment operator to avoid copying + Avatar(const Avatar&); + Avatar& operator= (const Avatar&); + + bool _initialized; + glm::vec3 _handHoldingPosition; + float _maxArmLength; + float _pelvisStandingHeight; // private methods... glm::vec3 calculateAverageEyePosition() { return _head.calculateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) - glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; float getBallRenderAlpha(int ball, bool lookingInMirror) const; void renderBody(bool lookingInMirror, bool renderAvatarBalls); void initializeBodyBalls(); void resetBodyBalls(); - void updateBodyBalls( float deltaTime ); - void calculateBoneLengths(); - void readSensors(); void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement); - void updateAvatarCollisions(float deltaTime); - void updateArmIKAndConstraints( float deltaTime ); - void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateCollisionWithEnvironment(float deltaTime); - void updateCollisionWithVoxels(float deltaTime); - void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); - void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); - void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); - void checkForMouseRayTouching(); - void setScale (const float scale); }; #endif diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index fc6ca4224e..dda948d92f 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -36,7 +36,7 @@ Hand::Hand(Avatar* owningAvatar) : void Hand::init() { // Different colors for my hand and others' hands - if (_owningAvatar && _owningAvatar->isMyAvatar()) { + if (_owningAvatar && _owningAvatar->getOwningNode() == NULL) { _ballColor = glm::vec3(0.0, 0.4, 0.0); } else { From de9bd9e1b824817f6616fe894b03924c5ca60527 Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Wed, 21 Aug 2013 13:38:23 -0700 Subject: [PATCH 03/12] Add MyAvatar and resolve merge conflicts. --- interface/src/avatar/MyAvatar.cpp | 1046 +++++++++++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 91 +++ 2 files changed, 1137 insertions(+) create mode 100644 interface/src/avatar/MyAvatar.cpp create mode 100644 interface/src/avatar/MyAvatar.h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp new file mode 100644 index 0000000000..82f2062a84 --- /dev/null +++ b/interface/src/avatar/MyAvatar.cpp @@ -0,0 +1,1046 @@ +// +// MyAvatar.cpp +// interface +// +// Created by Mark Peng on 8/16/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#include "MyAvatar.h" + +#include + +#include + +#include +#include +#include +#include +#include + +#include "Application.h" +#include "Physics.h" +#include "ui/TextRenderer.h" + +using namespace std; + +const bool USING_AVATAR_GRAVITY = true; +const glm::vec3 DEFAULT_UP_DIRECTION (0.0f, 1.0f, 0.0f); +const float YAW_MAG = 500.0; +const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions +const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions +const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions +const float PERIPERSONAL_RADIUS = 1.0f; +const float MOUSE_RAY_TOUCH_RANGE = 0.01f; +const bool USING_HEAD_LEAN = false; +const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; +const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; + +MyAvatar::MyAvatar(Node* owningNode) : + Avatar(owningNode), + _mousePressed(false), + _bodyPitchDelta(0.0f), + _bodyRollDelta(0.0f), + _shouldJump(false), + _gravity(0.0f, -1.0f, 0.0f), + _distanceToNearestAvatar(std::numeric_limits::max()), + _interactingOther(NULL), + _elapsedTimeMoving(0.0f), + _elapsedTimeStopped(0.0f), + _elapsedTimeSinceCollision(0.0f), + _lastCollisionPosition(0, 0, 0), + _speedBrakes(false), + _isThrustOn(false) +{ + for (int i = 0; i < MAX_DRIVE_KEYS; i++) { + _driveKeys[i] = false; + } + + _collisionRadius = _height * 0.125f; +} + +void MyAvatar::reset() { + _head.reset(); + _hand.reset(); +} + +void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity) { + + glm::quat orientation = getOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + + // Update movement timers + _elapsedTimeSinceCollision += deltaTime; + const float VELOCITY_MOVEMENT_TIMER_THRESHOLD = 0.2f; + if (glm::length(_velocity) < VELOCITY_MOVEMENT_TIMER_THRESHOLD) { + _elapsedTimeMoving = 0.f; + _elapsedTimeStopped += deltaTime; + } else { + _elapsedTimeStopped = 0.f; + _elapsedTimeMoving += deltaTime; + } + + if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) { + follow(NULL); + } + + // Ajust, scale, position and lookAt position when following an other avatar + if (_leadingAvatar && _newScale != _leadingAvatar->getScale()) { + _newScale = _leadingAvatar->getScale(); + } + + if (_scale != _newScale) { + float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _newScale; + setScale(scale); + Application::getInstance()->getCamera()->setScale(scale); + } + + // Collect thrust forces from keyboard and devices + updateThrust(deltaTime, transmitter); + + // copy velocity so we can use it later for acceleration + glm::vec3 oldVelocity = getVelocity(); + + // calculate speed + _speed = glm::length(_velocity); + + //figure out if the mouse cursor is over any body spheres... + checkForMouseRayTouching(); + + // update balls + if (_balls) { + _balls->moveOrigin(_position); + glm::vec3 lookAt = _head.getLookAtPosition(); + if (glm::length(lookAt) > EPSILON) { + _balls->moveOrigin(lookAt); + } else { + _balls->moveOrigin(_position); + } + _balls->simulate(deltaTime); + } + + // update torso rotation based on head lean + _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3( + _head.getLeanForward(), 0.0f, _head.getLeanSideways()))); + + // apply joint data (if any) to skeleton + bool enableHandMovement = true; + for (vector::iterator it = _joints.begin(); it != _joints.end(); it++) { + _skeleton.joint[it->jointID].rotation = it->rotation; + + // disable hand movement if we have joint info for the right wrist + enableHandMovement &= (it->jointID != AVATAR_JOINT_RIGHT_WRIST); + } + + // update avatar skeleton + _skeleton.update(deltaTime, getOrientation(), _position); + + //determine the lengths of the body springs now that we have updated the skeleton at least once + if (!_ballSpringsInitialized) { + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + + glm::vec3 targetPosition + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + + glm::vec3 parentTargetPosition + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + + _bodyBall[b].springLength = glm::length(targetPosition - parentTargetPosition); + } + + _ballSpringsInitialized = true; + } + + //update the movement of the hand and process handshaking with other avatars... + updateHandMovementAndTouching(deltaTime, enableHandMovement); + _avatarTouch.simulate(deltaTime); + + // apply gravity + if (USING_AVATAR_GRAVITY) { + // For gravity, always move the avatar by the amount driven by gravity, so that the collision + // routines will detect it and collide every frame when pulled by gravity to a surface + // + const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f; + if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) { + _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); + } + } + + if (_isCollisionsOn) { + Camera* myCamera = Application::getInstance()->getCamera(); + + if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON) { + _collisionRadius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f)); + _collisionRadius *= COLLISION_RADIUS_SCALAR; + } else { + _collisionRadius = _height * .125f; + } + + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); + updateAvatarCollisions(deltaTime); + } + + // update body balls + updateBodyBalls(deltaTime); + + + // test for avatar collision response with the big sphere + if (usingBigSphereCollisionTest && _isCollisionsOn) { + updateCollisionWithSphere(_TEST_bigSpherePosition, _TEST_bigSphereRadius, deltaTime); + } + + // add thrust to velocity + _velocity += _thrust * deltaTime; + + // update body yaw by body yaw delta + orientation = orientation * glm::quat(glm::radians( + glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); + // decay body rotation momentum + + const float BODY_SPIN_FRICTION = 7.5f; + float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime; + if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; } + _bodyPitchDelta *= bodySpinMomentum; + _bodyYawDelta *= bodySpinMomentum; + _bodyRollDelta *= bodySpinMomentum; + + float MINIMUM_ROTATION_RATE = 2.0f; + if (fabs(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { _bodyYawDelta = 0.f; } + if (fabs(_bodyRollDelta) < MINIMUM_ROTATION_RATE) { _bodyRollDelta = 0.f; } + if (fabs(_bodyPitchDelta) < MINIMUM_ROTATION_RATE) { _bodyPitchDelta = 0.f; } + + const float MAX_STATIC_FRICTION_VELOCITY = 0.5f; + const float STATIC_FRICTION_STRENGTH = _scale * 20.f; + applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_VELOCITY, STATIC_FRICTION_STRENGTH); + + const float LINEAR_DAMPING_STRENGTH = 1.0f; + const float SPEED_BRAKE_POWER = _scale * 10.0f; + const float SQUARED_DAMPING_STRENGTH = 0.2f; + if (_speedBrakes) { + applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH * SPEED_BRAKE_POWER, SQUARED_DAMPING_STRENGTH * SPEED_BRAKE_POWER); + } else { + applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH, SQUARED_DAMPING_STRENGTH); + } + + //pitch and roll the body as a function of forward speed and turning delta + const float BODY_PITCH_WHILE_WALKING = -20.0; + const float BODY_ROLL_WHILE_TURNING = 0.2; + float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity); + orientation = orientation * glm::quat(glm::radians(glm::vec3( + BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f, + BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta))); + + // these forces keep the body upright... + const float BODY_UPRIGHT_FORCE = _scale * 10.0; + float tiltDecay = BODY_UPRIGHT_FORCE * deltaTime; + if (tiltDecay > 1.0f) {tiltDecay = 1.0f;} + + // update the euler angles + setOrientation(orientation); + + //the following will be used to make the avatar upright no matter what gravity is + setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation); + + // Compute instantaneous acceleration + float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; + const float ACCELERATION_PITCH_DECAY = 0.4f; + const float ACCELERATION_YAW_DECAY = 0.4f; + const float ACCELERATION_PULL_THRESHOLD = 0.2f; + const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; + const int OCULUS_YAW_OFFSET_THRESHOLD = 10; + + // Decay HeadPitch as a function of acceleration, so that you look straight ahead when + // you start moving, but don't do this with an HMD like the Oculus. + if (!OculusManager::isConnected()) { + if (forwardAcceleration > ACCELERATION_PULL_THRESHOLD) { + _head.setPitch(_head.getPitch() * (1.f - forwardAcceleration * ACCELERATION_PITCH_DECAY * deltaTime)); + _head.setYaw(_head.getYaw() * (1.f - forwardAcceleration * ACCELERATION_YAW_DECAY * deltaTime)); + } + } else if (fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD + && fabs(_head.getYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { + // if we're wearing the oculus + // and this acceleration is above the pull threshold + // and the head yaw if off the body by more than OCULUS_YAW_OFFSET_THRESHOLD + + // match the body yaw to the oculus yaw + _bodyYaw = getAbsoluteHeadYaw(); + + // set the head yaw to zero for this draw + _head.setYaw(0); + + // correct the oculus yaw offset + OculusManager::updateYawOffset(); + } + + //apply the head lean values to the ball positions... + if (USING_HEAD_LEAN) { + if (fabs(_head.getLeanSideways() + _head.getLeanForward()) > 0.0f) { + glm::vec3 headLean = + right * _head.getLeanSideways() + + front * _head.getLeanForward(); + + _bodyBall[ BODY_BALL_TORSO ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_CHEST ].position += headLean * 0.4f; + _bodyBall[ BODY_BALL_NECK_BASE ].position += headLean * 0.7f; + _bodyBall[ BODY_BALL_HEAD_BASE ].position += headLean * 1.0f; + + _bodyBall[ BODY_BALL_LEFT_COLLAR ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].position += headLean * 0.2f; + _bodyBall[ BODY_BALL_LEFT_WRIST ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].position += headLean * 0.0f; + + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].position += headLean * 0.2f; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position += headLean * 0.0f; + } + } + + _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); + _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); + _head.setScale(_scale); + _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); + _head.simulate(deltaTime, true, gyroCameraSensitivity); + _hand.simulate(deltaTime, true); + + // use speed and angular velocity to determine walking vs. standing + if (_speed + fabs(_bodyYawDelta) > 0.2) { + _mode = AVATAR_MODE_WALKING; + } else { + _mode = AVATAR_MODE_INTERACTING; + } + + // update position by velocity, and subtract the change added earlier for gravity + _position += _velocity * deltaTime; + + // Zero thrust out now that we've added it to velocity in this frame + _thrust = glm::vec3(0, 0, 0); + +} + +// Update avatar head rotation with sensor data +void MyAvatar::updateFromGyrosAndOrWebcam(bool gyroLook, + float pitchFromTouch) { + SerialInterface* gyros = Application::getInstance()->getSerialHeadSensor(); + Webcam* webcam = Application::getInstance()->getWebcam(); + glm::vec3 estimatedPosition, estimatedRotation; + if (gyros->isActive()) { + estimatedRotation = gyros->getEstimatedRotation(); + + } else if (webcam->isActive()) { + estimatedRotation = webcam->getEstimatedRotation(); + + } else if (_leadingAvatar) { + _head.getFace().clearFrame(); + return; + } else { + _head.setMousePitch(pitchFromTouch); + _head.setPitch(pitchFromTouch); + _head.getFace().clearFrame(); + return; + } + _head.setMousePitch(pitchFromTouch); + + if (webcam->isActive()) { + estimatedPosition = webcam->getEstimatedPosition(); + + // apply face data + _head.getFace().setFrameFromWebcam(); + + // compute and store the joint rotations + const JointVector& joints = webcam->getEstimatedJoints(); + _joints.clear(); + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + if (joints.size() > i && joints[i].isValid) { + JointData data = { i, joints[i].rotation }; + _joints.push_back(data); + + if (i == AVATAR_JOINT_CHEST) { + // if we have a chest rotation, don't apply lean based on head + estimatedPosition = glm::vec3(); + } + } + } + } else { + _head.getFace().clearFrame(); + } + + // Set the rotation of the avatar's head (as seen by others, not affecting view frustum) + // to be scaled. Pitch is greater to emphasize nodding behavior / synchrony. + const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; + const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; + const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; + _head.setPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); + _head.setYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); + _head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); + _head.setCameraFollowsHead(gyroLook); + + // Update torso lean distance based on accelerometer data + const float TORSO_LENGTH = _scale * 0.5f; + const float MAX_LEAN = 45.0f; + _head.setLeanSideways(glm::clamp(glm::degrees(atanf(estimatedPosition.x * _leanScale / TORSO_LENGTH)), + -MAX_LEAN, MAX_LEAN)); + _head.setLeanForward(glm::clamp(glm::degrees(atanf(estimatedPosition.z * _leanScale / TORSO_LENGTH)), + -MAX_LEAN, MAX_LEAN)); +} + +static TextRenderer* textRenderer() { + static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); + return renderer; +} + +void MyAvatar::render(bool lookingInMirror, bool renderAvatarBalls) { + + if (usingBigSphereCollisionTest) { + // show TEST big sphere + 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); + glPopMatrix(); + } + + if (Application::getInstance()->getAvatar()->getHand().isRaveGloveActive()) { + _hand.setRaveLights(RAVE_LIGHTS_AVATAR); + } + + // render a simple round on the ground projected down from the avatar's position + renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), _scale * 0.1f, 0.2f); + + // render body + renderBody(lookingInMirror, renderAvatarBalls); + + // if this is my avatar, then render my interactions with the other avatar + _avatarTouch.render(Application::getInstance()->getCamera()->getPosition()); + + // Render the balls + if (_balls) { + glPushMatrix(); + _balls->render(); + glPopMatrix(); + } + + if (!_chatMessage.empty()) { + int width = 0; + int lastWidth; + for (string::iterator it = _chatMessage.begin(); it != _chatMessage.end(); it++) { + width += (lastWidth = textRenderer()->computeWidth(*it)); + } + glPushMatrix(); + + glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight * _scale; + glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); + glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); + glm::vec3 chatAxis = glm::axis(chatRotation); + glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z); + + + glColor3f(0, 0.8, 0); + glRotatef(180, 0, 1, 0); + glRotatef(180, 0, 0, 1); + glScalef(_scale * chatMessageScale, _scale * chatMessageScale, 1.0f); + + glDisable(GL_LIGHTING); + glDepthMask(false); + if (_keyState == NO_KEY_DOWN) { + textRenderer()->draw(-width / 2.0f, 0, _chatMessage.c_str()); + + } else { + // rather than using substr and allocating a new string, just replace the last + // character with a null, then restore it + int lastIndex = _chatMessage.size() - 1; + char lastChar = _chatMessage[lastIndex]; + _chatMessage[lastIndex] = '\0'; + textRenderer()->draw(-width / 2.0f, 0, _chatMessage.c_str()); + _chatMessage[lastIndex] = lastChar; + glColor3f(0, 1, 0); + textRenderer()->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex); + } + glEnable(GL_LIGHTING); + glDepthMask(true); + + glPopMatrix(); + } +} + +void MyAvatar::renderScreenTint(ScreenTintLayer layer, Camera& whichCamera) { + + if (layer == SCREEN_TINT_BEFORE_AVATARS) { + if (_hand.isRaveGloveActive()) { + _hand.renderRaveGloveStage(); + } + } + else if (layer == SCREEN_TINT_BEFORE_AVATARS) { + if (_hand.isRaveGloveActive()) { + // Restore the world lighting + Application::getInstance()->setupWorldLight(whichCamera); + } + } +} + +float MyAvatar::getAbsoluteHeadYaw() const { + return glm::yaw(_head.getOrientation()); +} + +glm::vec3 MyAvatar::getUprightHeadPosition() const { + return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, _pelvisToHeadLength, 0.0f); +} + +glm::vec3 MyAvatar::getUprightEyeLevelPosition() const { + const float EYE_UP_OFFSET = 0.36f; + glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; + return _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET + glm::vec3(0.0f, _pelvisToHeadLength, 0.0f); +} + +float MyAvatar::getBallRenderAlpha(int ball, bool lookingInMirror) const { + const float RENDER_OPAQUE_OUTSIDE = _scale * 0.25f; // render opaque if greater than this distance + const float DO_NOT_RENDER_INSIDE = _scale * 0.25f; // do not render if less than this distance + float distanceToCamera = glm::length(Application::getInstance()->getCamera()->getPosition() - _bodyBall[ball].position); + return (lookingInMirror) ? 1.0f : glm::clamp( + (distanceToCamera - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f); +} + +void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { + + if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON) { + // Dont display body + } else if (_head.getFace().isFullFrame()) { + // Render the full-frame video + float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror); + if (alpha > 0.0f) { + _head.getFace().render(1.0f); + } + } else if (renderAvatarBalls || !_voxels.getVoxelURL().isValid()) { + // Render the body as balls and cones + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + float alpha = getBallRenderAlpha(b, lookingInMirror); + + // When we have leap hands, hide part of the arms. + if (_hand.getNumPalms() > 0) { + if (b == BODY_BALL_LEFT_FINGERTIPS + || b == BODY_BALL_RIGHT_FINGERTIPS) { + continue; + } + } + // Always render other people, and render myself when beyond threshold distance + if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special + if (alpha > 0.0f) { + _head.render(alpha); + } + } else if (alpha > 0.0f) { + // Render the body ball sphere + if (b == BODY_BALL_RIGHT_ELBOW + || b == BODY_BALL_RIGHT_WRIST + || b == BODY_BALL_RIGHT_FINGERTIPS ) { + glColor3f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, + SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, + SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f); + } else { + glColor4f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, + SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, + SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f, + alpha); + } + + if ((b != BODY_BALL_HEAD_TOP ) + && (b != BODY_BALL_HEAD_BASE )) { + glPushMatrix(); + glTranslatef(_bodyBall[b].position.x, _bodyBall[b].position.y, _bodyBall[b].position.z); + glutSolidSphere(_bodyBall[b].radius, 20.0f, 20.0f); + glPopMatrix(); + } + + // Render the cone connecting this ball to its parent + if (_bodyBall[b].parentBall != BODY_BALL_NULL) { + if ((b != BODY_BALL_HEAD_TOP ) + && (b != BODY_BALL_HEAD_BASE ) + && (b != BODY_BALL_PELVIS ) + && (b != BODY_BALL_TORSO ) + && (b != BODY_BALL_CHEST ) + && (b != BODY_BALL_LEFT_COLLAR ) + && (b != BODY_BALL_LEFT_SHOULDER ) + && (b != BODY_BALL_RIGHT_COLLAR ) + && (b != BODY_BALL_RIGHT_SHOULDER)) { + glColor3fv(DARK_SKIN_COLOR); + + float r1 = _bodyBall[_bodyBall[b].parentBall ].radius * 0.8; + float r2 = _bodyBall[b].radius * 0.8; + if (b == BODY_BALL_HEAD_BASE) { + r1 *= 0.5f; + } + renderJointConnectingCone + ( + _bodyBall[_bodyBall[b].parentBall].position, + _bodyBall[b].position, r2, r2 + ); + } + } + } + } + } else { + // Render the body's voxels + float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror); + if (alpha > 0.0f) { + _voxels.render(false); + } + } + _hand.render(lookingInMirror); +} + +void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { + // + // Gather thrust information from keyboard and sensors to apply to avatar motion + // + glm::quat orientation = getHead().getCameraOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + + const float THRUST_MAG_UP = 800.0f; + const float THRUST_MAG_DOWN = 300.f; + const float THRUST_MAG_FWD = 500.f; + const float THRUST_MAG_BACK = 300.f; + const float THRUST_MAG_LATERAL = 250.f; + const float THRUST_JUMP = 120.f; + + // Add Thrusts from keyboard + if (_driveKeys[FWD ]) {_thrust += _scale * THRUST_MAG_FWD * deltaTime * front;} + if (_driveKeys[BACK ]) {_thrust -= _scale * THRUST_MAG_BACK * deltaTime * front;} + if (_driveKeys[RIGHT ]) {_thrust += _scale * THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[LEFT ]) {_thrust -= _scale * THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[UP ]) {_thrust += _scale * THRUST_MAG_UP * deltaTime * up;} + if (_driveKeys[DOWN ]) {_thrust -= _scale * THRUST_MAG_DOWN * deltaTime * up;} + if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} + if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} + + // Add one time jumping force if requested + if (_shouldJump) { + _thrust += _scale * THRUST_JUMP * up; + _shouldJump = false; + } + + + // Add thrusts from leading avatar + const float FOLLOWING_RATE = 0.02f; + const float MIN_YAW = 5.0f; + const float MIN_PITCH = 1.0f; + const float PITCH_RATE = 0.1f; + const float MIN_YAW_BEFORE_PITCH = 30.0f; + + if (_leadingAvatar != NULL) { + glm::vec3 toTarget = _leadingAvatar->getPosition() - _position; + + if (glm::length(_position - _leadingAvatar->getPosition()) > _scale * _stringLength) { + _position += toTarget * FOLLOWING_RATE; + } else { + toTarget = _leadingAvatar->getHead().getLookAtPosition() - _head.getPosition(); + } + toTarget = glm::vec3(glm::dot(right, toTarget), + glm::dot(up , toTarget), + glm::dot(front, toTarget)); + + float yawAngle = angleBetween(-IDENTITY_FRONT, glm::vec3(toTarget.x, 0.f, toTarget.z)); + if (glm::abs(yawAngle) > MIN_YAW){ + if (IDENTITY_RIGHT.x * toTarget.x + IDENTITY_RIGHT.y * toTarget.y + IDENTITY_RIGHT.z * toTarget.z > 0) { + _bodyYawDelta -= yawAngle; + } else { + _bodyYawDelta += yawAngle; + } + } + + float pitchAngle = glm::abs(90.0f - angleBetween(IDENTITY_UP, toTarget)); + if (glm::abs(pitchAngle) > MIN_PITCH && yawAngle < MIN_YAW_BEFORE_PITCH){ + if (IDENTITY_UP.x * toTarget.x + IDENTITY_UP.y * toTarget.y + IDENTITY_UP.z * toTarget.z > 0) { + _head.setMousePitch(_head.getMousePitch() + PITCH_RATE * pitchAngle); + } else { + _head.setMousePitch(_head.getMousePitch() - PITCH_RATE * pitchAngle); + } + _head.setPitch(_head.getMousePitch()); + } + } + + + // Add thrusts from Transmitter + if (transmitter) { + transmitter->checkForLostTransmitter(); + glm::vec3 rotation = transmitter->getEstimatedRotation(); + const float TRANSMITTER_MIN_RATE = 1.f; + const float TRANSMITTER_MIN_YAW_RATE = 4.f; + const float TRANSMITTER_LATERAL_FORCE_SCALE = 5.f; + const float TRANSMITTER_FWD_FORCE_SCALE = 25.f; + const float TRANSMITTER_UP_FORCE_SCALE = 100.f; + const float TRANSMITTER_YAW_SCALE = 10.0f; + const float TRANSMITTER_LIFT_SCALE = 3.f; + const float TOUCH_POSITION_RANGE_HALF = 32767.f; + if (fabs(rotation.z) > TRANSMITTER_MIN_RATE) { + _thrust += rotation.z * TRANSMITTER_LATERAL_FORCE_SCALE * deltaTime * right; + } + if (fabs(rotation.x) > TRANSMITTER_MIN_RATE) { + _thrust += -rotation.x * TRANSMITTER_FWD_FORCE_SCALE * deltaTime * front; + } + if (fabs(rotation.y) > TRANSMITTER_MIN_YAW_RATE) { + _bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime; + } + if (transmitter->getTouchState()->state == 'D') { + _thrust += TRANSMITTER_UP_FORCE_SCALE * + (float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF * + TRANSMITTER_LIFT_SCALE * + deltaTime * + up; + } + } + + // Update speed brake status + const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f; + if ((glm::length(_thrust) == 0.0f) && _isThrustOn && (glm::length(_velocity) > MIN_SPEED_BRAKE_VELOCITY)) { + _speedBrakes = true; + } + + if (_speedBrakes && (glm::length(_velocity) < MIN_SPEED_BRAKE_VELOCITY)) { + _speedBrakes = false; + } + _isThrustOn = (glm::length(_thrust) > EPSILON); +} + +void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovement) { + + glm::quat orientation = getOrientation(); + + // reset hand and arm positions according to hand movement + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; + + if (enableHandMovement) { + glm::vec3 transformedHandMovement = + right * _movedHandOffset.x * 2.0f + + up * -_movedHandOffset.y * 2.0f + + front * -_movedHandOffset.y * 2.0f; + + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement; + } + + _avatarTouch.setMyBodyPosition(_position); + _avatarTouch.setMyOrientation(orientation); + + float closestDistance = std::numeric_limits::max(); + + _interactingOther = NULL; + + //loop through all the other avatars for potential interactions... + NodeList* nodeList = NodeList::getInstance(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { + Avatar *otherAvatar = (Avatar *)node->getLinkedData(); + + // test whether shoulders are close enough to allow for reaching to touch hands + glm::vec3 v(_position - otherAvatar->_position); + float distance = glm::length(v); + if (distance < closestDistance) { + closestDistance = distance; + + if (distance < _scale * PERIPERSONAL_RADIUS) { + _interactingOther = otherAvatar; + } + } + } + } + + if (_interactingOther) { + + _avatarTouch.setHasInteractingOther(true); + _avatarTouch.setYourBodyPosition(_interactingOther->_position); + _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); + _avatarTouch.setYourOrientation (_interactingOther->getOrientation()); + _avatarTouch.setYourHandState (_interactingOther->_handState); + + //if hand-holding is initiated by either avatar, turn on hand-holding... + if (_avatarTouch.getHandsCloseEnoughToGrasp()) { + if ((_handState == HAND_STATE_GRASPING ) || (_interactingOther->_handState == HAND_STATE_GRASPING)) { + if (!_avatarTouch.getHoldingHands()) + { + _avatarTouch.setHoldingHands(true); + } + } + } + + glm::vec3 vectorFromMyHandToYourHand + ( + _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position + ); + + float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand); + + /* + // if my arm can no longer reach the other hand, turn off hand-holding + if (!_avatarTouch.getAbleToReachOtherAvatar()) { + _avatarTouch.setHoldingHands(false); + } + if (distanceBetweenOurHands > _maxArmLength) { + _avatarTouch.setHoldingHands(false); + } + */ + + // if neither of us are grasping, turn off hand-holding + if ((_handState != HAND_STATE_GRASPING ) && (_interactingOther->_handState != HAND_STATE_GRASPING)) { + _avatarTouch.setHoldingHands(false); + } + + //if holding hands, apply the appropriate forces + if (_avatarTouch.getHoldingHands()) { + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += + ( + _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position + - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position + ) * 0.5f; + + if (distanceBetweenOurHands > 0.3) { + float force = 10.0f * deltaTime; + if (force > 1.0f) {force = 1.0f;} + _velocity += vectorFromMyHandToYourHand * force; + } + } + } else { + _avatarTouch.setHasInteractingOther(false); + } + + // If there's a leap-interaction hand visible, use that as the endpoint + glm::vec3 rightMostHand; + bool anyHandsFound = false; + for (size_t i = 0; i < getHand().getPalms().size(); ++i) { + PalmData& palm = getHand().getPalms()[i]; + if (palm.isActive()) { + if (!anyHandsFound + || palm.getRawPosition().x > rightMostHand.x) { + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition(); + rightMostHand = palm.getRawPosition(); + } + anyHandsFound = true; + } + } + + //constrain right arm length and re-adjust elbow position as it bends + // NOTE - the following must be called on all avatars - not just _isMine + if (enableHandMovement) { + updateArmIKAndConstraints(deltaTime); + } + + //Set right hand position and state to be transmitted, and also tell AvatarTouch about it + setHandPosition(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + + if (_mousePressed) { + _handState = HAND_STATE_GRASPING; + } else { + _handState = HAND_STATE_NULL; + } + + _avatarTouch.setMyHandState(_handState); + _avatarTouch.setMyHandPosition(_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); +} + +void MyAvatar::updateCollisionWithEnvironment(float deltaTime) { + glm::vec3 up = getBodyUpDirection(); + float radius = _collisionRadius; + const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; + const float ENVIRONMENT_SURFACE_DAMPING = 0.01; + const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; + glm::vec3 penetration; + if (Application::getInstance()->getEnvironment()->findCapsulePenetration( + _position - up * (_pelvisFloatingHeight - radius), + _position + up * (_height - _pelvisFloatingHeight + radius), radius, penetration)) { + _lastCollisionPosition = _position; + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } +} + + +void MyAvatar::updateCollisionWithVoxels(float deltaTime) { + float radius = _collisionRadius; + const float VOXEL_ELASTICITY = 1.4f; + const float VOXEL_DAMPING = 0.0; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; + glm::vec3 penetration; + if (Application::getInstance()->getVoxels()->findCapsulePenetration( + _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), + _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight + radius, 0.0f), radius, penetration)) { + _lastCollisionPosition = _position; + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); + applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); + } +} + +void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { + // + // Update the avatar in response to a hard collision. Position will be reset exactly + // to outside the colliding surface. Velocity will be modified according to elasticity. + // + // if elasticity = 1.0, collision is inelastic. + // if elasticity > 1.0, collision is elastic. + // + _position -= penetration; + static float HALTING_VELOCITY = 0.2f; + // cancel out the velocity component in the direction of penetration + float penetrationLength = glm::length(penetration); + if (penetrationLength > EPSILON) { + _elapsedTimeSinceCollision = 0.0f; + glm::vec3 direction = penetration / penetrationLength; + _velocity -= glm::dot(_velocity, direction) * direction * elasticity; + _velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f); + if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.f)) { + // If moving really slowly after a collision, and not applying forces, stop altogether + _velocity *= 0.f; + } + } +} + +void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { + // consider whether to have the collision make a sound + const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float COLLISION_LOUDNESS = 1.f; + const float DURATION_SCALING = 0.004f; + const float NOISE_SCALING = 0.1f; + glm::vec3 velocity = _velocity; + glm::vec3 gravity = getGravity(); + + if (glm::length(gravity) > EPSILON) { + // If gravity is on, remove the effect of gravity on velocity for this + // frame, so that we are not constantly colliding with the surface + velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); + } + float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; + + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + // Volume is proportional to collision velocity + // Base frequency is modified upward by the angle of the collision + // Noise is a function of the angle of collision + // Duration of the sound is a function of both base frequency and velocity of impact + Application::getInstance()->getAudio()->startCollisionSound( + fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), + frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), + fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + } +} + +void MyAvatar::updateAvatarCollisions(float deltaTime) { + + // Reset detector for nearest avatar + _distanceToNearestAvatar = std::numeric_limits::max(); + + // loop through all the other avatars for potential interactions... + NodeList* nodeList = NodeList::getInstance(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { + Avatar *otherAvatar = (Avatar *)node->getLinkedData(); + + // 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) { + // apply forces from collision + applyCollisionWithOtherAvatar(otherAvatar, deltaTime); + } + // test other avatar hand position for proximity + glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position); + v -= otherAvatar->getPosition(); + + float distance = glm::length(v); + if (distance < _distanceToNearestAvatar) { + _distanceToNearestAvatar = distance; + } + } + } +} + +// detect collisions with other avatars and respond +void MyAvatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) { + + glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); + + // loop through the body balls of each avatar to check for every possible collision + for (int b = 1; b < NUM_AVATAR_BODY_BALLS; b++) { + if (_bodyBall[b].isCollidable) { + + for (int o = b+1; o < NUM_AVATAR_BODY_BALLS; o++) { + if (otherAvatar->_bodyBall[o].isCollidable) { + + glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); + float distanceBetweenBalls = glm::length(vectorBetweenBalls); + + if (distanceBetweenBalls > 0.0) { // to avoid divide by zero + float combinedRadius = _bodyBall[b].radius + otherAvatar->_bodyBall[o].radius; + + // check for collision + if (distanceBetweenBalls < combinedRadius * COLLISION_RADIUS_SCALAR) { + glm::vec3 directionVector = vectorBetweenBalls / distanceBetweenBalls; + + // push balls away from each other and apply friction + float penetration = 1.0f - (distanceBetweenBalls / (combinedRadius * COLLISION_RADIUS_SCALAR)); + + glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * penetration * deltaTime; + bodyPushForce += directionVector * COLLISION_BODY_FORCE * penetration * deltaTime; + + _bodyBall[b].velocity += ballPushForce; + otherAvatar->_bodyBall[o].velocity -= ballPushForce; + + }// check for collision + } // to avoid divide by zero + } // o loop + } // collidable + } // b loop + } // collidable + + // apply force on the whole body + _velocity += bodyPushForce; +} + +void MyAvatar::setGravity(glm::vec3 gravity) { + _gravity = gravity; + _head.setGravity(_gravity); + + // use the gravity to determine the new world up direction, if possible + float gravityLength = glm::length(gravity); + if (gravityLength > EPSILON) { + _worldUpDirection = _gravity / -gravityLength; + } else { + _worldUpDirection = DEFAULT_UP_DIRECTION; + } +} + +void MyAvatar::checkForMouseRayTouching() { + + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + + glm::vec3 directionToBodySphere = glm::normalize(_bodyBall[b].position - _mouseRayOrigin); + float dot = glm::dot(directionToBodySphere, _mouseRayDirection); + + float range = _bodyBall[b].radius * MOUSE_RAY_TOUCH_RANGE; + + if (dot > (1.0f - range)) { + _bodyBall[b].touchForce = (dot - (1.0f - range)) / range; + } else { + _bodyBall[b].touchForce = 0.0; + } + } +} + +void MyAvatar::setOrientation(const glm::quat& orientation) { + glm::vec3 eulerAngles = safeEulerAngles(orientation); + _bodyPitch = eulerAngles.x; + _bodyYaw = eulerAngles.y; + _bodyRoll = eulerAngles.z; +} + +void MyAvatar::setNewScale(const float scale) { + _newScale = scale; +} \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h new file mode 100644 index 0000000000..059a10976d --- /dev/null +++ b/interface/src/avatar/MyAvatar.h @@ -0,0 +1,91 @@ +// +// MyAvatar.h +// interface +// +// Created by Mark Peng on 8/16/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__myavatar__ +#define __interface__myavatar__ + +#include "Avatar.h" + +class MyAvatar : public Avatar { +public: + MyAvatar(Node* owningNode = NULL); + + void reset(); + void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity); + void updateFromGyrosAndOrWebcam(bool gyroLook, float pitchFromTouch); + void render(bool lookingInMirror, bool renderAvatarBalls); + void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera); + + // setters + void setMousePressed (bool mousePressed ) { _mousePressed = mousePressed;} + void setNoise (float mag ) { _head.noise = mag;} + void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;} + void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; }; + void setVelocity (const glm::vec3 velocity ) { _velocity = velocity; }; + void setLeanScale (float scale ) { _leanScale = scale;} + void setGravity (glm::vec3 gravity); + void setOrientation (const glm::quat& orientation); + void setNewScale (const float scale); + void setWantCollisionsOn (bool wantCollisionsOn ) { _isCollisionsOn = wantCollisionsOn; } + + // getters + float getNewScale () const { return _newScale;} + float getSpeed () const { return _speed;} + AvatarMode getMode () const { return _mode;} + float getLeanScale () const { return _leanScale;} + float getElapsedTimeStopped () const { return _elapsedTimeStopped;} + float getElapsedTimeMoving () const { return _elapsedTimeMoving;} + float getAbsoluteHeadYaw () const; + const glm::vec3& getMouseRayOrigin () const { return _mouseRayOrigin; } + const glm::vec3& getMouseRayDirection () const { return _mouseRayDirection; } + Avatar* getLeadingAvatar () const { return _leadingAvatar; } + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; + glm::vec3 getUprightEyeLevelPosition() const; + + // Set what driving keys are being pressed to control thrust levels + void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; + bool getDriveKeys(int key) { return _driveKeys[key]; }; + void jump() { _shouldJump = true; }; + + // Set/Get update the thrust that will move the avatar around + void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + glm::vec3 getThrust() { return _thrust; }; + + private: + bool _mousePressed; + float _bodyPitchDelta; + float _bodyRollDelta; + bool _shouldJump; + int _driveKeys[MAX_DRIVE_KEYS]; + glm::vec3 _gravity; + float _distanceToNearestAvatar; // How close is the nearest avatar? + Avatar* _interactingOther; + float _elapsedTimeMoving; // Timers to drive camera transitions when moving + float _elapsedTimeStopped; + float _elapsedTimeSinceCollision; + glm::vec3 _lastCollisionPosition; + bool _speedBrakes; + bool _isThrustOn; + float _collisionRadius; + + // private methods + float getBallRenderAlpha(int ball, bool lookingInMirror) const; + void renderBody(bool lookingInMirror, bool renderAvatarBalls); + void updateThrust(float deltaTime, Transmitter * transmitter); + void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement); + void updateAvatarCollisions(float deltaTime); + void updateCollisionWithEnvironment(float deltaTime); + void updateCollisionWithVoxels(float deltaTime); + void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); + void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); + void checkForMouseRayTouching(); +}; + +#endif \ No newline at end of file From bb9af3103caf58e9eeae96f661dee230dc17a3ef Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Wed, 21 Aug 2013 13:44:01 -0700 Subject: [PATCH 04/12] Remove unused setNoise() function in MyAvatar.h that was causing build error. --- interface/src/avatar/MyAvatar.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 059a10976d..c26670a933 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -23,7 +23,6 @@ public: // setters void setMousePressed (bool mousePressed ) { _mousePressed = mousePressed;} - void setNoise (float mag ) { _head.noise = mag;} void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;} void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; }; void setVelocity (const glm::vec3 velocity ) { _velocity = velocity; }; From a6109d411b7c6e78192b5bf2ca2f972da59d25cb Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Wed, 21 Aug 2013 13:47:19 -0700 Subject: [PATCH 05/12] Remove unnecessary comments and spaces. --- interface/src/avatar/Avatar.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bdab3420ed..8ad4a87aba 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -93,14 +93,12 @@ Avatar::Avatar(Node* owningNode) : _TEST_bigSphereRadius(0.5f), _TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f), _bodyYawDelta(0.0f), - // _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), _speed(0.0f), _leanScale(0.5f), - _pelvisFloatingHeight(0.0f), _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), From 747008c2299a1e9e960f4834cfb72c44f3f8f0ae Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Wed, 21 Aug 2013 15:03:12 -0700 Subject: [PATCH 06/12] Significant updates to README to make it more useful --- README.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 75eddb474e..af8d2cf09c 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,76 @@ -interface +What is Hifi? ========= -Test platform for various render and interface tests for next-gen VR system. +High Fidelity (hifi) is an early-stage technology +lab experimenting with Virtual Worlds and VR. + +In this repository you'll find the source to many of the components in our +alpha-stage virtual world. The project embraces distributed development +and if you'd like to help, we'll pay you -- find out more at Worklist.net. +If you find a small bug and have a fix, pull requests are welcome. If you'd +like to get paid for your work, make sure you report the bug via a job on Worklist.net. + +We're hiring! We're looking for skilled developers; +send your resume to hiring@highfidelity.io + + +Building Interface +========= + +Interface is our OS X and Linux build-able +client for accessing our virtual world. CMake ----- +Hifi uses CMake to generate build files and project files +for your platform. You can download CMake at cmake.org -This project uses CMake to generate build files and project files for your platform. - -Create a build directory in the root of your checkout and then run the CMake build from there. This will keep the rest of the directory clean, and makes the gitignore a little easier to handle (since we can just ignore build). +Create a build directory in the root of your checkout and then run the +CMake build from there. This will keep the rest of the directory clean, +and makes the gitignore a little easier to handle (since we can just ignore build). mkdir build cd build - cmake .. -GXcode + cmake .. -G Xcode -Those are the commands used on OS X to run CMake from the build folder and generate XCode project files. \ No newline at end of file +Those are the commands used on OS X to run CMake from the build folder +and generate Xcode project files. If you are building on a *nix system, +you'll run something like "cmake .." (this will depend on your exact needs) + +Other dependencies & information +---- +In addition to CMake, Qt 5.1 is required to build all components. + +What can I build on? +We have successfully built on OS X 10.8, Ubuntu and a few other modern Linux distributions. +A Windows build is planned for the future, but not currently in development. + +I'm in-world, what can I do? +---- +If you don't see anything, make sure your preferences are pointing to root.highfidelity.io, +if you still have no luck it's possible our servers are simply down; if you're experiencing +a major bug, let us know by suggesting a Job on Worklist.net -- make sure to include details +about your operating system and your computer system. + +To move around in-world, use the arrow keys (and Shift + up/down to fly up or down) +or W A S D, and E or C to fly up/down. All of the other possible options and features +are available via menus in the Interface application. + + +Other components +======== + +voxel-server, animation-server, audio-mixer, avatar-mixer, domain-server, pairing-server +and space-server are architectural components that will allow you to run the full stack of +the virtual world should you choose to. + + +I'm ready, I want to run my own virtual world! +======== + +In the voxel-server/src directory you will find a README that explains +how to setup and administer a voxel-server. + +Keep in mind that, at a minimum, you must run a domain-server, voxel-server, +audio-mixer, and avatar-mixer to have a working virtual world. +Basic documentation for the other components is on its way. From d6edf958e3f6e6987cba06e70b9d8dcd7bb3f83a Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Wed, 21 Aug 2013 15:05:28 -0700 Subject: [PATCH 07/12] Removed "I'm ready" from last section header to prevent ugly wrapping --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af8d2cf09c..af433f917a 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ and space-server are architectural components that will allow you to run the ful the virtual world should you choose to. -I'm ready, I want to run my own virtual world! +I want to run my own virtual world! ======== In the voxel-server/src directory you will find a README that explains From d63bb3afaae15e2d027d35dca8fcc18b0f6c3af3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Aug 2013 15:44:57 -0700 Subject: [PATCH 08/12] Fixed glow/ambient occlusion with Oculus. --- .../resources/shaders/ambient_occlusion.frag | 3 +- interface/src/Application.cpp | 45 +++++++------------ interface/src/Application.h | 1 - interface/src/OculusManager.cpp | 1 + .../src/renderer/AmbientOcclusionEffect.cpp | 18 +++++--- interface/src/renderer/GlowEffect.cpp | 36 ++++++++++++++- interface/src/renderer/GlowEffect.h | 4 +- interface/src/renderer/RenderUtil.cpp | 10 ++--- interface/src/renderer/RenderUtil.h | 4 +- 9 files changed, 74 insertions(+), 48 deletions(-) diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag index a62d1d3a71..4e87ac3221 100644 --- a/interface/resources/shaders/ambient_occlusion.frag +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -44,7 +44,8 @@ float texCoordToViewSpaceZ(vec2 texCoord) { // given a texture coordinate, returns the 3D view space coordinate vec3 texCoordToViewSpace(vec2 texCoord) { float z = texCoordToViewSpaceZ(texCoord); - return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); + return vec3(((texCoord * 2.0 - vec2(1.0 - gl_ProjectionMatrix[2][0], 1.0)) * + (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); } void main(void) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index adc5bb1b71..b606ce47eb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -112,7 +113,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _lookatIndicatorScale(1.0f), _perfStatsOn(false), _chatEntryOn(false), - _oculusTextureID(0), _oculusProgram(0), _oculusDistortionScale(1.25), #ifndef _WIN32 @@ -370,13 +370,18 @@ void Application::paintGL() { if (OculusManager::isConnected()) { displayOculus(whichCamera); + } else { + _glowEffect.prepare(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); displaySide(whichCamera); glPopMatrix(); + _glowEffect.render(); + displayOverlay(); } @@ -400,13 +405,6 @@ void Application::resizeGL(int width, int height) { resetCamerasOnResizeGL(_viewFrustumOffsetCamera, width, height); resetCamerasOnResizeGL(_myCamera, width, height); - // resize the render texture - if (OculusManager::isConnected() && _oculusTextureID != 0) { - glBindTexture(GL_TEXTURE_2D, _oculusTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - // Tell our viewFrustum about this change, using the application camera loadViewFrustum(_myCamera, _viewFrustum); @@ -2056,6 +2054,8 @@ static const char* DISTORTION_FRAGMENT_SHADER = "}"; void Application::displayOculus(Camera& whichCamera) { + _glowEffect.prepare(); + // magic numbers ahoy! in order to avoid pulling in the Oculus utility library that calculates // the rendering parameters from the hardware stats, i just folded their calculations into // constants using the stats for the current-model hardware as contained in the SDK file @@ -2098,12 +2098,10 @@ void Application::displayOculus(Camera& whichCamera) { // restore our normal viewport glViewport(0, 0, _glWidget->width(), _glWidget->height()); - if (_oculusTextureID == 0) { - glGenTextures(1, &_oculusTextureID); - glBindTexture(GL_TEXTURE_2D, _oculusTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _glWidget->width(), _glWidget->height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + QOpenGLFramebufferObject* fbo = _glowEffect.render(true); + glBindTexture(GL_TEXTURE_2D, fbo->texture()); + + if (_oculusProgram == 0) { _oculusProgram = new ProgramObject(); _oculusProgram->addShaderFromSourceCode(QGLShader::Fragment, DISTORTION_FRAGMENT_SHADER); _oculusProgram->link(); @@ -2113,18 +2111,13 @@ void Application::displayOculus(Camera& whichCamera) { _screenCenterLocation = _oculusProgram->uniformLocation("screenCenter"); _scaleLocation = _oculusProgram->uniformLocation("scale"); _scaleInLocation = _oculusProgram->uniformLocation("scaleIn"); - _hmdWarpParamLocation = _oculusProgram->uniformLocation("hmdWarpParam"); - - } else { - glBindTexture(GL_TEXTURE_2D, _oculusTextureID); + _hmdWarpParamLocation = _oculusProgram->uniformLocation("hmdWarpParam"); } - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _glWidget->width(), _glWidget->height()); - + glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, _glWidget->width(), 0, _glWidget->height()); glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); // for reference on setting these values, see SDK file Samples/OculusRoomTiny/RenderTiny_Device.cpp @@ -2132,7 +2125,6 @@ void Application::displayOculus(Camera& whichCamera) { float aspectRatio = (_glWidget->width() * 0.5) / _glWidget->height(); glDisable(GL_BLEND); - glEnable(GL_TEXTURE_2D); _oculusProgram->bind(); _oculusProgram->setUniformValue(_textureLocation, 0); _oculusProgram->setUniformValue(_lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 @@ -2168,7 +2160,6 @@ void Application::displayOculus(Camera& whichCamera) { glEnd(); glEnable(GL_BLEND); - glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); _oculusProgram->release(); @@ -2229,9 +2220,6 @@ void Application::displaySide(Camera& whichCamera) { // Setup 3D lights (after the camera transform, so that they are positioned in world space) setupWorldLight(whichCamera); - // prepare the glow effect - _glowEffect.prepare(); - if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { if (!_stars.getFileLoaded()) { _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); @@ -2372,7 +2360,7 @@ void Application::displaySide(Camera& whichCamera) { _myAvatar.renderScreenTint(SCREEN_TINT_AFTER_AVATARS, whichCamera); // Render the world box - if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { renderWorldBox(); } @@ -2399,9 +2387,6 @@ void Application::displaySide(Camera& whichCamera) { } renderFollowIndicator(); - - // render the glow effect - _glowEffect.render(); } void Application::displayOverlay() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 51606ce75a..39fca6e532 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -301,7 +301,6 @@ private: ChatEntry _chatEntry; // chat entry field bool _chatEntryOn; // Whether to show the chat entry - GLuint _oculusTextureID; // The texture to which we render for Oculus distortion ProgramObject* _oculusProgram; // The GLSL program containing the distortion shader float _oculusDistortionScale; // Controls the Oculus field of view int _textureLocation; diff --git a/interface/src/OculusManager.cpp b/interface/src/OculusManager.cpp index 17775b9f9c..046e1684fb 100644 --- a/interface/src/OculusManager.cpp +++ b/interface/src/OculusManager.cpp @@ -46,6 +46,7 @@ void OculusManager::updateYawOffset() { } void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { + yaw = pitch = roll = 0.0f; #ifdef __APPLE__ _sensorFusion.GetOrientation().GetEulerAngles(&yaw, &pitch, &roll); diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 309816191b..2169ec00af 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -111,11 +111,17 @@ void AmbientOcclusionEffect::render() { _occlusionProgram->setUniformValue(_farLocation, farVal); _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); _occlusionProgram->setUniformValue(_rightTopLocation, right, top); - QSize size = Application::getInstance()->getGLWidget()->size(); - _occlusionProgram->setUniformValue(_noiseScaleLocation, size.width() / (float)ROTATION_WIDTH, - size.height() / (float)ROTATION_HEIGHT); + QSize widgetSize = Application::getInstance()->getGLWidget()->size(); + _occlusionProgram->setUniformValue(_noiseScaleLocation, widgetSize.width() / (float)ROTATION_WIDTH, + widgetSize.height() / (float)ROTATION_HEIGHT); - renderFullscreenQuad(); + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + const int VIEWPORT_X_INDEX = 0; + const int VIEWPORT_WIDTH_INDEX = 2; + float sMin = viewport[VIEWPORT_X_INDEX] / (float)widgetSize.width(); + float sMax = (viewport[VIEWPORT_X_INDEX] + viewport[VIEWPORT_WIDTH_INDEX]) / (float)widgetSize.width(); + renderFullscreenQuad(sMin, sMax); _occlusionProgram->release(); @@ -133,9 +139,9 @@ void AmbientOcclusionEffect::render() { glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); _blurProgram->bind(); - _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / size.width(), 1.0f / size.height()); + _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / widgetSize.width(), 1.0f / widgetSize.height()); - renderFullscreenQuad(); + renderFullscreenQuad(sMin, sMax); _blurProgram->release(); diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index 936364f8c0..e35896c975 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -78,7 +78,19 @@ void GlowEffect::end() { glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); } -void GlowEffect::render() { +static void maybeBind(QOpenGLFramebufferObject* fbo) { + if (fbo != NULL) { + fbo->bind(); + } +} + +static void maybeRelease(QOpenGLFramebufferObject* fbo) { + if (fbo != NULL) { + fbo->release(); + } +} + +QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); @@ -94,23 +106,29 @@ void GlowEffect::render() { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); + QOpenGLFramebufferObject* destFBO = toTexture ? + Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject() : NULL; if (_isEmpty) { // copy the primary to the screen if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { - QOpenGLFramebufferObject::blitFramebuffer(NULL, primaryFBO); + QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); } else { + maybeBind(destFBO); glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glColor3f(1.0f, 1.0f, 1.0f); renderFullscreenQuad(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); + maybeRelease(destFBO); } } else if (_renderMode == ADD_MODE) { + maybeBind(destFBO); _addProgram->bind(); renderFullscreenQuad(); _addProgram->release(); + maybeRelease(destFBO); } else if (_renderMode == DIFFUSE_ADD_MODE) { // diffuse into the secondary/tertiary (alternating between frames) @@ -139,9 +157,14 @@ void GlowEffect::render() { // add diffused texture to the primary glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture()); + if (toTexture) { + destFBO = oldDiffusedFBO; + } + maybeBind(destFBO); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); + maybeRelease(destFBO); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); @@ -163,9 +186,14 @@ void GlowEffect::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); + if (toTexture) { + destFBO = Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject(); + } + maybeBind(destFBO); _verticalBlurAddProgram->bind(); renderFullscreenQuad(); _verticalBlurAddProgram->release(); + maybeRelease(destFBO); } else { // _renderMode == BLUR_PERSIST_ADD_MODE // render the secondary to the tertiary with horizontal blur and persistence @@ -196,9 +224,11 @@ void GlowEffect::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tertiaryFBO->texture()); + maybeBind(destFBO); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); + maybeRelease(destFBO); } glBindTexture(GL_TEXTURE_2D, 0); @@ -214,6 +244,8 @@ void GlowEffect::render() { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); + + return destFBO; } void GlowEffect::cycleRenderMode() { diff --git a/interface/src/renderer/GlowEffect.h b/interface/src/renderer/GlowEffect.h index 73119365e8..2cf1efe9d7 100644 --- a/interface/src/renderer/GlowEffect.h +++ b/interface/src/renderer/GlowEffect.h @@ -40,7 +40,9 @@ public: void end(); /// Renders the glow effect. To be called after rendering the scene. - void render(); + /// \param toTexture whether to render to a texture, rather than to the frame buffer + /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer + QOpenGLFramebufferObject* render(bool toTexture = false); public slots: diff --git a/interface/src/renderer/RenderUtil.cpp b/interface/src/renderer/RenderUtil.cpp index 4b53fb4d12..11ec8b572c 100644 --- a/interface/src/renderer/RenderUtil.cpp +++ b/interface/src/renderer/RenderUtil.cpp @@ -8,15 +8,15 @@ #include "InterfaceConfig.h" #include "RenderUtil.h" -void renderFullscreenQuad() { +void renderFullscreenQuad(float sMin, float sMax) { glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); + glTexCoord2f(sMin, 0.0f); glVertex2f(-1.0f, -1.0f); - glTexCoord2f(1.0f, 0.0f); + glTexCoord2f(sMax, 0.0f); glVertex2f(1.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); + glTexCoord2f(sMax, 1.0f); glVertex2f(1.0f, 1.0f); - glTexCoord2f(0.0f, 1.0f); + glTexCoord2f(sMin, 1.0f); glVertex2f(-1.0f, 1.0f); glEnd(); } diff --git a/interface/src/renderer/RenderUtil.h b/interface/src/renderer/RenderUtil.h index 51e31fe260..5e7e9b5d64 100644 --- a/interface/src/renderer/RenderUtil.h +++ b/interface/src/renderer/RenderUtil.h @@ -9,7 +9,7 @@ #ifndef __interface__RenderUtil__ #define __interface__RenderUtil__ -/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (0, 0) to (1, 1). -void renderFullscreenQuad(); +/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, 0) to (sMax, 1). +void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f); #endif /* defined(__interface__RenderUtil__) */ From e252d3b2ac5ba2b535ae45bf8e96752f992e9689 Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Wed, 21 Aug 2013 16:32:06 -0700 Subject: [PATCH 09/12] Style and spacing changes in MyAvatar/Avatar classes. --- interface/src/avatar/Avatar.cpp | 460 ++++++++++++++---------------- interface/src/avatar/Avatar.h | 183 ++++++------ interface/src/avatar/MyAvatar.cpp | 190 ++++++------ interface/src/avatar/MyAvatar.h | 70 ++--- 4 files changed, 423 insertions(+), 480 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8ad4a87aba..603b5b79ad 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -27,39 +27,37 @@ using namespace std; -const bool BALLS_ON = false; -const bool USING_AVATAR_GRAVITY = true; -const glm::vec3 DEFAULT_UP_DIRECTION (0.0f, 1.0f, 0.0f); -const float YAW_MAG = 500.0; -const float MY_HAND_HOLDING_PULL = 0.2; -const float YOUR_HAND_HOLDING_PULL = 1.0; +const bool BALLS_ON = false; +const bool USING_AVATAR_GRAVITY = true; +const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f); +const float YAW_MAG = 500.0; +const float MY_HAND_HOLDING_PULL = 0.2; +const float YOUR_HAND_HOLDING_PULL = 1.0; const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f; -const float BODY_SPRING_FORCE = 300.0f; -const float BODY_SPRING_DECAY = 16.0f; -const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions -const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions -const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions -const float HEAD_ROTATION_SCALE = 0.70; -const float HEAD_ROLL_SCALE = 0.40; -const float HEAD_MAX_PITCH = 45; -const float HEAD_MIN_PITCH = -45; -const float HEAD_MAX_YAW = 85; -const float HEAD_MIN_YAW = -85; -const float PERIPERSONAL_RADIUS = 1.0f; -const float AVATAR_BRAKING_STRENGTH = 40.0f; -const float MOUSE_RAY_TOUCH_RANGE = 0.01f; -const float FLOATING_HEIGHT = 0.13f; -const bool USING_HEAD_LEAN = false; -const float LEAN_SENSITIVITY = 0.15; -const float LEAN_MAX = 0.45; -const float LEAN_AVERAGING = 10.0; -const float HEAD_RATE_MAX = 50.f; -const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; -const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; -const int NUM_BODY_CONE_SIDES = 9; - +const float BODY_SPRING_FORCE = 300.0f; +const float BODY_SPRING_DECAY = 16.0f; +const float COLLISION_RADIUS_SCALAR = 1.2; // pertains to avatar-to-avatar collisions +const float COLLISION_BALL_FORCE = 200.0; // pertains to avatar-to-avatar collisions +const float COLLISION_BODY_FORCE = 30.0; // pertains to avatar-to-avatar collisions +const float HEAD_ROTATION_SCALE = 0.70; +const float HEAD_ROLL_SCALE = 0.40; +const float HEAD_MAX_PITCH = 45; +const float HEAD_MIN_PITCH = -45; +const float HEAD_MAX_YAW = 85; +const float HEAD_MIN_YAW = -85; +const float PERIPERSONAL_RADIUS = 1.0f; +const float AVATAR_BRAKING_STRENGTH = 40.0f; +const float MOUSE_RAY_TOUCH_RANGE = 0.01f; +const float FLOATING_HEIGHT = 0.13f; +const bool USING_HEAD_LEAN = false; +const float LEAN_SENSITIVITY = 0.15; +const float LEAN_MAX = 0.45; +const float LEAN_AVERAGING = 10.0; +const float HEAD_RATE_MAX = 50.f; +const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; +const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; +const int NUM_BODY_CONE_SIDES = 9; const bool usingBigSphereCollisionTest = true; - const float chatMessageScale = 0.0015; const float chatMessageHeight = 0.20; @@ -79,10 +77,7 @@ void Avatar::sendAvatarVoxelURLMessage(const QUrl& url) { message.append((const char*)&ownerID, sizeof(ownerID)); message.append(url.toEncoded()); - Application::controlledBroadcastToNodes((unsigned char*)message.data(), - message.size(), - &NODE_TYPE_AVATAR_MIXER, - 1); + Application::controlledBroadcastToNodes((unsigned char*)message.data(), message.size(), &NODE_TYPE_AVATAR_MIXER, 1); } Avatar::Avatar(Node* owningNode) : @@ -120,12 +115,12 @@ Avatar::Avatar(Node* owningNode) : initializeBodyBalls(); - _height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius; + _height = _skeleton.getHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius + _bodyBall[BODY_BALL_HEAD_BASE].radius; - _maxArmLength = _skeleton.getArmLength(); - _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; - _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; - _pelvisToHeadLength = _skeleton.getPelvisToHeadLength(); + _maxArmLength = _skeleton.getArmLength(); + _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius; + _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius; + _pelvisToHeadLength = _skeleton.getPelvisToHeadLength(); _avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS); @@ -142,140 +137,119 @@ void Avatar::initializeBodyBalls() { _ballSpringsInitialized = false; //this gets set to true on the first update pass... for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - _bodyBall[b].parentJoint = AVATAR_JOINT_NULL; - _bodyBall[b].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[b].position = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[b].velocity = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[b].radius = 0.0; - _bodyBall[b].touchForce = 0.0; - _bodyBall[b].isCollidable = true; + _bodyBall[b].parentJoint = AVATAR_JOINT_NULL; + _bodyBall[b].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[b].position = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[b].velocity = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[b].radius = 0.0; + _bodyBall[b].touchForce = 0.0; + _bodyBall[b].isCollidable = true; _bodyBall[b].jointTightness = BODY_SPRING_DEFAULT_TIGHTNESS; } // specify the radius of each ball - _bodyBall[ BODY_BALL_PELVIS ].radius = BODY_BALL_RADIUS_PELVIS; - _bodyBall[ BODY_BALL_TORSO ].radius = BODY_BALL_RADIUS_TORSO; - _bodyBall[ BODY_BALL_CHEST ].radius = BODY_BALL_RADIUS_CHEST; - _bodyBall[ BODY_BALL_NECK_BASE ].radius = BODY_BALL_RADIUS_NECK_BASE; - _bodyBall[ BODY_BALL_HEAD_BASE ].radius = BODY_BALL_RADIUS_HEAD_BASE; - _bodyBall[ BODY_BALL_LEFT_COLLAR ].radius = BODY_BALL_RADIUS_LEFT_COLLAR; - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].radius = BODY_BALL_RADIUS_LEFT_SHOULDER; - _bodyBall[ BODY_BALL_LEFT_ELBOW ].radius = BODY_BALL_RADIUS_LEFT_ELBOW; - _bodyBall[ BODY_BALL_LEFT_WRIST ].radius = BODY_BALL_RADIUS_LEFT_WRIST; - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].radius = BODY_BALL_RADIUS_LEFT_FINGERTIPS; - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].radius = BODY_BALL_RADIUS_RIGHT_COLLAR; - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].radius = BODY_BALL_RADIUS_RIGHT_SHOULDER; - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].radius = BODY_BALL_RADIUS_RIGHT_ELBOW; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].radius = BODY_BALL_RADIUS_RIGHT_WRIST; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].radius = BODY_BALL_RADIUS_RIGHT_FINGERTIPS; - _bodyBall[ BODY_BALL_LEFT_HIP ].radius = BODY_BALL_RADIUS_LEFT_HIP; - - //_bodyBall[ BODY_BALL_LEFT_MID_THIGH ].radius = BODY_BALL_RADIUS_LEFT_MID_THIGH; - - _bodyBall[ BODY_BALL_LEFT_KNEE ].radius = BODY_BALL_RADIUS_LEFT_KNEE; - _bodyBall[ BODY_BALL_LEFT_HEEL ].radius = BODY_BALL_RADIUS_LEFT_HEEL; - _bodyBall[ BODY_BALL_LEFT_TOES ].radius = BODY_BALL_RADIUS_LEFT_TOES; - _bodyBall[ BODY_BALL_RIGHT_HIP ].radius = BODY_BALL_RADIUS_RIGHT_HIP; - _bodyBall[ BODY_BALL_RIGHT_KNEE ].radius = BODY_BALL_RADIUS_RIGHT_KNEE; - _bodyBall[ BODY_BALL_RIGHT_HEEL ].radius = BODY_BALL_RADIUS_RIGHT_HEEL; - _bodyBall[ BODY_BALL_RIGHT_TOES ].radius = BODY_BALL_RADIUS_RIGHT_TOES; + _bodyBall[BODY_BALL_PELVIS].radius = BODY_BALL_RADIUS_PELVIS; + _bodyBall[BODY_BALL_TORSO].radius = BODY_BALL_RADIUS_TORSO; + _bodyBall[BODY_BALL_CHEST].radius = BODY_BALL_RADIUS_CHEST; + _bodyBall[BODY_BALL_NECK_BASE].radius = BODY_BALL_RADIUS_NECK_BASE; + _bodyBall[BODY_BALL_HEAD_BASE].radius = BODY_BALL_RADIUS_HEAD_BASE; + _bodyBall[BODY_BALL_LEFT_COLLAR].radius = BODY_BALL_RADIUS_LEFT_COLLAR; + _bodyBall[BODY_BALL_LEFT_SHOULDER].radius = BODY_BALL_RADIUS_LEFT_SHOULDER; + _bodyBall[BODY_BALL_LEFT_ELBOW].radius = BODY_BALL_RADIUS_LEFT_ELBOW; + _bodyBall[BODY_BALL_LEFT_WRIST].radius = BODY_BALL_RADIUS_LEFT_WRIST; + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].radius = BODY_BALL_RADIUS_LEFT_FINGERTIPS; + _bodyBall[BODY_BALL_RIGHT_COLLAR].radius = BODY_BALL_RADIUS_RIGHT_COLLAR; + _bodyBall[BODY_BALL_RIGHT_SHOULDER].radius = BODY_BALL_RADIUS_RIGHT_SHOULDER; + _bodyBall[BODY_BALL_RIGHT_ELBOW].radius = BODY_BALL_RADIUS_RIGHT_ELBOW; + _bodyBall[BODY_BALL_RIGHT_WRIST].radius = BODY_BALL_RADIUS_RIGHT_WRIST; + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].radius = BODY_BALL_RADIUS_RIGHT_FINGERTIPS; + _bodyBall[BODY_BALL_LEFT_HIP].radius = BODY_BALL_RADIUS_LEFT_HIP; + _bodyBall[BODY_BALL_LEFT_KNEE].radius = BODY_BALL_RADIUS_LEFT_KNEE; + _bodyBall[BODY_BALL_LEFT_HEEL].radius = BODY_BALL_RADIUS_LEFT_HEEL; + _bodyBall[BODY_BALL_LEFT_TOES].radius = BODY_BALL_RADIUS_LEFT_TOES; + _bodyBall[BODY_BALL_RIGHT_HIP].radius = BODY_BALL_RADIUS_RIGHT_HIP; + _bodyBall[BODY_BALL_RIGHT_KNEE].radius = BODY_BALL_RADIUS_RIGHT_KNEE; + _bodyBall[BODY_BALL_RIGHT_HEEL].radius = BODY_BALL_RADIUS_RIGHT_HEEL; + _bodyBall[BODY_BALL_RIGHT_TOES].radius = BODY_BALL_RADIUS_RIGHT_TOES; // specify the parent joint for each ball - _bodyBall[ BODY_BALL_PELVIS ].parentJoint = AVATAR_JOINT_PELVIS; - _bodyBall[ BODY_BALL_TORSO ].parentJoint = AVATAR_JOINT_TORSO; - _bodyBall[ BODY_BALL_CHEST ].parentJoint = AVATAR_JOINT_CHEST; - _bodyBall[ BODY_BALL_NECK_BASE ].parentJoint = AVATAR_JOINT_NECK_BASE; - _bodyBall[ BODY_BALL_HEAD_BASE ].parentJoint = AVATAR_JOINT_HEAD_BASE; - _bodyBall[ BODY_BALL_HEAD_TOP ].parentJoint = AVATAR_JOINT_HEAD_TOP; - _bodyBall[ BODY_BALL_LEFT_COLLAR ].parentJoint = AVATAR_JOINT_LEFT_COLLAR; - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].parentJoint = AVATAR_JOINT_LEFT_SHOULDER; - _bodyBall[ BODY_BALL_LEFT_ELBOW ].parentJoint = AVATAR_JOINT_LEFT_ELBOW; - _bodyBall[ BODY_BALL_LEFT_WRIST ].parentJoint = AVATAR_JOINT_LEFT_WRIST; - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].parentJoint = AVATAR_JOINT_LEFT_FINGERTIPS; - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].parentJoint = AVATAR_JOINT_RIGHT_COLLAR; - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].parentJoint = AVATAR_JOINT_RIGHT_SHOULDER; - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].parentJoint = AVATAR_JOINT_RIGHT_ELBOW; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].parentJoint = AVATAR_JOINT_RIGHT_WRIST; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].parentJoint = AVATAR_JOINT_RIGHT_FINGERTIPS; - _bodyBall[ BODY_BALL_LEFT_HIP ].parentJoint = AVATAR_JOINT_LEFT_HIP; - _bodyBall[ BODY_BALL_LEFT_KNEE ].parentJoint = AVATAR_JOINT_LEFT_KNEE; - _bodyBall[ BODY_BALL_LEFT_HEEL ].parentJoint = AVATAR_JOINT_LEFT_HEEL; - _bodyBall[ BODY_BALL_LEFT_TOES ].parentJoint = AVATAR_JOINT_LEFT_TOES; - _bodyBall[ BODY_BALL_RIGHT_HIP ].parentJoint = AVATAR_JOINT_RIGHT_HIP; - _bodyBall[ BODY_BALL_RIGHT_KNEE ].parentJoint = AVATAR_JOINT_RIGHT_KNEE; - _bodyBall[ BODY_BALL_RIGHT_HEEL ].parentJoint = AVATAR_JOINT_RIGHT_HEEL; - _bodyBall[ BODY_BALL_RIGHT_TOES ].parentJoint = AVATAR_JOINT_RIGHT_TOES; - - //_bodyBall[ BODY_BALL_LEFT_MID_THIGH ].parentJoint = AVATAR_JOINT_LEFT_HIP; - + _bodyBall[BODY_BALL_PELVIS].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[BODY_BALL_TORSO].parentJoint = AVATAR_JOINT_TORSO; + _bodyBall[BODY_BALL_CHEST].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[BODY_BALL_NECK_BASE].parentJoint = AVATAR_JOINT_NECK_BASE; + _bodyBall[BODY_BALL_HEAD_BASE].parentJoint = AVATAR_JOINT_HEAD_BASE; + _bodyBall[BODY_BALL_HEAD_TOP].parentJoint = AVATAR_JOINT_HEAD_TOP; + _bodyBall[BODY_BALL_LEFT_COLLAR].parentJoint = AVATAR_JOINT_LEFT_COLLAR; + _bodyBall[BODY_BALL_LEFT_SHOULDER].parentJoint = AVATAR_JOINT_LEFT_SHOULDER; + _bodyBall[BODY_BALL_LEFT_ELBOW].parentJoint = AVATAR_JOINT_LEFT_ELBOW; + _bodyBall[BODY_BALL_LEFT_WRIST].parentJoint = AVATAR_JOINT_LEFT_WRIST; + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].parentJoint = AVATAR_JOINT_LEFT_FINGERTIPS; + _bodyBall[BODY_BALL_RIGHT_COLLAR].parentJoint = AVATAR_JOINT_RIGHT_COLLAR; + _bodyBall[BODY_BALL_RIGHT_SHOULDER].parentJoint = AVATAR_JOINT_RIGHT_SHOULDER; + _bodyBall[BODY_BALL_RIGHT_ELBOW].parentJoint = AVATAR_JOINT_RIGHT_ELBOW; + _bodyBall[BODY_BALL_RIGHT_WRIST].parentJoint = AVATAR_JOINT_RIGHT_WRIST; + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].parentJoint = AVATAR_JOINT_RIGHT_FINGERTIPS; + _bodyBall[BODY_BALL_LEFT_HIP].parentJoint = AVATAR_JOINT_LEFT_HIP; + _bodyBall[BODY_BALL_LEFT_KNEE].parentJoint = AVATAR_JOINT_LEFT_KNEE; + _bodyBall[BODY_BALL_LEFT_HEEL].parentJoint = AVATAR_JOINT_LEFT_HEEL; + _bodyBall[BODY_BALL_LEFT_TOES].parentJoint = AVATAR_JOINT_LEFT_TOES; + _bodyBall[BODY_BALL_RIGHT_HIP].parentJoint = AVATAR_JOINT_RIGHT_HIP; + _bodyBall[BODY_BALL_RIGHT_KNEE].parentJoint = AVATAR_JOINT_RIGHT_KNEE; + _bodyBall[BODY_BALL_RIGHT_HEEL].parentJoint = AVATAR_JOINT_RIGHT_HEEL; + _bodyBall[BODY_BALL_RIGHT_TOES].parentJoint = AVATAR_JOINT_RIGHT_TOES; + // specify the parent offset for each ball - _bodyBall[ BODY_BALL_PELVIS ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_TORSO ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_CHEST ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_NECK_BASE ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_HEAD_BASE ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_HEAD_TOP ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_COLLAR ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_ELBOW ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_WRIST ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_WRIST ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_HIP ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_KNEE ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_HEEL ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_LEFT_TOES ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_HIP ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_KNEE ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_HEEL ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - _bodyBall[ BODY_BALL_RIGHT_TOES ].parentOffset = glm::vec3(0.0, 0.0, 0.0); - - - //_bodyBall[ BODY_BALL_LEFT_MID_THIGH ].parentOffset = glm::vec3(-0.1, -0.1, 0.0); - - + _bodyBall[BODY_BALL_PELVIS].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_TORSO].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_CHEST].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_NECK_BASE].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_HEAD_BASE].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_HEAD_TOP].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_COLLAR].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_SHOULDER].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_ELBOW].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_WRIST].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_COLLAR].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_SHOULDER].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_ELBOW].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_WRIST].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_HIP].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_KNEE].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_HEEL].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_LEFT_TOES].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_HIP].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_KNEE].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_HEEL].parentOffset = glm::vec3(0.0, 0.0, 0.0); + _bodyBall[BODY_BALL_RIGHT_TOES].parentOffset = glm::vec3(0.0, 0.0, 0.0); + // specify the parent BALL for each ball - _bodyBall[ BODY_BALL_PELVIS ].parentBall = BODY_BALL_NULL; - _bodyBall[ BODY_BALL_TORSO ].parentBall = BODY_BALL_PELVIS; - _bodyBall[ BODY_BALL_CHEST ].parentBall = BODY_BALL_TORSO; - _bodyBall[ BODY_BALL_NECK_BASE ].parentBall = BODY_BALL_CHEST; - _bodyBall[ BODY_BALL_HEAD_BASE ].parentBall = BODY_BALL_NECK_BASE; - _bodyBall[ BODY_BALL_HEAD_TOP ].parentBall = BODY_BALL_HEAD_BASE; - _bodyBall[ BODY_BALL_LEFT_COLLAR ].parentBall = BODY_BALL_CHEST; - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].parentBall = BODY_BALL_LEFT_COLLAR; - _bodyBall[ BODY_BALL_LEFT_ELBOW ].parentBall = BODY_BALL_LEFT_SHOULDER; - _bodyBall[ BODY_BALL_LEFT_WRIST ].parentBall = BODY_BALL_LEFT_ELBOW; - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].parentBall = BODY_BALL_LEFT_WRIST; - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].parentBall = BODY_BALL_CHEST; - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].parentBall = BODY_BALL_RIGHT_COLLAR; - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].parentBall = BODY_BALL_RIGHT_SHOULDER; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].parentBall = BODY_BALL_RIGHT_ELBOW; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].parentBall = BODY_BALL_RIGHT_WRIST; - _bodyBall[ BODY_BALL_LEFT_HIP ].parentBall = BODY_BALL_PELVIS; - - //_bodyBall[ BODY_BALL_LEFT_MID_THIGH ].parentBall = BODY_BALL_LEFT_HIP; - - //_bodyBall[ BODY_BALL_LEFT_KNEE ].parentBall = BODY_BALL_LEFT_MID_THIGH; - _bodyBall[ BODY_BALL_LEFT_KNEE ].parentBall = BODY_BALL_LEFT_HIP; - - _bodyBall[ BODY_BALL_LEFT_HEEL ].parentBall = BODY_BALL_LEFT_KNEE; - _bodyBall[ BODY_BALL_LEFT_TOES ].parentBall = BODY_BALL_LEFT_HEEL; - _bodyBall[ BODY_BALL_RIGHT_HIP ].parentBall = BODY_BALL_PELVIS; - _bodyBall[ BODY_BALL_RIGHT_KNEE ].parentBall = BODY_BALL_RIGHT_HIP; - _bodyBall[ BODY_BALL_RIGHT_HEEL ].parentBall = BODY_BALL_RIGHT_KNEE; - _bodyBall[ BODY_BALL_RIGHT_TOES ].parentBall = BODY_BALL_RIGHT_HEEL; - - /* - // to aid in hand-shaking and hand-holding, the right hand is not collidable - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].isCollidable = false; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].isCollidable = false; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].isCollidable = false; - */ + _bodyBall[BODY_BALL_PELVIS].parentBall = BODY_BALL_NULL; + _bodyBall[BODY_BALL_TORSO].parentBall = BODY_BALL_PELVIS; + _bodyBall[BODY_BALL_CHEST].parentBall = BODY_BALL_TORSO; + _bodyBall[BODY_BALL_NECK_BASE].parentBall = BODY_BALL_CHEST; + _bodyBall[BODY_BALL_HEAD_BASE].parentBall = BODY_BALL_NECK_BASE; + _bodyBall[BODY_BALL_HEAD_TOP].parentBall = BODY_BALL_HEAD_BASE; + _bodyBall[BODY_BALL_LEFT_COLLAR].parentBall = BODY_BALL_CHEST; + _bodyBall[BODY_BALL_LEFT_SHOULDER].parentBall = BODY_BALL_LEFT_COLLAR; + _bodyBall[BODY_BALL_LEFT_ELBOW].parentBall = BODY_BALL_LEFT_SHOULDER; + _bodyBall[BODY_BALL_LEFT_WRIST].parentBall = BODY_BALL_LEFT_ELBOW; + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].parentBall = BODY_BALL_LEFT_WRIST; + _bodyBall[BODY_BALL_RIGHT_COLLAR].parentBall = BODY_BALL_CHEST; + _bodyBall[BODY_BALL_RIGHT_SHOULDER].parentBall = BODY_BALL_RIGHT_COLLAR; + _bodyBall[BODY_BALL_RIGHT_ELBOW].parentBall = BODY_BALL_RIGHT_SHOULDER; + _bodyBall[BODY_BALL_RIGHT_WRIST].parentBall = BODY_BALL_RIGHT_ELBOW; + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].parentBall = BODY_BALL_RIGHT_WRIST; + _bodyBall[BODY_BALL_LEFT_HIP].parentBall = BODY_BALL_PELVIS; + _bodyBall[BODY_BALL_LEFT_KNEE].parentBall = BODY_BALL_LEFT_HIP; + _bodyBall[BODY_BALL_LEFT_HEEL].parentBall = BODY_BALL_LEFT_KNEE; + _bodyBall[BODY_BALL_LEFT_TOES].parentBall = BODY_BALL_LEFT_HEEL; + _bodyBall[BODY_BALL_RIGHT_HIP].parentBall = BODY_BALL_PELVIS; + _bodyBall[BODY_BALL_RIGHT_KNEE].parentBall = BODY_BALL_RIGHT_HIP; + _bodyBall[BODY_BALL_RIGHT_HEEL].parentBall = BODY_BALL_RIGHT_KNEE; + _bodyBall[BODY_BALL_RIGHT_TOES].parentBall = BODY_BALL_RIGHT_HEEL; } Avatar::~Avatar() { @@ -364,12 +338,12 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { glm::vec3 targetPosition - = _skeleton.joint[_bodyBall[b].parentJoint].position - + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; glm::vec3 parentTargetPosition - = _skeleton.joint[_bodyBall[b].parentJoint].position - + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; _bodyBall[b].springLength = glm::length(targetPosition - parentTargetPosition); } @@ -400,26 +374,26 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer right * _head.getLeanSideways() + front * _head.getLeanForward(); - _bodyBall[ BODY_BALL_TORSO ].position += headLean * 0.1f; - _bodyBall[ BODY_BALL_CHEST ].position += headLean * 0.4f; - _bodyBall[ BODY_BALL_NECK_BASE ].position += headLean * 0.7f; - _bodyBall[ BODY_BALL_HEAD_BASE ].position += headLean * 1.0f; + _bodyBall[BODY_BALL_TORSO].position += headLean * 0.1f; + _bodyBall[BODY_BALL_CHEST].position += headLean * 0.4f; + _bodyBall[BODY_BALL_NECK_BASE].position += headLean * 0.7f; + _bodyBall[BODY_BALL_HEAD_BASE].position += headLean * 1.0f; - _bodyBall[ BODY_BALL_LEFT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_LEFT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ BODY_BALL_LEFT_WRIST ].position += headLean * 0.1f; - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[BODY_BALL_LEFT_COLLAR].position += headLean * 0.6f; + _bodyBall[BODY_BALL_LEFT_SHOULDER].position += headLean * 0.6f; + _bodyBall[BODY_BALL_LEFT_ELBOW].position += headLean * 0.2f; + _bodyBall[BODY_BALL_LEFT_WRIST].position += headLean * 0.1f; + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].position += headLean * 0.0f; - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].position += headLean * 0.1f; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[BODY_BALL_RIGHT_COLLAR].position += headLean * 0.6f; + _bodyBall[BODY_BALL_RIGHT_SHOULDER].position += headLean * 0.6f; + _bodyBall[BODY_BALL_RIGHT_ELBOW].position += headLean * 0.2f; + _bodyBall[BODY_BALL_RIGHT_WRIST].position += headLean * 0.1f; + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].position += headLean * 0.0f; } } - _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); + _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); _head.setScale(_scale); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); @@ -441,7 +415,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCamer } -void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction ) { +void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) { _mouseRayOrigin = origin; _mouseRayDirection = direction; } @@ -452,16 +426,16 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem // reset hand and arm positions according to hand movement glm::vec3 right = orientation * IDENTITY_RIGHT; - glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 front = orientation * IDENTITY_FRONT; if (enableHandMovement) { glm::vec3 transformedHandMovement = - right * _movedHandOffset.x * 2.0f + - up * -_movedHandOffset.y * 2.0f + + right * _movedHandOffset.x * 2.0f + + up * -_movedHandOffset.y * 2.0f + front * -_movedHandOffset.y * 2.0f; - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement; + _skeleton.joint[AVATAR_JOINT_RIGHT_FINGERTIPS].position += transformedHandMovement; } //constrain right arm length and re-adjust elbow position as it bends @@ -517,7 +491,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { // render sphere when far away const float MAX_ANGLE = 10.f; glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition(); - glm::vec3 delta = _height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f; + glm::vec3 delta = _height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f; float angle = abs(angleBetween(toTarget + delta, toTarget - delta)); if (angle < MAX_ANGLE) { @@ -629,8 +603,8 @@ void Avatar::updateBodyBalls(float deltaTime) { // apply tightness force - (causing ball position to be close to skeleton joint position) glm::vec3 targetPosition - = _skeleton.joint[_bodyBall[b].parentJoint].position - + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; _bodyBall[b].velocity += (targetPosition - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime; @@ -642,13 +616,6 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } - /* - // apply forces from touch... - if (_bodyBall[b].touchForce > 0.0) { - _bodyBall[b].velocity += _mouseRayDirection * _bodyBall[b].touchForce * 0.7f; - } - */ - // update position by velocity... _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; @@ -768,27 +735,23 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { // Render the cone connecting this ball to its parent if (_bodyBall[b].parentBall != BODY_BALL_NULL) { - if ((b != BODY_BALL_HEAD_TOP ) - && (b != BODY_BALL_HEAD_BASE ) - && (b != BODY_BALL_PELVIS ) - && (b != BODY_BALL_TORSO ) - && (b != BODY_BALL_CHEST ) - && (b != BODY_BALL_LEFT_COLLAR ) - && (b != BODY_BALL_LEFT_SHOULDER ) - && (b != BODY_BALL_RIGHT_COLLAR ) - && (b != BODY_BALL_RIGHT_SHOULDER)) { + if ((b != BODY_BALL_HEAD_TOP) + && (b != BODY_BALL_HEAD_BASE) + && (b != BODY_BALL_PELVIS) + && (b != BODY_BALL_TORSO) + && (b != BODY_BALL_CHEST) + && (b != BODY_BALL_LEFT_COLLAR) + && (b != BODY_BALL_LEFT_SHOULDER) + && (b != BODY_BALL_RIGHT_COLLAR) + && (b != BODY_BALL_RIGHT_SHOULDER)) { glColor3fv(DARK_SKIN_COLOR); - float r1 = _bodyBall[_bodyBall[b].parentBall ].radius * 0.8; + float r1 = _bodyBall[_bodyBall[b].parentBall].radius * 0.8; float r2 = _bodyBall[b].radius * 0.8; if (b == BODY_BALL_HEAD_BASE) { r1 *= 0.5f; } - renderJointConnectingCone - ( - _bodyBall[_bodyBall[b].parentBall].position, - _bodyBall[b].position, r2, r2 - ); + renderJointConnectingCone(_bodyBall[_bodyBall[b].parentBall].position, _bodyBall[b].position, r2, r2); } } } @@ -808,9 +771,9 @@ void Avatar::loadData(QSettings* settings) { settings->beginGroup("Avatar"); // in case settings is corrupt or missing loadSetting() will check for NaN - _bodyYaw = loadSetting(settings, "bodyYaw" , 0.0f); - _bodyPitch = loadSetting(settings, "bodyPitch", 0.0f); - _bodyRoll = loadSetting(settings, "bodyRoll" , 0.0f); + _bodyYaw = loadSetting(settings, "bodyYaw", 0.0f); + _bodyPitch = loadSetting(settings, "bodyPitch", 0.0f); + _bodyRoll = loadSetting(settings, "bodyRoll", 0.0f); _position.x = loadSetting(settings, "position_x", 0.0f); _position.y = loadSetting(settings, "position_y", 0.0f); _position.z = loadSetting(settings, "position_z", 0.0f); @@ -834,9 +797,9 @@ void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, gl void Avatar::saveData(QSettings* set) { set->beginGroup("Avatar"); - set->setValue("bodyYaw", _bodyYaw); + set->setValue("bodyYaw", _bodyYaw); set->setValue("bodyPitch", _bodyPitch); - set->setValue("bodyRoll", _bodyRoll); + set->setValue("bodyRoll", _bodyRoll); set->setValue("position_x", _position.x); set->setValue("position_y", _position.y); @@ -933,39 +896,36 @@ void Avatar::setScale(const float scale) { _skeleton.setScale(_scale); // specify the new radius of each ball - _bodyBall[ BODY_BALL_PELVIS ].radius = _scale * BODY_BALL_RADIUS_PELVIS; - _bodyBall[ BODY_BALL_TORSO ].radius = _scale * BODY_BALL_RADIUS_TORSO; - _bodyBall[ BODY_BALL_CHEST ].radius = _scale * BODY_BALL_RADIUS_CHEST; - _bodyBall[ BODY_BALL_NECK_BASE ].radius = _scale * BODY_BALL_RADIUS_NECK_BASE; - _bodyBall[ BODY_BALL_HEAD_BASE ].radius = _scale * BODY_BALL_RADIUS_HEAD_BASE; - _bodyBall[ BODY_BALL_LEFT_COLLAR ].radius = _scale * BODY_BALL_RADIUS_LEFT_COLLAR; - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].radius = _scale * BODY_BALL_RADIUS_LEFT_SHOULDER; - _bodyBall[ BODY_BALL_LEFT_ELBOW ].radius = _scale * BODY_BALL_RADIUS_LEFT_ELBOW; - _bodyBall[ BODY_BALL_LEFT_WRIST ].radius = _scale * BODY_BALL_RADIUS_LEFT_WRIST; - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].radius = _scale * BODY_BALL_RADIUS_LEFT_FINGERTIPS; - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].radius = _scale * BODY_BALL_RADIUS_RIGHT_COLLAR; - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].radius = _scale * BODY_BALL_RADIUS_RIGHT_SHOULDER; - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].radius = _scale * BODY_BALL_RADIUS_RIGHT_ELBOW; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].radius = _scale * BODY_BALL_RADIUS_RIGHT_WRIST; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].radius = _scale * BODY_BALL_RADIUS_RIGHT_FINGERTIPS; - _bodyBall[ BODY_BALL_LEFT_HIP ].radius = _scale * BODY_BALL_RADIUS_LEFT_HIP; + _bodyBall[BODY_BALL_PELVIS].radius = _scale * BODY_BALL_RADIUS_PELVIS; + _bodyBall[BODY_BALL_TORSO].radius = _scale * BODY_BALL_RADIUS_TORSO; + _bodyBall[BODY_BALL_CHEST].radius = _scale * BODY_BALL_RADIUS_CHEST; + _bodyBall[BODY_BALL_NECK_BASE].radius = _scale * BODY_BALL_RADIUS_NECK_BASE; + _bodyBall[BODY_BALL_HEAD_BASE].radius = _scale * BODY_BALL_RADIUS_HEAD_BASE; + _bodyBall[BODY_BALL_LEFT_COLLAR].radius = _scale * BODY_BALL_RADIUS_LEFT_COLLAR; + _bodyBall[BODY_BALL_LEFT_SHOULDER].radius = _scale * BODY_BALL_RADIUS_LEFT_SHOULDER; + _bodyBall[BODY_BALL_LEFT_ELBOW].radius = _scale * BODY_BALL_RADIUS_LEFT_ELBOW; + _bodyBall[BODY_BALL_LEFT_WRIST].radius = _scale * BODY_BALL_RADIUS_LEFT_WRIST; + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].radius = _scale * BODY_BALL_RADIUS_LEFT_FINGERTIPS; + _bodyBall[BODY_BALL_RIGHT_COLLAR].radius = _scale * BODY_BALL_RADIUS_RIGHT_COLLAR; + _bodyBall[BODY_BALL_RIGHT_SHOULDER].radius = _scale * BODY_BALL_RADIUS_RIGHT_SHOULDER; + _bodyBall[BODY_BALL_RIGHT_ELBOW].radius = _scale * BODY_BALL_RADIUS_RIGHT_ELBOW; + _bodyBall[BODY_BALL_RIGHT_WRIST].radius = _scale * BODY_BALL_RADIUS_RIGHT_WRIST; + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].radius = _scale * BODY_BALL_RADIUS_RIGHT_FINGERTIPS; + _bodyBall[BODY_BALL_LEFT_HIP].radius = _scale * BODY_BALL_RADIUS_LEFT_HIP; + _bodyBall[BODY_BALL_LEFT_KNEE].radius = _scale * BODY_BALL_RADIUS_LEFT_KNEE; + _bodyBall[BODY_BALL_LEFT_HEEL].radius = _scale * BODY_BALL_RADIUS_LEFT_HEEL; + _bodyBall[BODY_BALL_LEFT_TOES].radius = _scale * BODY_BALL_RADIUS_LEFT_TOES; + _bodyBall[BODY_BALL_RIGHT_HIP].radius = _scale * BODY_BALL_RADIUS_RIGHT_HIP; + _bodyBall[BODY_BALL_RIGHT_KNEE].radius = _scale * BODY_BALL_RADIUS_RIGHT_KNEE; + _bodyBall[BODY_BALL_RIGHT_HEEL].radius = _scale * BODY_BALL_RADIUS_RIGHT_HEEL; + _bodyBall[BODY_BALL_RIGHT_TOES].radius = _scale * BODY_BALL_RADIUS_RIGHT_TOES; - //_bodyBall[ BODY_BALL_LEFT_MID_THIGH ].radius = _scale * BODY_BALL_RADIUS_LEFT_MID_THIGH; + _height = _skeleton.getHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius + _bodyBall[BODY_BALL_HEAD_BASE].radius; - _bodyBall[ BODY_BALL_LEFT_KNEE ].radius = _scale * BODY_BALL_RADIUS_LEFT_KNEE; - _bodyBall[ BODY_BALL_LEFT_HEEL ].radius = _scale * BODY_BALL_RADIUS_LEFT_HEEL; - _bodyBall[ BODY_BALL_LEFT_TOES ].radius = _scale * BODY_BALL_RADIUS_LEFT_TOES; - _bodyBall[ BODY_BALL_RIGHT_HIP ].radius = _scale * BODY_BALL_RADIUS_RIGHT_HIP; - _bodyBall[ BODY_BALL_RIGHT_KNEE ].radius = _scale * BODY_BALL_RADIUS_RIGHT_KNEE; - _bodyBall[ BODY_BALL_RIGHT_HEEL ].radius = _scale * BODY_BALL_RADIUS_RIGHT_HEEL; - _bodyBall[ BODY_BALL_RIGHT_TOES ].radius = _scale * BODY_BALL_RADIUS_RIGHT_TOES; - - _height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius; - - _maxArmLength = _skeleton.getArmLength(); - _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; - _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; - _pelvisToHeadLength = _skeleton.getPelvisToHeadLength(); + _maxArmLength = _skeleton.getArmLength(); + _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius; + _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius; + _pelvisToHeadLength = _skeleton.getPelvisToHeadLength(); _avatarTouch.setReachableRadius(_scale * PERIPERSONAL_RADIUS); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 7838c31a5e..eb7a7851d0 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -27,36 +27,36 @@ #include "world.h" -static const float MAX_SCALE = 1000.f; -static const float MIN_SCALE = .005f; -static const float SCALING_RATIO = .05f; -static const float SMOOTHING_RATIO = .05f; // 0 < ratio < 1 +static const float MAX_SCALE = 1000.f; +static const float MIN_SCALE = .005f; +static const float SCALING_RATIO = .05f; +static const float SMOOTHING_RATIO = .05f; // 0 < ratio < 1 static const float RESCALING_TOLERANCE = .02f; -const float BODY_BALL_RADIUS_PELVIS = 0.07; -const float BODY_BALL_RADIUS_TORSO = 0.065; -const float BODY_BALL_RADIUS_CHEST = 0.08; -const float BODY_BALL_RADIUS_NECK_BASE = 0.03; -const float BODY_BALL_RADIUS_HEAD_BASE = 0.07; -const float BODY_BALL_RADIUS_LEFT_COLLAR = 0.04; -const float BODY_BALL_RADIUS_LEFT_SHOULDER = 0.03; -const float BODY_BALL_RADIUS_LEFT_ELBOW = 0.02; -const float BODY_BALL_RADIUS_LEFT_WRIST = 0.02; -const float BODY_BALL_RADIUS_LEFT_FINGERTIPS = 0.01; -const float BODY_BALL_RADIUS_RIGHT_COLLAR = 0.04; -const float BODY_BALL_RADIUS_RIGHT_SHOULDER = 0.03; -const float BODY_BALL_RADIUS_RIGHT_ELBOW = 0.02; -const float BODY_BALL_RADIUS_RIGHT_WRIST = 0.02; +const float BODY_BALL_RADIUS_PELVIS = 0.07; +const float BODY_BALL_RADIUS_TORSO = 0.065; +const float BODY_BALL_RADIUS_CHEST = 0.08; +const float BODY_BALL_RADIUS_NECK_BASE = 0.03; +const float BODY_BALL_RADIUS_HEAD_BASE = 0.07; +const float BODY_BALL_RADIUS_LEFT_COLLAR = 0.04; +const float BODY_BALL_RADIUS_LEFT_SHOULDER = 0.03; +const float BODY_BALL_RADIUS_LEFT_ELBOW = 0.02; +const float BODY_BALL_RADIUS_LEFT_WRIST = 0.02; +const float BODY_BALL_RADIUS_LEFT_FINGERTIPS = 0.01; +const float BODY_BALL_RADIUS_RIGHT_COLLAR = 0.04; +const float BODY_BALL_RADIUS_RIGHT_SHOULDER = 0.03; +const float BODY_BALL_RADIUS_RIGHT_ELBOW = 0.02; +const float BODY_BALL_RADIUS_RIGHT_WRIST = 0.02; const float BODY_BALL_RADIUS_RIGHT_FINGERTIPS = 0.01; -const float BODY_BALL_RADIUS_LEFT_HIP = 0.04; -const float BODY_BALL_RADIUS_LEFT_MID_THIGH = 0.03; -const float BODY_BALL_RADIUS_LEFT_KNEE = 0.025; -const float BODY_BALL_RADIUS_LEFT_HEEL = 0.025; -const float BODY_BALL_RADIUS_LEFT_TOES = 0.025; -const float BODY_BALL_RADIUS_RIGHT_HIP = 0.04; -const float BODY_BALL_RADIUS_RIGHT_KNEE = 0.025; -const float BODY_BALL_RADIUS_RIGHT_HEEL = 0.025; -const float BODY_BALL_RADIUS_RIGHT_TOES = 0.025; +const float BODY_BALL_RADIUS_LEFT_HIP = 0.04; +const float BODY_BALL_RADIUS_LEFT_MID_THIGH = 0.03; +const float BODY_BALL_RADIUS_LEFT_KNEE = 0.025; +const float BODY_BALL_RADIUS_LEFT_HEEL = 0.025; +const float BODY_BALL_RADIUS_LEFT_TOES = 0.025; +const float BODY_BALL_RADIUS_RIGHT_HIP = 0.04; +const float BODY_BALL_RADIUS_RIGHT_KNEE = 0.025; +const float BODY_BALL_RADIUS_RIGHT_HEEL = 0.025; +const float BODY_BALL_RADIUS_RIGHT_TOES = 0.025; extern const bool usingBigSphereCollisionTest; @@ -89,9 +89,6 @@ enum AvatarBodyBallID { BODY_BALL_RIGHT_KNEE, BODY_BALL_RIGHT_HEEL, BODY_BALL_RIGHT_TOES, - -//TEST! -//BODY_BALL_LEFT_MID_THIGH, NUM_AVATAR_BODY_BALLS }; @@ -131,6 +128,7 @@ const glm::vec3 START_LOCATION(0.485f * TREE_SCALE, 0.f, 0.5f * TREE_SCALE); class Avatar : public AvatarData { Q_OBJECT + public: static void sendAvatarVoxelURLMessage(const QUrl& url); @@ -143,28 +141,27 @@ public: void render(bool lookingInMirror, bool renderAvatarBalls); //setters - void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);} - void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction); + void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors); } + void setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction); //getters - bool isInitialized () const { return _initialized;} - const Skeleton& getSkeleton () const { return _skeleton;} - float getHeadYawRate () const { return _head.yawRate;} - const glm::vec3& getHeadJointPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;} - float getScale () const { return _scale;} - const glm::vec3& getVelocity () const { return _velocity;} - Head& getHead () {return _head; } - Hand& getHand () {return _hand; } - glm::quat getOrientation () const; - glm::quat getWorldAlignedOrientation() const; - + bool isInitialized() const { return _initialized; } + const Skeleton& getSkeleton() const { return _skeleton; } + float getHeadYawRate() const { return _head.yawRate; } + const glm::vec3& getHeadJointPosition() const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position; } + float getScale() const { return _scale; } + const glm::vec3& getVelocity() const { return _velocity; } + Head& getHead() {return _head; } + Hand& getHand() {return _hand; } + glm::quat getOrientation() const; + glm::quat getWorldAlignedOrientation() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } // get/set avatar data void saveData(QSettings* set); void loadData(QSettings* set); - // Get the position/rotation of a single body ball + // Get the position/rotation of a single body ball void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const; static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); @@ -180,59 +177,57 @@ public slots: protected: - struct AvatarBall - { - AvatarJointID parentJoint; // the skeletal joint that serves as a reference for determining the position - glm::vec3 parentOffset; // a 3D vector in the frame of reference of the parent skeletal joint - AvatarBodyBallID parentBall; // the ball to which this ball is constrained for spring forces - 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 springLength; // the ideal length of the spring between this ball and its parentBall - float jointTightness; // how tightly the ball position attempts to stay at its ideal position (determined by parentOffset) - 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 + struct AvatarBall { + AvatarJointID parentJoint; /// the skeletal joint that serves as a reference for determining the position + glm::vec3 parentOffset; /// a 3D vector in the frame of reference of the parent skeletal joint + AvatarBodyBallID parentBall; /// the ball to which this ball is constrained for spring forces + 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 springLength; /// the ideal length of the spring between this ball and its parentBall + float jointTightness; /// how tightly the ball position attempts to stay at its ideal position (determined by parentOffset) + 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 }; - Head _head; - Hand _hand; - Skeleton _skeleton; - bool _ballSpringsInitialized; - float _TEST_bigSphereRadius; - glm::vec3 _TEST_bigSpherePosition; - float _bodyYawDelta; - glm::vec3 _movedHandOffset; - AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; - AvatarMode _mode; - glm::vec3 _velocity; - glm::vec3 _thrust; - float _speed; - float _leanScale; - float _pelvisFloatingHeight; - float _pelvisToHeadLength; - float _scale; - float _height; - Balls* _balls; + Head _head; + Hand _hand; + Skeleton _skeleton; + bool _ballSpringsInitialized; + float _TEST_bigSphereRadius; + glm::vec3 _TEST_bigSpherePosition; + float _bodyYawDelta; + glm::vec3 _movedHandOffset; + AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; + AvatarMode _mode; + glm::vec3 _velocity; + glm::vec3 _thrust; + float _speed; + float _leanScale; + float _pelvisFloatingHeight; + float _pelvisToHeadLength; + float _scale; + float _height; + Balls* _balls; AvatarTouch _avatarTouch; - glm::vec3 _worldUpDirection; - glm::vec3 _mouseRayOrigin; - glm::vec3 _mouseRayDirection; - bool _isCollisionsOn; - Avatar* _leadingAvatar; - float _stringLength; - + glm::vec3 _worldUpDirection; + glm::vec3 _mouseRayOrigin; + glm::vec3 _mouseRayDirection; + bool _isCollisionsOn; + Avatar* _leadingAvatar; + float _stringLength; AvatarVoxelSystem _voxels; // protected methods... - glm::vec3 getBodyRightDirection () const { return getOrientation() * IDENTITY_RIGHT; } - glm::vec3 getBodyUpDirection () const { return getOrientation() * IDENTITY_UP; } - glm::vec3 getBodyFrontDirection () const { return getOrientation() * IDENTITY_FRONT; } + glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } + glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } + glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; - void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateBodyBalls( float deltaTime ); - void updateArmIKAndConstraints( float deltaTime ); - void setScale (const float scale); + void updateCollisionWithSphere(glm::vec3 position, float radius, float deltaTime); + void updateBodyBalls(float deltaTime); + void updateArmIKAndConstraints(float deltaTime); + void setScale(const float scale); private: @@ -240,10 +235,10 @@ private: Avatar(const Avatar&); Avatar& operator= (const Avatar&); - bool _initialized; - glm::vec3 _handHoldingPosition; - float _maxArmLength; - float _pelvisStandingHeight; + bool _initialized; + glm::vec3 _handHoldingPosition; + float _maxArmLength; + float _pelvisStandingHeight; // private methods... glm::vec3 calculateAverageEyePosition() { return _head.calculateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 82f2062a84..ebf275a104 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -24,17 +24,18 @@ using namespace std; -const bool USING_AVATAR_GRAVITY = true; -const glm::vec3 DEFAULT_UP_DIRECTION (0.0f, 1.0f, 0.0f); -const float YAW_MAG = 500.0; -const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions -const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions -const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions -const float PERIPERSONAL_RADIUS = 1.0f; -const float MOUSE_RAY_TOUCH_RANGE = 0.01f; -const bool USING_HEAD_LEAN = false; -const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; -const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; +const bool USING_AVATAR_GRAVITY = true; +const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f); +const float YAW_MAG = 500.0; +const float COLLISION_RADIUS_SCALAR = 1.2; // pertains to avatar-to-avatar collisions +const float COLLISION_BALL_FORCE = 200.0; // pertains to avatar-to-avatar collisions +const float COLLISION_BODY_FORCE = 30.0; // pertains to avatar-to-avatar collisions +const float COLLISION_RADIUS_SCALE = 0.125f; +const float PERIPERSONAL_RADIUS = 1.0f; +const float MOUSE_RAY_TOUCH_RANGE = 0.01f; +const bool USING_HEAD_LEAN = false; +const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; +const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; MyAvatar::MyAvatar(Node* owningNode) : Avatar(owningNode), @@ -56,7 +57,7 @@ MyAvatar::MyAvatar(Node* owningNode) : _driveKeys[i] = false; } - _collisionRadius = _height * 0.125f; + _collisionRadius = _height * COLLISION_RADIUS_SCALE; } void MyAvatar::reset() { @@ -105,7 +106,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam // calculate speed _speed = glm::length(_velocity); - //figure out if the mouse cursor is over any body spheres... + // figure out if the mouse cursor is over any body spheres... checkForMouseRayTouching(); // update balls @@ -136,17 +137,17 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam // update avatar skeleton _skeleton.update(deltaTime, getOrientation(), _position); - //determine the lengths of the body springs now that we have updated the skeleton at least once + // determine the lengths of the body springs now that we have updated the skeleton at least once if (!_ballSpringsInitialized) { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { glm::vec3 targetPosition - = _skeleton.joint[_bodyBall[b].parentJoint].position - + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; glm::vec3 parentTargetPosition - = _skeleton.joint[_bodyBall[b].parentJoint].position - + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; _bodyBall[b].springLength = glm::length(targetPosition - parentTargetPosition); } @@ -154,7 +155,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam _ballSpringsInitialized = true; } - //update the movement of the hand and process handshaking with other avatars... + // update the movement of the hand and process handshaking with other avatars... updateHandMovementAndTouching(deltaTime, enableHandMovement); _avatarTouch.simulate(deltaTime); @@ -162,7 +163,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam if (USING_AVATAR_GRAVITY) { // For gravity, always move the avatar by the amount driven by gravity, so that the collision // routines will detect it and collide every frame when pulled by gravity to a surface - // const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f; if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) { _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); @@ -176,7 +176,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam _collisionRadius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f)); _collisionRadius *= COLLISION_RADIUS_SCALAR; } else { - _collisionRadius = _height * .125f; + _collisionRadius = _height * COLLISION_RADIUS_SCALE; } updateCollisionWithEnvironment(deltaTime); @@ -186,7 +186,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam // update body balls updateBodyBalls(deltaTime); - // test for avatar collision response with the big sphere if (usingBigSphereCollisionTest && _isCollisionsOn) { @@ -198,15 +197,15 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam // update body yaw by body yaw delta orientation = orientation * glm::quat(glm::radians( - glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); + glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); // decay body rotation momentum const float BODY_SPIN_FRICTION = 7.5f; float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime; - if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; } + if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; } _bodyPitchDelta *= bodySpinMomentum; - _bodyYawDelta *= bodySpinMomentum; - _bodyRollDelta *= bodySpinMomentum; + _bodyYawDelta *= bodySpinMomentum; + _bodyRollDelta *= bodySpinMomentum; float MINIMUM_ROTATION_RATE = 2.0f; if (fabs(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { _bodyYawDelta = 0.f; } @@ -226,18 +225,20 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam applyDamping(deltaTime, _velocity, LINEAR_DAMPING_STRENGTH, SQUARED_DAMPING_STRENGTH); } - //pitch and roll the body as a function of forward speed and turning delta - const float BODY_PITCH_WHILE_WALKING = -20.0; - const float BODY_ROLL_WHILE_TURNING = 0.2; + // pitch and roll the body as a function of forward speed and turning delta + const float BODY_PITCH_WHILE_WALKING = -20.0; + const float BODY_ROLL_WHILE_TURNING = 0.2; float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity); orientation = orientation * glm::quat(glm::radians(glm::vec3( - BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f, - BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta))); + BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f, + BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta))); // these forces keep the body upright... const float BODY_UPRIGHT_FORCE = _scale * 10.0; float tiltDecay = BODY_UPRIGHT_FORCE * deltaTime; - if (tiltDecay > 1.0f) {tiltDecay = 1.0f;} + if (tiltDecay > 1.0f) { + tiltDecay = 1.0f; + } // update the euler angles setOrientation(orientation); @@ -245,7 +246,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam //the following will be used to make the avatar upright no matter what gravity is setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation); - // Compute instantaneous acceleration + // Compute instantaneous acceleration float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; const float ACCELERATION_PITCH_DECAY = 0.4f; const float ACCELERATION_YAW_DECAY = 0.4f; @@ -283,26 +284,26 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam right * _head.getLeanSideways() + front * _head.getLeanForward(); - _bodyBall[ BODY_BALL_TORSO ].position += headLean * 0.1f; - _bodyBall[ BODY_BALL_CHEST ].position += headLean * 0.4f; - _bodyBall[ BODY_BALL_NECK_BASE ].position += headLean * 0.7f; - _bodyBall[ BODY_BALL_HEAD_BASE ].position += headLean * 1.0f; + _bodyBall[BODY_BALL_TORSO].position += headLean * 0.1f; + _bodyBall[BODY_BALL_CHEST].position += headLean * 0.4f; + _bodyBall[BODY_BALL_NECK_BASE].position += headLean * 0.7f; + _bodyBall[BODY_BALL_HEAD_BASE].position += headLean * 1.0f; - _bodyBall[ BODY_BALL_LEFT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_LEFT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_LEFT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ BODY_BALL_LEFT_WRIST ].position += headLean * 0.1f; - _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[BODY_BALL_LEFT_COLLAR].position += headLean * 0.6f; + _bodyBall[BODY_BALL_LEFT_SHOULDER].position += headLean * 0.6f; + _bodyBall[BODY_BALL_LEFT_ELBOW].position += headLean * 0.2f; + _bodyBall[BODY_BALL_LEFT_WRIST].position += headLean * 0.1f; + _bodyBall[BODY_BALL_LEFT_FINGERTIPS].position += headLean * 0.0f; - _bodyBall[ BODY_BALL_RIGHT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ BODY_BALL_RIGHT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ BODY_BALL_RIGHT_WRIST ].position += headLean * 0.1f; - _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[BODY_BALL_RIGHT_COLLAR].position += headLean * 0.6f; + _bodyBall[BODY_BALL_RIGHT_SHOULDER].position += headLean * 0.6f; + _bodyBall[BODY_BALL_RIGHT_ELBOW].position += headLean * 0.2f; + _bodyBall[BODY_BALL_RIGHT_WRIST].position += headLean * 0.1f; + _bodyBall[BODY_BALL_RIGHT_FINGERTIPS].position += headLean * 0.0f; } } - _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); + _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); _head.setScale(_scale); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); @@ -326,16 +327,14 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam // Update avatar head rotation with sensor data void MyAvatar::updateFromGyrosAndOrWebcam(bool gyroLook, - float pitchFromTouch) { + float pitchFromTouch) { SerialInterface* gyros = Application::getInstance()->getSerialHeadSensor(); Webcam* webcam = Application::getInstance()->getWebcam(); glm::vec3 estimatedPosition, estimatedRotation; if (gyros->isActive()) { estimatedRotation = gyros->getEstimatedRotation(); - } else if (webcam->isActive()) { estimatedRotation = webcam->getEstimatedRotation(); - } else if (_leadingAvatar) { _head.getFace().clearFrame(); return; @@ -529,13 +528,13 @@ void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { continue; } } - // Always render other people, and render myself when beyond threshold distance + // Always render other people, and render myself when beyond threshold distance if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special if (alpha > 0.0f) { _head.render(alpha); } } else if (alpha > 0.0f) { - // Render the body ball sphere + // Render the body ball sphere if (b == BODY_BALL_RIGHT_ELBOW || b == BODY_BALL_RIGHT_WRIST || b == BODY_BALL_RIGHT_FINGERTIPS ) { @@ -559,18 +558,18 @@ void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { // Render the cone connecting this ball to its parent if (_bodyBall[b].parentBall != BODY_BALL_NULL) { - if ((b != BODY_BALL_HEAD_TOP ) - && (b != BODY_BALL_HEAD_BASE ) - && (b != BODY_BALL_PELVIS ) - && (b != BODY_BALL_TORSO ) - && (b != BODY_BALL_CHEST ) - && (b != BODY_BALL_LEFT_COLLAR ) - && (b != BODY_BALL_LEFT_SHOULDER ) - && (b != BODY_BALL_RIGHT_COLLAR ) - && (b != BODY_BALL_RIGHT_SHOULDER)) { + if ((b != BODY_BALL_HEAD_TOP) + && (b != BODY_BALL_HEAD_BASE) + && (b != BODY_BALL_PELVIS) + && (b != BODY_BALL_TORSO) + && (b != BODY_BALL_CHEST) + && (b != BODY_BALL_LEFT_COLLAR) + && (b != BODY_BALL_LEFT_SHOULDER) + && (b != BODY_BALL_RIGHT_COLLAR) + && (b != BODY_BALL_RIGHT_SHOULDER)) { glColor3fv(DARK_SKIN_COLOR); - float r1 = _bodyBall[_bodyBall[b].parentBall ].radius * 0.8; + float r1 = _bodyBall[_bodyBall[b].parentBall].radius * 0.8; float r2 = _bodyBall[b].radius * 0.8; if (b == BODY_BALL_HEAD_BASE) { r1 *= 0.5f; @@ -611,14 +610,14 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { const float THRUST_JUMP = 120.f; // Add Thrusts from keyboard - if (_driveKeys[FWD ]) {_thrust += _scale * THRUST_MAG_FWD * deltaTime * front;} - if (_driveKeys[BACK ]) {_thrust -= _scale * THRUST_MAG_BACK * deltaTime * front;} - if (_driveKeys[RIGHT ]) {_thrust += _scale * THRUST_MAG_LATERAL * deltaTime * right;} - if (_driveKeys[LEFT ]) {_thrust -= _scale * THRUST_MAG_LATERAL * deltaTime * right;} - if (_driveKeys[UP ]) {_thrust += _scale * THRUST_MAG_UP * deltaTime * up;} - if (_driveKeys[DOWN ]) {_thrust -= _scale * THRUST_MAG_DOWN * deltaTime * up;} - if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} - if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} + if (_driveKeys[FWD]) {_thrust += _scale * THRUST_MAG_FWD * deltaTime * front;} + if (_driveKeys[BACK]) {_thrust -= _scale * THRUST_MAG_BACK * deltaTime * front;} + if (_driveKeys[RIGHT]) {_thrust += _scale * THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[LEFT]) {_thrust -= _scale * THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[UP]) {_thrust += _scale * THRUST_MAG_UP * deltaTime * up;} + if (_driveKeys[DOWN]) {_thrust -= _scale * THRUST_MAG_DOWN * deltaTime * up;} + if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} + if (_driveKeys[ROT_LEFT]) {_bodyYawDelta += YAW_MAG * deltaTime;} // Add one time jumping force if requested if (_shouldJump) { @@ -628,10 +627,10 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { // Add thrusts from leading avatar - const float FOLLOWING_RATE = 0.02f; - const float MIN_YAW = 5.0f; - const float MIN_PITCH = 1.0f; - const float PITCH_RATE = 0.1f; + const float FOLLOWING_RATE = 0.02f; + const float MIN_YAW = 5.0f; + const float MIN_PITCH = 1.0f; + const float PITCH_RATE = 0.1f; const float MIN_YAW_BEFORE_PITCH = 30.0f; if (_leadingAvatar != NULL) { @@ -715,13 +714,13 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov // reset hand and arm positions according to hand movement glm::vec3 right = orientation * IDENTITY_RIGHT; - glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 front = orientation * IDENTITY_FRONT; if (enableHandMovement) { glm::vec3 transformedHandMovement = right * _movedHandOffset.x * 2.0f + - up * -_movedHandOffset.y * 2.0f + + up * -_movedHandOffset.y * 2.0f + front * -_movedHandOffset.y * 2.0f; _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement; @@ -759,7 +758,7 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov _avatarTouch.setYourBodyPosition(_interactingOther->_position); _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); _avatarTouch.setYourOrientation (_interactingOther->getOrientation()); - _avatarTouch.setYourHandState (_interactingOther->_handState); + _avatarTouch.setYourHandState(_interactingOther->_handState); //if hand-holding is initiated by either avatar, turn on hand-holding... if (_avatarTouch.getHandsCloseEnoughToGrasp()) { @@ -779,16 +778,6 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand); - /* - // if my arm can no longer reach the other hand, turn off hand-holding - if (!_avatarTouch.getAbleToReachOtherAvatar()) { - _avatarTouch.setHoldingHands(false); - } - if (distanceBetweenOurHands > _maxArmLength) { - _avatarTouch.setHoldingHands(false); - } - */ - // if neither of us are grasping, turn off hand-holding if ((_handState != HAND_STATE_GRASPING ) && (_interactingOther->_handState != HAND_STATE_GRASPING)) { _avatarTouch.setHoldingHands(false); @@ -796,15 +785,15 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov //if holding hands, apply the appropriate forces if (_avatarTouch.getHoldingHands()) { - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += - ( - _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - ) * 0.5f; + _skeleton.joint[AVATAR_JOINT_RIGHT_FINGERTIPS ].position += + (_interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position + - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position) * 0.5f; + const float MAX_FORCE = 1.0f; + const float FORCE_RATIO = 10.0f; + if (distanceBetweenOurHands > 0.3) { - float force = 10.0f * deltaTime; - if (force > 1.0f) {force = 1.0f;} + float force = min(MAX_FORCE, FORCE_RATIO * deltaTime); _velocity += vectorFromMyHandToYourHand * force; } } @@ -818,8 +807,7 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov for (size_t i = 0; i < getHand().getPalms().size(); ++i) { PalmData& palm = getHand().getPalms()[i]; if (palm.isActive()) { - if (!anyHandsFound - || palm.getRawPosition().x > rightMostHand.x) { + if (!anyHandsFound || palm.getRawPosition().x > rightMostHand.x) { _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition(); rightMostHand = palm.getRawPosition(); } @@ -854,8 +842,8 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime) { const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( - _position - up * (_pelvisFloatingHeight - radius), - _position + up * (_height - _pelvisFloatingHeight + radius), radius, penetration)) { + _position - up * (_pelvisFloatingHeight - radius), + _position + up * (_height - _pelvisFloatingHeight + radius), radius, penetration)) { _lastCollisionPosition = _position; updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); @@ -870,8 +858,8 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime) { const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( - _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), - _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight + radius, 0.0f), radius, penetration)) { + _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), + _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight + radius, 0.0f), radius, penetration)) { _lastCollisionPosition = _position; updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c26670a933..b88b5befcf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -22,28 +22,28 @@ public: void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera); // setters - void setMousePressed (bool mousePressed ) { _mousePressed = mousePressed;} - void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;} - void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; }; - void setVelocity (const glm::vec3 velocity ) { _velocity = velocity; }; - void setLeanScale (float scale ) { _leanScale = scale;} - void setGravity (glm::vec3 gravity); - void setOrientation (const glm::quat& orientation); - void setNewScale (const float scale); - void setWantCollisionsOn (bool wantCollisionsOn ) { _isCollisionsOn = wantCollisionsOn; } + void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; } + void setMovedHandOffset(glm::vec3 movedHandOffset) { _movedHandOffset = movedHandOffset; } + void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } + void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } + void setLeanScale(float scale) { _leanScale = scale; } + void setGravity(glm::vec3 gravity); + void setOrientation(const glm::quat& orientation); + void setNewScale(const float scale); + void setWantCollisionsOn(bool wantCollisionsOn) { _isCollisionsOn = wantCollisionsOn; } // getters - float getNewScale () const { return _newScale;} - float getSpeed () const { return _speed;} - AvatarMode getMode () const { return _mode;} - float getLeanScale () const { return _leanScale;} - float getElapsedTimeStopped () const { return _elapsedTimeStopped;} - float getElapsedTimeMoving () const { return _elapsedTimeMoving;} - float getAbsoluteHeadYaw () const; - const glm::vec3& getMouseRayOrigin () const { return _mouseRayOrigin; } - const glm::vec3& getMouseRayDirection () const { return _mouseRayDirection; } - Avatar* getLeadingAvatar () const { return _leadingAvatar; } - glm::vec3 getGravity () const { return _gravity; } + float getNewScale() const { return _newScale; } + float getSpeed() const { return _speed; } + AvatarMode getMode() const { return _mode; } + float getLeanScale() const { return _leanScale; } + float getElapsedTimeStopped() const { return _elapsedTimeStopped; } + float getElapsedTimeMoving() const { return _elapsedTimeMoving; } + float getAbsoluteHeadYaw() const; + const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } + const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } + Avatar* getLeadingAvatar() const { return _leadingAvatar; } + glm::vec3 getGravity() const { return _gravity; } glm::vec3 getUprightHeadPosition() const; glm::vec3 getUprightEyeLevelPosition() const; @@ -57,21 +57,21 @@ public: glm::vec3 getThrust() { return _thrust; }; private: - bool _mousePressed; - float _bodyPitchDelta; - float _bodyRollDelta; - bool _shouldJump; - int _driveKeys[MAX_DRIVE_KEYS]; - glm::vec3 _gravity; - float _distanceToNearestAvatar; // How close is the nearest avatar? - Avatar* _interactingOther; - float _elapsedTimeMoving; // Timers to drive camera transitions when moving - float _elapsedTimeStopped; - float _elapsedTimeSinceCollision; - glm::vec3 _lastCollisionPosition; - bool _speedBrakes; - bool _isThrustOn; - float _collisionRadius; + bool _mousePressed; + float _bodyPitchDelta; + float _bodyRollDelta; + bool _shouldJump; + int _driveKeys[MAX_DRIVE_KEYS]; + glm::vec3 _gravity; + float _distanceToNearestAvatar; // How close is the nearest avatar? + Avatar* _interactingOther; + float _elapsedTimeMoving; // Timers to drive camera transitions when moving + float _elapsedTimeStopped; + float _elapsedTimeSinceCollision; + glm::vec3 _lastCollisionPosition; + bool _speedBrakes; + bool _isThrustOn; + float _collisionRadius; // private methods float getBallRenderAlpha(int ball, bool lookingInMirror) const; From 3eb0a1a190d32176042bf199346634dcaf269b8f Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Wed, 21 Aug 2013 16:35:16 -0700 Subject: [PATCH 10/12] Magic number removal... --- interface/src/avatar/MyAvatar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ebf275a104..4ab5caf882 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -310,8 +310,9 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCam _head.simulate(deltaTime, true, gyroCameraSensitivity); _hand.simulate(deltaTime, true); + const float WALKING_SPEED_THRESHOLD = 0.2f; // use speed and angular velocity to determine walking vs. standing - if (_speed + fabs(_bodyYawDelta) > 0.2) { + if (_speed + fabs(_bodyYawDelta) > WALKING_SPEED_THRESHOLD) { _mode = AVATAR_MODE_WALKING; } else { _mode = AVATAR_MODE_INTERACTING; From 447d9a65cea2ef9854185462c67dcfa41912bcf6 Mon Sep 17 00:00:00 2001 From: atlante45 Date: Wed, 21 Aug 2013 16:28:32 -0700 Subject: [PATCH 11/12] Fixed only square png import + reduced amount of code --- libraries/voxels/src/SquarePixelMap.cpp | 242 ------------------------ libraries/voxels/src/SquarePixelMap.h | 44 ----- libraries/voxels/src/VoxelTree.cpp | 65 +++++-- 3 files changed, 51 insertions(+), 300 deletions(-) delete mode 100644 libraries/voxels/src/SquarePixelMap.cpp delete mode 100644 libraries/voxels/src/SquarePixelMap.h diff --git a/libraries/voxels/src/SquarePixelMap.cpp b/libraries/voxels/src/SquarePixelMap.cpp deleted file mode 100644 index f37bee4757..0000000000 --- a/libraries/voxels/src/SquarePixelMap.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// -// SquarePixelMap.cpp -// hifi -// -// Created by Tomáš Horáček on 6/25/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#include -#include -#include -#include - -#include "SquarePixelMap.h" - -#define CHILD_COORD_X_IS_1 0x1 -#define CHILD_COORD_Y_IS_1 0x2 -#define ALPHA_CHANNEL_RANGE_FLOAT 256.f -#define ALPHA_CHANNEL_BIT_OFFSET 24 -#define RED_CHANNEL_BIT_OFFSET 16 -#define GREEN_CHANNEL_BIT_OFFSET 8 - -unsigned int numberOfBitsForSize(unsigned int size) { - if (size == 0) { - return 0; - } - - size--; - - unsigned int ans = 1; - while (size >>= 1) { - ans++; - } - return ans; -} - -struct PixelQuadTreeCoordinates { - unsigned int x; - unsigned int y; - unsigned int size; -}; - -class PixelQuadTreeNode { -public: - PixelQuadTreeCoordinates _coord; - uint32_t _color; // undefined value for _allChildrenHasSameColor = false - bool _allChildrenHasSameColor; - uint8_t _minimumNeighbourhoodAplha; - - // 0 x -> 1 - // +---+---+ - // y | 0 | 1 | <- child index - // | +---+---+ - // v | 2 | 3 | - // +---+---+ - // 1 - PixelQuadTreeNode* _children[4]; - - PixelQuadTreeNode(PixelQuadTreeCoordinates coord, SquarePixelMap* pixelMap); - ~PixelQuadTreeNode() { - for (int i = 0; i < 4; i++) { - delete _children[i]; - } - } - -private: - void updateChildCoordinates(int i, PixelQuadTreeCoordinates& childCoord) { - childCoord.x = _coord.x; - childCoord.y = _coord.y; - - if (i & CHILD_COORD_X_IS_1) { - childCoord.x += childCoord.size; - } - if (i & CHILD_COORD_Y_IS_1) { - childCoord.y += childCoord.size; - } - } - - bool hasAllChildrenSameColor() { - return false; //turn off import voxel grouping - - for (int i = 1; i < 4; i++) { - if (!_children[i]->_allChildrenHasSameColor) { - return false; - } - } - - uint32_t firstColor = _children[0]->_color; - - for (int i = 1; i < 4; i++) { - if (firstColor != _children[i]->_color) { - return false; - } - } - return true; - } -}; - -PixelQuadTreeNode::PixelQuadTreeNode(PixelQuadTreeCoordinates coord, SquarePixelMap* pixelMap) : _coord(coord), _minimumNeighbourhoodAplha(-1) { - for (int i = 0; i < 4; i++) { - _children[i] = NULL; - } - - if (_coord.size == 1) { - _color = pixelMap->getPixelAt(_coord.x, _coord.y); - - _minimumNeighbourhoodAplha = std::min(pixelMap->getAlphaAt(_coord.x + 1, _coord.y), _minimumNeighbourhoodAplha); - _minimumNeighbourhoodAplha = std::min(pixelMap->getAlphaAt(_coord.x - 1, _coord.y), _minimumNeighbourhoodAplha); - _minimumNeighbourhoodAplha = std::min(pixelMap->getAlphaAt(_coord.x, _coord.y + 1), _minimumNeighbourhoodAplha); - _minimumNeighbourhoodAplha = std::min(pixelMap->getAlphaAt(_coord.x, _coord.y - 1), _minimumNeighbourhoodAplha); - - _allChildrenHasSameColor = true; - } else { - PixelQuadTreeCoordinates childCoord = PixelQuadTreeCoordinates(); - childCoord.size = _coord.size / 2; - - for (int i = 0; i < 4; i++) { - this->updateChildCoordinates(i, childCoord); - - - if (childCoord.x < pixelMap->dimension() && - childCoord.y < pixelMap->dimension()) { - - _children[i] = new PixelQuadTreeNode(childCoord, pixelMap); - } - } - - if (this->hasAllChildrenSameColor()) { - _allChildrenHasSameColor = true; - _color = _children[0]->_color; - - _minimumNeighbourhoodAplha = _children[0]->_minimumNeighbourhoodAplha; - - for (int i = 0; i < 4; i++) { - _minimumNeighbourhoodAplha = std::min(_children[i]->_minimumNeighbourhoodAplha, _minimumNeighbourhoodAplha); - delete _children[i]; - _children[i] = NULL; - } - } else { - _allChildrenHasSameColor = false; - } - } -} - -SquarePixelMap::SquarePixelMap(const uint32_t* pixels, int dimension) : _rootPixelQuadTreeNode(NULL) { - _data = new SquarePixelMapData(); - _data->dimension = dimension; - _data->reference_counter = 1; - - size_t pixels_size = dimension * dimension; - _data->pixels = new uint32_t[pixels_size]; - memcpy((void*)_data->pixels, (void*)pixels, sizeof(uint32_t) * pixels_size); -} - -SquarePixelMap::SquarePixelMap(const SquarePixelMap& other) { - this->_data = other._data; - this->_data->reference_counter++; -} - -SquarePixelMap::~SquarePixelMap() { - delete _rootPixelQuadTreeNode; - - if (--_data->reference_counter == 0) { - delete _data->pixels; - delete _data; - } -} - -void SquarePixelMap::addVoxelsToVoxelTree(VoxelTree* voxelTree) { - this->generateRootPixelQuadTreeNode(); - this->createVoxelsFromPixelQuadTreeToVoxelTree(_rootPixelQuadTreeNode, voxelTree); -} - -int SquarePixelMap::dimension() { - return _data->dimension; -} - -uint32_t SquarePixelMap::getPixelAt(unsigned int x, unsigned int y) { - return _data->pixels[x + y * _data->dimension]; -} - -uint8_t SquarePixelMap::getAlphaAt(int x, int y) { - int max_coord = this->dimension() - 1; - - if (x < 0 || y < 0 || x > max_coord || y > max_coord) { - return -1; - } - - return this->getPixelAt(x, y) >> ALPHA_CHANNEL_BIT_OFFSET; -} - -void SquarePixelMap::generateRootPixelQuadTreeNode() { - delete _rootPixelQuadTreeNode; - - PixelQuadTreeCoordinates rootNodeCoord = PixelQuadTreeCoordinates(); - rootNodeCoord.size = 1 << numberOfBitsForSize(_data->dimension); - rootNodeCoord.x = rootNodeCoord.y = 0; - - _rootPixelQuadTreeNode = new PixelQuadTreeNode(rootNodeCoord, this); -} - -void SquarePixelMap::createVoxelsFromPixelQuadTreeToVoxelTree(PixelQuadTreeNode* pixelQuadTreeNode, VoxelTree* voxelTree) { - if (pixelQuadTreeNode->_allChildrenHasSameColor) { - VoxelDetail voxel = this->getVoxelDetail(pixelQuadTreeNode); - - unsigned char minimumNeighbourhoodAplha = std::max(0, pixelQuadTreeNode->_minimumNeighbourhoodAplha - 1); - - float minimumNeighbourhoodY = voxel.s * (floor(minimumNeighbourhoodAplha / (ALPHA_CHANNEL_RANGE_FLOAT * voxel.s)) + 0.5); - - do { - voxelTree->createVoxel(voxel.x, voxel.y, voxel.z, voxel.s, voxel.red, voxel.green, voxel.blue, true); - } while ((voxel.y -= voxel.s) > minimumNeighbourhoodY); - } else { - for (int i = 0; i < 4; i++) { - PixelQuadTreeNode* child = pixelQuadTreeNode->_children[i]; - if (child) { - this->createVoxelsFromPixelQuadTreeToVoxelTree(child, voxelTree); - } - } - } -} - -VoxelDetail SquarePixelMap::getVoxelDetail(PixelQuadTreeNode* pixelQuadTreeNode) { - VoxelDetail voxel = VoxelDetail(); - - uint32_t color = pixelQuadTreeNode->_color; - unsigned char alpha = std::max(0, (color >> ALPHA_CHANNEL_BIT_OFFSET) - 1); - - voxel.red = color >> RED_CHANNEL_BIT_OFFSET; - voxel.green = color >> GREEN_CHANNEL_BIT_OFFSET; - voxel.blue = color; - - - float rootSize = _rootPixelQuadTreeNode->_coord.size; - - voxel.s = pixelQuadTreeNode->_coord.size / rootSize; - voxel.y = voxel.s * (floor(alpha / (ALPHA_CHANNEL_RANGE_FLOAT * voxel.s)) + 0.5); - voxel.x = pixelQuadTreeNode->_coord.x / rootSize + voxel.s / 2; - voxel.z = pixelQuadTreeNode->_coord.y / rootSize + voxel.s / 2; - - return voxel; -} diff --git a/libraries/voxels/src/SquarePixelMap.h b/libraries/voxels/src/SquarePixelMap.h deleted file mode 100644 index 0ef6dc55ee..0000000000 --- a/libraries/voxels/src/SquarePixelMap.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// SquarePixelMap.h -// hifi -// -// Created by Tomáš Horáček on 6/25/13. -// -// - -#ifndef __hifi__SquarePixelMap__ -#define __hifi__SquarePixelMap__ - -#include -#include "VoxelTree.h" -#include "SharedUtil.h" - -class PixelQuadTreeNode; - -struct SquarePixelMapData { - const uint32_t* pixels; - int dimension; - int reference_counter; -}; - -class SquarePixelMap { -public: - SquarePixelMap(const uint32_t* pixels, int dimension); - SquarePixelMap(const SquarePixelMap& other); - ~SquarePixelMap(); - - void addVoxelsToVoxelTree(VoxelTree* voxelTree); - - int dimension(); - uint32_t getPixelAt(unsigned int x, unsigned int y); - uint8_t getAlphaAt(int x, int y); -private: - SquarePixelMapData* _data; - PixelQuadTreeNode* _rootPixelQuadTreeNode; - - void generateRootPixelQuadTreeNode(); - void createVoxelsFromPixelQuadTreeToVoxelTree(PixelQuadTreeNode* pixelQuadTreeNode, VoxelTree* voxelTree); - VoxelDetail getVoxelDetail(PixelQuadTreeNode* pixelQuadTreeNode); -}; - -#endif /* defined(__hifi__SquarePixelMap__) */ diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 124d2f7fa6..404659de2c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "CoverageMap.h" #include "GeometryUtil.h" @@ -1587,25 +1588,61 @@ bool VoxelTree::readFromSVOFile(const char* fileName) { } bool VoxelTree::readFromSquareARGB32Pixels(const char* filename) { - QImage pngImage = QImage(filename); - if (pngImage.height() != pngImage.width()) { - qDebug("ERROR: Bad PNG size: height != width.\n"); - return false; - } - emit importSize(1.0f, 1.0f, 1.0f); emit importProgress(0); - const uint32_t* pixels; - if (pngImage.format() == QImage::Format_ARGB32) { - pixels = reinterpret_cast(pngImage.constBits()); - } else { - QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32); - pixels = reinterpret_cast(tmp.constBits()); + int minAlpha = 256; + + QImage pngImage = QImage(filename); + + for (int x = 0; x < pngImage.width() * pngImage.height(); ++x) { + minAlpha = std::min(qAlpha(pngImage.color(x)) , minAlpha); } - SquarePixelMap pixelMap = SquarePixelMap(pixels, pngImage.height()); - pixelMap.addVoxelsToVoxelTree(this); + int maxSize = std::max(pngImage.width(), pngImage.height()); + + int scale = 1; + while (maxSize > scale) {scale *= 2;} + float size = 1.0f / scale; + + QRgb pixel; + int minNeighborhoodAlpha; + + for (int i = 0; i < pngImage.width(); ++i) { + for (int j = 0; j < pngImage.height(); ++j) { + emit importProgress((100 * (i * pngImage.height() + j)) / + (pngImage.width() * pngImage.height())); + + pixel = pngImage.pixel(i, j); + minNeighborhoodAlpha = qAlpha(pixel) - 1; + + if (i != 0) { + minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i - 1, j))); + } + if (j != 0) { + minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i, j - 1))); + } + if (i < pngImage.width() - 1) { + minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i + 1, j))); + } + if (j < pngImage.height() - 1) { + minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i, j + 1))); + } + + while (qAlpha(pixel) > minNeighborhoodAlpha) { + ++minNeighborhoodAlpha; + createVoxel(i * size, + (minNeighborhoodAlpha - minAlpha) * size, + j * size, + size, + qRed(pixel), + qGreen(pixel), + qBlue(pixel), + true); + } + + } + } emit importProgress(100); return true; From 12459079e9ec8469bed6e195a30a3952196d2361 Mon Sep 17 00:00:00 2001 From: atlante45 Date: Wed, 21 Aug 2013 16:41:24 -0700 Subject: [PATCH 12/12] Fixed magic number --- libraries/voxels/src/VoxelTree.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 404659de2c..d46833284c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -26,7 +26,6 @@ #include "OctalCode.h" #include "PacketHeaders.h" #include "SharedUtil.h" -#include "SquarePixelMap.h" #include "Tags.h" #include "ViewFrustum.h" #include "VoxelConstants.h" @@ -1591,7 +1590,7 @@ bool VoxelTree::readFromSquareARGB32Pixels(const char* filename) { emit importSize(1.0f, 1.0f, 1.0f); emit importProgress(0); - int minAlpha = 256; + int minAlpha = INT_MAX; QImage pngImage = QImage(filename);