diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index bceb276a8a..d9d1f37722 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -244,7 +244,6 @@ static void renderMovingBug() { } - float intensity = 0.5f; float intensityIncrement = 0.1f; const float MAX_INTENSITY = 1.0f; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e69e40f527..9b39c6508d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -62,8 +62,6 @@ using namespace std; -const bool TESTING_AVATAR_TOUCH = false; - // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; @@ -510,6 +508,9 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_E: + if (!_myAvatar.getDriveKeys(UP)) { + _myAvatar.jump(); + } _myAvatar.setDriveKeys(UP, 1); break; @@ -720,6 +721,9 @@ void Application::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { _mouseX = event->x(); _mouseY = event->y(); + _mouseDragStartedX = _mouseX; + _mouseDragStartedY = _mouseY; + _mouseVoxelDragging = _mouseVoxel; _mousePressed = true; maybeEditVoxelUnderCursor(); @@ -1012,6 +1016,12 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { } } +const glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel) { + return glm::vec3((_mouseVoxel.x + _mouseVoxel.s / 2.f) * TREE_SCALE, + (_mouseVoxel.y + _mouseVoxel.s / 2.f) * TREE_SCALE, + (_mouseVoxel.z + _mouseVoxel.s / 2.f) * TREE_SCALE); +} + void Application::decreaseVoxelSize() { _mouseVoxelScale /= 2; } @@ -1221,7 +1231,7 @@ void Application::initMenu() { (_gyroLook = optionsMenu->addAction("Gyro Look"))->setCheckable(true); _gyroLook->setChecked(false); (_mouseLook = optionsMenu->addAction("Mouse Look"))->setCheckable(true); - _mouseLook->setChecked(false); + _mouseLook->setChecked(true); (_showHeadMouse = optionsMenu->addAction("Head Mouse"))->setCheckable(true); _showHeadMouse->setChecked(false); (_transmitterDrives = optionsMenu->addAction("Transmitter Drive"))->setCheckable(true); @@ -1245,7 +1255,6 @@ void Application::initMenu() { _renderAtmosphereOn->setShortcut(Qt::SHIFT | Qt::Key_A); (_renderGroundPlaneOn = renderMenu->addAction("Ground Plane"))->setCheckable(true); _renderGroundPlaneOn->setChecked(true); - _renderGroundPlaneOn->setShortcut(Qt::SHIFT | Qt::Key_G); (_renderAvatarsOn = renderMenu->addAction("Avatars"))->setCheckable(true); _renderAvatarsOn->setChecked(true); (_renderAvatarBalls = renderMenu->addAction("Avatar as Balls"))->setCheckable(true); @@ -1441,6 +1450,26 @@ void Application::update(float deltaTime) { // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); + // If we are dragging on a voxel, add thrust according to the amount the mouse is dragging + const float VOXEL_GRAB_THRUST = 5.0f; + if (_mousePressed && (_mouseVoxel.s != 0)) { + glm::vec2 mouseDrag(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY); + glm::quat orientation = _myAvatar.getOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 towardVoxel = getMouseVoxelWorldCoordinates(_mouseVoxelDragging) + - _myAvatar.getCameraPosition(); + towardVoxel = front * glm::length(towardVoxel); + glm::vec3 lateralToVoxel = glm::cross(up, glm::normalize(towardVoxel)) * glm::length(towardVoxel); + _voxelThrust = glm::vec3(0, 0, 0); + _voxelThrust += towardVoxel * VOXEL_GRAB_THRUST * deltaTime * mouseDrag.y; + _voxelThrust += lateralToVoxel * VOXEL_GRAB_THRUST * deltaTime * mouseDrag.x; + + // Add thrust from voxel grabbing to the avatar + _myAvatar.addThrust(_voxelThrust); + + } + _mouseVoxel.s = 0.0f; if (checkedVoxelModeAction() != 0 && (fabs(_myAvatar.getVelocity().x) + @@ -1569,30 +1598,27 @@ void Application::update(float deltaTime) { _myAvatar.simulate(deltaTime, NULL); } - if (TESTING_AVATAR_TOUCH) { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); - } - } else { if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { if (_manualFirstPerson->isChecked()) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); } - } else { - if (_myAvatar.getIsNearInteractingOther()) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { - _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _myCamera.setModeShiftRate(1.0f); - } - } else { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); - } + } else { + const float THIRD_PERSON_SHIFT_VELOCITY = 2.0f; + const float TIME_BEFORE_SHIFT_INTO_FIRST_PERSON = 0.75f; + const float TIME_BEFORE_SHIFT_INTO_THIRD_PERSON = 0.1f; + + if ((_myAvatar.getElapsedTimeStopped() > TIME_BEFORE_SHIFT_INTO_FIRST_PERSON) + && (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON)) { + _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); + _myCamera.setModeShiftRate(1.0f); } + if ((_myAvatar.getSpeed() > THIRD_PERSON_SHIFT_VELOCITY) + && (_myAvatar.getElapsedTimeMoving() > TIME_BEFORE_SHIFT_INTO_THIRD_PERSON) + && (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON)) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1000.0f); } } } @@ -1960,6 +1986,10 @@ void Application::displaySide(Camera& whichCamera) { glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); + // Enable to show line from me to the voxel I am touching + //renderLineToTouchedVoxel(); + //renderThrustAtVoxel(_voxelThrust); + // draw a red sphere float sphereRadius = 0.25f; glColor3f(1,0,0); @@ -2175,6 +2205,32 @@ void Application::displayStats() { } } +void Application::renderThrustAtVoxel(const glm::vec3& thrust) { + if (_mousePressed) { + glColor3f(1, 0, 0); + glLineWidth(2.0f); + glBegin(GL_LINES); + glm::vec3 voxelTouched = getMouseVoxelWorldCoordinates(_mouseVoxelDragging); + glVertex3f(voxelTouched.x, voxelTouched.y, voxelTouched.z); + glVertex3f(voxelTouched.x + thrust.x, voxelTouched.y + thrust.y, voxelTouched.z + thrust.z); + glEnd(); + } + +} +void Application::renderLineToTouchedVoxel() { + // Draw a teal line to the voxel I am currently dragging on + if (_mousePressed) { + glColor3f(0, 1, 1); + glLineWidth(2.0f); + glBegin(GL_LINES); + glm::vec3 voxelTouched = getMouseVoxelWorldCoordinates(_mouseVoxelDragging); + glVertex3f(voxelTouched.x, voxelTouched.y, voxelTouched.z); + glm::vec3 headPosition = _myAvatar.getHeadJointPosition(); + glVertex3fv(&headPosition.x); + glEnd(); + } +} + ///////////////////////////////////////////////////////////////////////////////////// // renderViewFrustum() // @@ -2451,6 +2507,8 @@ void Application::resetSensors() { QCursor::setPos(_headMouseX, _headMouseY); _myAvatar.reset(); _myTransmitter.resetLevels(); + _myAvatar.setVelocity(glm::vec3(0,0,0)); + _myAvatar.setThrust(glm::vec3(0,0,0)); } static void setShortcutsEnabled(QWidget* widget, bool enabled) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 062954a4b7..1d50b5065f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -67,6 +67,8 @@ public: void wheelEvent(QWheelEvent* event); + const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); + Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } @@ -93,6 +95,9 @@ private slots: void setRenderFirstPerson(bool firstPerson); + void renderThrustAtVoxel(const glm::vec3& thrust); + void renderLineToTouchedVoxel(); + void setFrustumOffset(bool frustumOffset); void cycleFrustumRenderMode(); @@ -141,7 +146,7 @@ private: void displayStats(); void renderViewFrustum(ViewFrustum& viewFrustum); - + void setupPaintingVoxel(); void shiftPaintingColor(); void maybeEditVoxelUnderCursor(); @@ -256,7 +261,12 @@ private: int _mouseX; int _mouseY; + int _mouseDragStartedX; + int _mouseDragStartedY; + VoxelDetail _mouseVoxelDragging; + glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) + VoxelDetail _mouseVoxel; // details of the voxel under the mouse cursor float _mouseVoxelScale; // the scale for adding/removing voxels diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 771ce8e7e5..a2ff33ca52 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -77,6 +77,7 @@ Avatar::Avatar(Agent* owningAgent) : _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), @@ -89,6 +90,9 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _isMouseTurningRight(false), + _elapsedTimeMoving(0.0f), + _elapsedTimeStopped(0.0f), + _elapsedTimeSinceCollision(0.0f), _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -316,40 +320,128 @@ glm::vec3 Avatar::getUprightHeadPosition() const { void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { // Update head yaw and pitch based on mouse input - const float MOUSE_MOVE_RADIUS = 0.3f; - const float MOUSE_ROTATE_SPEED = 4.0f; - const float MOUSE_PITCH_SPEED = 2.0f; + const float MOUSE_ROTATE_SPEED = 0.01f; + const float MOUSE_PITCH_SPEED = 0.02f; const int TITLE_BAR_HEIGHT = 46; - float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f; - float mouseLocationY = (float)mouseY / (float)screenHeight - 0.5f; if ((mouseX > 1) && (mouseX < screenWidth) && (mouseY > TITLE_BAR_HEIGHT) && (mouseY < screenHeight)) { // // Mouse must be inside screen (not at edge) and not on title bar for movement to happen // - if (mouseLocationX > MOUSE_MOVE_RADIUS) { - _head.addYaw(-(mouseLocationX - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED); - } else if (mouseLocationX < -MOUSE_MOVE_RADIUS) { - _head.addYaw(-(mouseLocationX + MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED); - } - if (mouseLocationY > MOUSE_MOVE_RADIUS) { - _head.addPitch(-(mouseLocationY - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED); - } else if (mouseLocationY < -MOUSE_MOVE_RADIUS) { - _head.addPitch(-(mouseLocationY + MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED); + int pixelMoveThreshold = screenWidth / 6; + glm::vec2 mouseVector(mouseX - (screenWidth / 2), mouseY - (screenHeight / 2)); + if (glm::length(mouseVector) > pixelMoveThreshold) { + mouseVector -= glm::normalize(mouseVector) * (float) pixelMoveThreshold; + _head.addYaw(-mouseVector.x * MOUSE_ROTATE_SPEED); + _head.addPitch(-mouseVector.y * MOUSE_PITCH_SPEED); } } - return; } +void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) { + // + // Gather thrust information from keyboard and sensors to apply to avatar motion + // + glm::quat orientation = getOrientation(); + 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 = 200.f; + const float THRUST_MAG_FWD = 300.f; + const float THRUST_MAG_BACK = 150.f; + const float THRUST_MAG_LATERAL = 200.f; + const float THRUST_JUMP = 120.f; + + // Add Thrusts from keyboard + if (_driveKeys[FWD ]) {_thrust += THRUST_MAG_FWD * deltaTime * front;} + if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG_BACK * deltaTime * front;} + if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[LEFT ]) {_thrust -= THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[UP ]) {_thrust += THRUST_MAG_UP * deltaTime * up;} + if (_driveKeys[DOWN ]) {_thrust -= 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 += THRUST_JUMP * up; + _shouldJump = false; + } + + // 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; + } + } +} + void Avatar::simulate(float deltaTime, Transmitter* transmitter) { - //figure out if the mouse cursor is over any body spheres... - checkForMouseRayTouching(); + glm::quat orientation = getOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + + // Update movement timers + if (!_owningAgent) { + _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; + } + } + + // Collect thrust forces from keyboard and devices + if (!_owningAgent) { + updateThrust(deltaTime, transmitter); + } // copy velocity so we can use it later for acceleration glm::vec3 oldVelocity = getVelocity(); + if (!_owningAgent) { + // update position by velocity + _position += _velocity * deltaTime; + + // calculate speed + _speed = glm::length(_velocity); + } + + //figure out if the mouse cursor is over any body spheres... + if (!_owningAgent) { + checkForMouseRayTouching(); + } + // update balls if (_balls) { _balls->simulate(deltaTime); } @@ -391,12 +483,13 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { //update the movement of the hand and process handshaking with other avatars... updateHandMovementAndTouching(deltaTime); - _avatarTouch.simulate(deltaTime); // apply gravity and collision with the ground/floor if (!_owningAgent && USING_AVATAR_GRAVITY) { _velocity += _gravity * (GRAVITY_EARTH * deltaTime); + } + if (!_owningAgent) { updateCollisionWithEnvironment(); } @@ -413,57 +506,11 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { updateCollisionWithVoxels(); } - glm::quat orientation = getOrientation(); - glm::vec3 front = orientation * IDENTITY_FRONT; - glm::vec3 right = orientation * IDENTITY_RIGHT; - glm::vec3 up = orientation * IDENTITY_UP; - - // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) - const float THRUST_MAG = 600.0f; - if (!_owningAgent) { - - _thrust = glm::vec3(0.0f, 0.0f, 0.0f); - - // Add Thrusts from keyboard - if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * front;} - if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * front;} - if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG * deltaTime * right;} - if (_driveKeys[LEFT ]) {_thrust -= THRUST_MAG * deltaTime * right;} - if (_driveKeys[UP ]) {_thrust += THRUST_MAG * deltaTime * up;} - if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG * deltaTime * up;} - if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} - if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} - - // 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 = 25.f; - const float TRANSMITTER_FWD_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 += THRUST_MAG * - (float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF * - TRANSMITTER_LIFT_SCALE * - deltaTime * - up; - } - } - + + // 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)); @@ -475,12 +522,22 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _bodyYawDelta *= bodySpinMomentum; _bodyRollDelta *= bodySpinMomentum; - // add thrust to velocity - _velocity += _thrust * deltaTime; - - // calculate speed - _speed = glm::length(_velocity); - + // Decay velocity. If velocity is really low, increase decay to simulate static friction + const float VELOCITY_DECAY_UNDER_THRUST = 0.2; + const float VELOCITY_FAST_DECAY = 0.6; + const float VELOCITY_SLOW_DECAY = 3.0; + const float VELOCITY_FAST_THRESHOLD = 2.0f; + float decayConstant, decay; + if (glm::length(_thrust) > 0.f) { + decayConstant = VELOCITY_DECAY_UNDER_THRUST; + } else if (glm::length(_velocity) > VELOCITY_FAST_THRESHOLD) { + decayConstant = VELOCITY_FAST_DECAY; + } else { + decayConstant = VELOCITY_SLOW_DECAY; + } + decay = glm::clamp(1.0f - decayConstant * deltaTime, 0.0f, 1.0f); + _velocity *= decay; + //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; @@ -500,29 +557,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { //the following will be used to make the avatar upright no matter what gravity is setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation); - // update position by velocity - _position += _velocity * deltaTime; - - // decay velocity - const float VELOCITY_DECAY = 0.9; - float decay = 1.0 - VELOCITY_DECAY * deltaTime; - if ( decay < 0.0 ) { - _velocity = glm::vec3( 0.0f, 0.0f, 0.0f ); - } else { - _velocity *= decay; - } - - // If another avatar is near, dampen velocity as a function of closeness - if (_distanceToNearestAvatar < PERIPERSONAL_RADIUS) { - float closeness = 1.0f - (_distanceToNearestAvatar / PERIPERSONAL_RADIUS); - float drag = 1.0f - closeness * AVATAR_BRAKING_STRENGTH * deltaTime; - if ( drag > 0.0f ) { - _velocity *= drag; - } else { - _velocity = glm::vec3( 0.0f, 0.0f, 0.0f ); - } - } - // Compute instantaneous acceleration float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; const float ACCELERATION_PITCH_DECAY = 0.4f; @@ -602,6 +636,10 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } else { _mode = AVATAR_MODE_INTERACTING; } + + // Zero thrust out now that we've added it to velocity in this frame + _thrust = glm::vec3(0, 0, 0); + } void Avatar::checkForMouseRayTouching() { @@ -782,41 +820,52 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } void Avatar::updateCollisionWithEnvironment() { + glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; + const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; + const float ENVIRONMENT_SURFACE_DAMPING = 0.01; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { - applyCollisionWithScene(penetration); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); } } + void Avatar::updateCollisionWithVoxels() { float radius = _height * 0.125f; + const float VOXEL_ELASTICITY = 1.4f; + const float VOXEL_DAMPING = 0.0; 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)) { - applyCollisionWithScene(penetration); + applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } -void Avatar::applyCollisionWithScene(const glm::vec3& penetration) { +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 STATIC_FRICTION_VELOCITY = 0.15f; - static float STATIC_FRICTION_DAMPING = 0.0f; - static float KINETIC_FRICTION_DAMPING = 0.95f; - + 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; - _velocity *= KINETIC_FRICTION_DAMPING; - // If velocity is quite low, apply static friction that takes away energy - if (glm::length(_velocity) < STATIC_FRICTION_VELOCITY) { - _velocity *= STATIC_FRICTION_DAMPING; + _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; } } } @@ -839,7 +888,6 @@ void Avatar::updateAvatarCollisions(float deltaTime) { // 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(); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 34483b6d93..db4f4dd7a6 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -85,6 +85,7 @@ public: void init(); void reset(); void simulate(float deltaTime, Transmitter* transmitter); + void updateThrust(float deltaTime, Transmitter * transmitter); void updateHeadFromGyros(float frametime, SerialInterface * serialInterface); void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight); void addBodyYaw(float y) {_bodyYaw += y;}; @@ -96,6 +97,7 @@ public: 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); @@ -117,6 +119,9 @@ public: 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;} float getAbsoluteHeadYaw () const; float getAbsoluteHeadPitch () const; Head& getHead () {return _head; } @@ -130,6 +135,7 @@ public: // 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; }; @@ -182,6 +188,7 @@ private: glm::vec3 _handHoldingPosition; glm::vec3 _velocity; glm::vec3 _thrust; + bool _shouldJump; float _speed; float _maxArmLength; float _leanScale; @@ -192,13 +199,16 @@ private: float _height; Balls* _balls; AvatarTouch _avatarTouch; - float _distanceToNearestAvatar; // How close is the nearest avatar? + 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; AvatarVoxelSystem _voxels; @@ -218,7 +228,7 @@ private: void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); void updateCollisionWithEnvironment(); void updateCollisionWithVoxels(); - void applyCollisionWithScene(const glm::vec3& penetration); + void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); diff --git a/interface/src/Transmitter.cpp b/interface/src/Transmitter.cpp index a02e864087..8cbb4a5c29 100644 --- a/interface/src/Transmitter.cpp +++ b/interface/src/Transmitter.cpp @@ -70,9 +70,7 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) { // Update estimated absolute position from rotation rates _estimatedRotation += _lastRotationRate * DELTA_TIME; - - printf("The accel %f, %f, %f\n", _lastAcceleration.x, _lastAcceleration.y, _lastAcceleration.z); - + // Sensor Fusion! Slowly adjust estimated rotation to be relative to gravity (average acceleration) const float GRAVITY_FOLLOW_RATE = 1.f; float rollAngle = angleBetween(glm::vec3(_lastAcceleration.x, _lastAcceleration.y, 0.f), glm::vec3(0,-1,0)) * diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 8f71ef64f1..4aa64f019e 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -103,8 +103,8 @@ public: void setColor(const nodeColor& color); const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _currentColor; }; - void setDensity(const float density) { _density = density; }; - const float getDensity() const { return _density; }; + void setDensity(float density) { _density = density; }; + float getDensity() const { return _density; }; #else void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ }; void setFalseColored(bool isFalseColored) { /* no op */ };