// // Camera.cpp // interface // // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include #include #include // #include "Log.h" #include "Camera.h" const float CAMERA_MINIMUM_MODE_SHIFT_RATE = 0.5f; const float CAMERA_FIRST_PERSON_MODE_UP_SHIFT = 0.0f; const float CAMERA_FIRST_PERSON_MODE_DISTANCE = 0.0f; const float CAMERA_FIRST_PERSON_MODE_TIGHTNESS = 100.0f; const float CAMERA_THIRD_PERSON_MODE_UP_SHIFT = -0.2f; const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f; const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f; const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f; const float CAMERA_MIRROR_MODE_DISTANCE = 0.2f; const float CAMERA_MIRROR_MODE_TIGHTNESS = 100.0f; Camera::Camera() { _needsToInitialize = true; _frustumNeedsReshape = true; _modeShift = 0.0f; _modeShiftRate = 1.0f; _linearModeShift = 0.0f; _mode = CAMERA_MODE_THIRD_PERSON; _tightness = 10.0f; // default _fieldOfView = 60.0f; // default _nearClip = 0.08f; // default _farClip = 50.0f * TREE_SCALE; // default _yaw = 0.0f; _pitch = 0.0f; _roll = 0.0f; _upShift = 0.0f; _distance = 0.0f; _previousUpShift = 0.0f; _previousDistance = 0.0f; _previousTightness = 0.0f; _newUpShift = 0.0f; _newDistance = 0.0f; _newTightness = 0.0f; _idealYaw = 0.0f; _idealPitch = 0.0f; _idealRoll = 0.0f; _targetPosition = glm::vec3(0.0f, 0.0f, 0.0f); _position = glm::vec3(0.0f, 0.0f, 0.0f); _idealPosition = glm::vec3(0.0f, 0.0f, 0.0f); _orientation.setToIdentity(); } void Camera::update(float deltaTime) { if (_mode != CAMERA_MODE_NULL) { // use iterative forces to push the camera towards the target position and angle updateFollowMode(deltaTime); } // do this AFTER making any changes to yaw pitch and roll.... generateOrientation(); } // generate the ortho-normals for the orientation based on the three Euler angles void Camera::generateOrientation() { _orientation.setToIdentity(); _orientation.pitch(_pitch); _orientation.yaw (_yaw ); _orientation.roll (_roll ); } // use iterative forces to keep the camera at the desired position and angle void Camera::updateFollowMode(float deltaTime) { if (_linearModeShift < 1.0f) { _linearModeShift += _modeShiftRate * deltaTime; _modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PIE ); _upShift = _previousUpShift * (1.0f - _modeShift) + _newUpShift * _modeShift; _distance = _previousDistance * (1.0f - _modeShift) + _newDistance * _modeShift; _tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift; if (_linearModeShift > 1.0f ) { _linearModeShift = 1.0f; _modeShift = 1.0f; _upShift = _newUpShift; _distance = _newDistance; _tightness = _newTightness; } } // derive t from tightness float t = _tightness * _modeShift * deltaTime; if (t > 1.0) { t = 1.0; } // update Euler angles (before position!) if (_needsToInitialize || OculusManager::isConnected()) { _yaw = _idealYaw; _pitch = _idealPitch; _roll = _idealRoll; } else { // pull Euler angles towards ideal Euler angles _yaw += (_idealYaw - _yaw ) * t; _pitch += (_idealPitch - _pitch) * t; _roll += (_idealRoll - _roll ) * t; } float radian = (_yaw / 180.0) * PIE; // update _position double x = -_distance * sin(radian); double z = -_distance * cos(radian); double y = _upShift; _idealPosition = _targetPosition + glm::vec3(x, y, z); if (_needsToInitialize) { _position = _idealPosition; _needsToInitialize = false; } else { // force position towards ideal position _position += (_idealPosition - _position) * t; } } void Camera::setModeShiftRate ( float rate ) { _modeShiftRate = rate; if (_modeShiftRate < CAMERA_MINIMUM_MODE_SHIFT_RATE ) { _modeShiftRate = CAMERA_MINIMUM_MODE_SHIFT_RATE; } } void Camera::setMode(CameraMode m) { _mode = m; _modeShift = 0.0; _linearModeShift = 0.0; _previousUpShift = _upShift; _previousDistance = _distance; _previousTightness = _tightness; if (_mode == CAMERA_MODE_THIRD_PERSON) { _newUpShift = CAMERA_THIRD_PERSON_MODE_UP_SHIFT; _newDistance = CAMERA_THIRD_PERSON_MODE_DISTANCE; _newTightness = CAMERA_THIRD_PERSON_MODE_TIGHTNESS; } else if (_mode == CAMERA_MODE_FIRST_PERSON) { _newUpShift = CAMERA_FIRST_PERSON_MODE_UP_SHIFT; _newDistance = CAMERA_FIRST_PERSON_MODE_DISTANCE; _newTightness = CAMERA_FIRST_PERSON_MODE_TIGHTNESS; } else if (_mode == CAMERA_MODE_MIRROR) { _newUpShift = CAMERA_MIRROR_MODE_UP_SHIFT; _newDistance = CAMERA_MIRROR_MODE_DISTANCE; _newTightness = CAMERA_MIRROR_MODE_TIGHTNESS; } } void Camera::setTargetRotation( float yaw, float pitch, float roll ) { _idealYaw = yaw; _idealPitch = pitch; _idealRoll = roll; } void Camera::setFieldOfView(float f) { _fieldOfView = f; _frustumNeedsReshape = true; } void Camera::setAspectRatio(float a) { _aspectRatio = a; _frustumNeedsReshape = true; } void Camera::setNearClip (float n) { _nearClip = n; _frustumNeedsReshape = true; } void Camera::setFarClip (float f) { _farClip = f; _frustumNeedsReshape = true; } void Camera::setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; _frustumNeedsReshape = true; } void Camera::setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; _frustumNeedsReshape = true; } void Camera::initialize() { _needsToInitialize = true; _modeShift = 0.0; } // call to find out if the view frustum needs to be reshaped bool Camera::getFrustumNeedsReshape() { return _frustumNeedsReshape; } // call this after reshaping the view frustum void Camera::setFrustumWasReshaped() { _frustumNeedsReshape = false; }