326 lines · 10.3 KB · C++
RawDownload
////  Camera.cpp//  interface/src////  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <glm/gtx/quaternion.hpp> #include <SharedUtil.h>#include <VoxelConstants.h>#include <EventTypes.h> #include "Application.h"#include "Camera.h"#include "Menu.h"#include "Util.h"#include "devices/OculusManager.h" 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_INDEPENDENT_MODE_UP_SHIFT  = 0.0f;const float CAMERA_INDEPENDENT_MODE_DISTANCE  = 0.0f;const float CAMERA_INDEPENDENT_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.17f;const float CAMERA_MIRROR_MODE_TIGHTNESS       = 100.0f;  Camera::Camera() :     _needsToInitialize(true),    _mode(CAMERA_MODE_THIRD_PERSON),    _prevMode(CAMERA_MODE_THIRD_PERSON),    _frustumNeedsReshape(true),    _position(0.0f, 0.0f, 0.0f),    _idealPosition(0.0f, 0.0f, 0.0f),    _targetPosition(0.0f, 0.0f, 0.0f),    _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),    _aspectRatio(16.0f/9.0f),    _nearClip(0.08f), // default    _farClip(50.0f * TREE_SCALE), // default    _upShift(0.0f),    _distance(0.0f),    _tightness(10.0f), // default    _previousUpShift(0.0f),    _previousDistance(0.0f),    _previousTightness(0.0f),    _newUpShift(0.0f),    _newDistance(0.0f),    _newTightness(0.0f),    _modeShift(1.0f),    _linearModeShift(0.0f),    _modeShiftPeriod(1.0f),    _scale(1.0f),    _lookingAt(0.0f, 0.0f, 0.0f),    _isKeepLookingAt(false){} 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);     }} // use iterative forces to keep the camera at the desired position and anglevoid Camera::updateFollowMode(float deltaTime) {      if (_linearModeShift < 1.0f) {        _linearModeShift += deltaTime / _modeShiftPeriod;        if (_needsToInitialize || _linearModeShift > 1.0f) {            _linearModeShift = 1.0f;            _modeShift = 1.0f;            _upShift   = _newUpShift;            _distance  = _newDistance;            _tightness = _newTightness;        } else {            _modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PI );            _upShift   = _previousUpShift   * (1.0f - _modeShift) + _newUpShift   * _modeShift;            _distance  = _previousDistance  * (1.0f - _modeShift) + _newDistance  * _modeShift;            _tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift;        }    }     // derive t from tightness    float t = _tightness * _modeShift * deltaTime;	    if (t > 1.0f) {        t = 1.0f;    }        // handle keepLookingAt    if (_isKeepLookingAt) {        lookAt(_lookingAt);    }        // Update position and rotation, setting directly if tightness is 0.0    if (_needsToInitialize || (_tightness == 0.0f)) {        _rotation = _targetRotation;        _idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));        _position = _idealPosition;        _needsToInitialize = false;    } else {        // pull rotation towards ideal        _rotation = safeMix(_rotation, _targetRotation, t);        _idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));        _position += (_idealPosition - _position) * t;    }} float Camera::getFarClip() const {    return (_scale * _farClip < std::numeric_limits<int16_t>::max())            ? _scale * _farClip            : std::numeric_limits<int16_t>::max() - 1;} void Camera::setModeShiftPeriod (float period) {    const float MIN_PERIOD = 0.001f;    const float MAX_PERIOD = 3.0f;    _modeShiftPeriod = glm::clamp(period, MIN_PERIOD, MAX_PERIOD);        // if a zero period was requested, we clearly want to snap immediately to the target    if (period == 0.0f) {        update(MAX_PERIOD);    }} void Camera::setMode(CameraMode m) {      _prevMode = _mode;    _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;    } else if (_mode == CAMERA_MODE_INDEPENDENT) {        _newUpShift   = CAMERA_INDEPENDENT_MODE_UP_SHIFT;        _newDistance  = CAMERA_INDEPENDENT_MODE_DISTANCE;        _newTightness = CAMERA_INDEPENDENT_MODE_TIGHTNESS;            }} void Camera::setTargetPosition(const glm::vec3& t) {     _targetPosition = t;      // handle keepLookingAt    if (_isKeepLookingAt) {        lookAt(_lookingAt);    }    } void Camera::setTargetRotation( const glm::quat& targetRotation ) {    _targetRotation = targetRotation;} 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::setScale(float s) {    _scale = s;    _needsToInitialize = true;    _frustumNeedsReshape = true;} void Camera::initialize() {    _needsToInitialize = true;    _modeShift = 0.0;} // call to find out if the view frustum needs to be reshapedbool Camera::getFrustumNeedsReshape() const {    return _frustumNeedsReshape;} // call this when deciding whether to render the head or notCameraMode Camera::getInterpolatedMode() const {    const float SHIFT_THRESHOLD_INTO_FIRST_PERSON = 0.7f;    const float SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON = 0.6f;    if ((_mode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_INTO_FIRST_PERSON) ||        (_prevMode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON)) {        return _prevMode;    }    return _mode;} // call this after reshaping the view frustumvoid Camera::setFrustumWasReshaped() {    _frustumNeedsReshape = false;} void Camera::lookAt(const glm::vec3& lookAt) {    glm::vec3 up = IDENTITY_UP;    glm::mat4 lookAtMatrix = glm::lookAt(_targetPosition, lookAt, up);    glm::quat rotation = glm::quat_cast(lookAtMatrix);    rotation.w = -rotation.w; // Rosedale approved    setTargetRotation(rotation);} void Camera::keepLookingAt(const glm::vec3& point) {    lookAt(point);    _isKeepLookingAt = true;    _lookingAt = point;} CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* viewFrustum) :    _camera(camera), _viewFrustum(viewFrustum) {} PickRay CameraScriptableObject::computePickRay(float x, float y) {    float screenWidth = Application::getInstance()->getGLWidget()->width();    float screenHeight = Application::getInstance()->getGLWidget()->height();    PickRay result;    if (OculusManager::isConnected()) {        result.origin = _camera->getPosition();        Application::getInstance()->getApplicationOverlay().computeOculusPickRay(x / screenWidth, y / screenHeight, result.direction);    } else {        _viewFrustum->computePickRay(x / screenWidth, y / screenHeight, result.origin, result.direction);    }    return result;} QString CameraScriptableObject::getMode() const {    QString mode("unknown");    switch(_camera->getMode()) {        case CAMERA_MODE_THIRD_PERSON:            mode = "third person";            break;        case CAMERA_MODE_FIRST_PERSON:            mode = "first person";            break;        case CAMERA_MODE_MIRROR:            mode = "mirror";            break;        case CAMERA_MODE_INDEPENDENT:            mode = "independent";            break;        default:            break;    }    return mode;} void CameraScriptableObject::setMode(const QString& mode) {    CameraMode currentMode = _camera->getMode();    CameraMode targetMode = currentMode;    if (mode == "third person") {        targetMode = CAMERA_MODE_THIRD_PERSON;        Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);        Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);    } else if (mode == "first person") {        targetMode = CAMERA_MODE_FIRST_PERSON;        Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);        Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);    } else if (mode == "mirror") {        targetMode = CAMERA_MODE_MIRROR;        Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true);        Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);    } else if (mode == "independent") {        targetMode = CAMERA_MODE_INDEPENDENT;        Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);        Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);    }    if (currentMode != targetMode) {        _camera->setMode(targetMode);        const float DEFAULT_MODE_SHIFT_PERIOD = 0.5f; // half second        _camera->setModeShiftPeriod(DEFAULT_MODE_SHIFT_PERIOD);    }}