#include "Camera.h" namespace NB { // Camera class Camera::Camera(const Vec3& pos, const Vec3& tar, const Vec3& up) { _pos = pos; _tar = tar; _world_up = glm::normalize(up); _dir = glm::normalize(_tar-_pos); _right = normCross(_dir, _world_up); _up = normCross(_right, _dir); _proj = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); _calcLook(); } void Camera::_calcLook() { _look = glm::lookAt(_pos, _tar, (_lock_world_up)?_world_up:_up); } glm::vec3 Camera::normCross(const Vec3& a, const Vec3& b) { return glm::normalize(glm::cross(a, b)); } glm::vec3 Camera::transformVec(const Mat4& mat, const Vec3& vec) { return Vec3(mat * glm::vec4(vec, 1.0f)); } glm::vec3 Camera::getPos() const { return _pos; } glm::vec3 Camera::getTarget() const { return _tar; } glm::vec3 Camera::getDirection() const { return _dir; } glm::vec3 Camera::getWorldUp() const { return _world_up; } glm::vec3 Camera::getUp() const { return _up; } glm::vec3 Camera::getRight() const { return _right; } glm::mat4 Camera::getLookMatrix() const { return _look; } glm::mat4 Camera::getProjectionMatrix() const { return _proj; } glm::mat4 Camera::getFlattenedMatrices() const { return _proj * _look; } bool Camera::isUpLocked() const { return _lock_world_up; } void Camera::setProjection(const Mat4& proj) { _proj = proj; } void Camera::setPos(const Vec3& pos) { _pos = pos; _calcLook(); } void Camera::setTarget(const Vec3& tar) { _tar = tar; _dir = glm::normalize(_tar-_pos); _right = normCross(_dir, _world_up); _up = normCross(_right, _dir); _calcLook(); } void Camera::setDirection(const Vec3& dir) { setTarget(glm::normalize(dir)+_pos); } void Camera::setWorldUp(const Vec3& up) { _world_up = up; _right = normCross(_dir, _up); _up = normCross(_right, _dir); _calcLook(); } void Camera::lockToWorldUp(bool lock) { if (!_lock_world_up && lock) { resetUp(); } _lock_world_up = lock; } void Camera::resetUp() { _right = normCross(_dir, _world_up); _up = normCross(_right, _dir); _calcLook(); } void Camera::addPos(const Vec3& add) { _pos += add; _dir = glm::normalize(_tar-_pos); if (_lock_world_up) { _right = normCross(_dir, _world_up); } else { _right = normCross(_dir, _up); _up = normCross(_right, _dir); } _calcLook(); } void Camera::panPos(const Vec3& add) { _tar += add; addPos(add); } void Camera::panPosRelative(const Vec3& add) { panPos(add.x*_right + add.y*((_lock_world_up)?_world_up:_up) + add.z*_dir); } void Camera::addTarget(const Vec3& add) { _tar += add; _dir = glm::normalize(_tar-_pos); _right = normCross(_dir, _world_up); _up = normCross(_right, _dir); _calcLook(); } void Camera::roll(float ang) { if (!_lock_world_up) { Mat4 rot_mat = glm::rotate(Mat4(1.0f), ang, _dir); _right = transformVec(rot_mat, _right); _up = transformVec(rot_mat, _up); _calcLook(); } } void Camera::pitch(float ang) { Mat4 rot_mat = glm::rotate(Mat4(1.0f), ang, _right); _dir = transformVec(rot_mat, _dir); _up = transformVec(rot_mat, _up); _tar = _pos + _dir; _calcLook(); } void Camera::yaw(float ang) { Mat4 rot_mat = glm::rotate(Mat4(1.0f), ang, ((_lock_world_up)?_world_up:_up)); _dir = transformVec(rot_mat, _dir); _right = transformVec(rot_mat, _right); _up = normCross(_right, _dir); _tar = _pos + _dir; _calcLook(); } // OrthographicCamera class OrthographicCamera::OrthographicCamera( const Vec3& pos, const Vec3& tar, const Vec3& up, float left, float right, float bottom, float top, float near, float far ) : Camera(pos, tar, up), _leftPlane(left), _rightPlane(right), _bottomPlane(bottom), _topPlane(top), _nearPlane(near), _farPlane(far) { _calcView(); } void OrthographicCamera::_calcView() { setProjection(glm::ortho(_leftPlane, _rightPlane, _bottomPlane, _topPlane, _nearPlane, _farPlane)); } float OrthographicCamera::getLeftPlane() const { return _leftPlane; } float OrthographicCamera::getRightPlane() const { return _rightPlane; } float OrthographicCamera::getBottomPlane() const { return _bottomPlane; } float OrthographicCamera::getTopPlane() const { return _topPlane; } float OrthographicCamera::getNearPlane() const { return _nearPlane; } float OrthographicCamera::getFarPlane() const { return _farPlane; } void OrthographicCamera::setLeftPlane(float left) { _leftPlane = left; _calcView(); } void OrthographicCamera::setRightPlane(float right) { _rightPlane = right; _calcView(); } void OrthographicCamera::setBottomPlane(float bottom) { _bottomPlane = bottom; _calcView(); } void OrthographicCamera::setTopPlane(float top) { _topPlane = top; _calcView(); } void OrthographicCamera::setNearPlane(float near) { _nearPlane = near; _calcView(); } void OrthographicCamera::setFarPlane(float far) { _farPlane = far; _calcView(); } void OrthographicCamera::setOrthographicProjection(float left, float right, float bottom, float top, float near, float far) { _leftPlane = left; _rightPlane = right; _bottomPlane = bottom; _topPlane = top; _nearPlane = near; _farPlane = far; _calcView(); } // PerspectiveCamera class PerspectiveCamera::PerspectiveCamera( const Vec3& pos, const Vec3& tar, const Vec3& up , float fov, float aspectRatio, float near, float far ) : Camera(pos, tar, up), _fov(fov), _ratio(aspectRatio), _nearPlane(near), _farPlane(far) { _calcView(); } void PerspectiveCamera::_calcView() { setProjection(glm::perspective(glm::radians(_fov), _ratio, _nearPlane, _farPlane)); } float PerspectiveCamera::getFOV() const { return _fov; } float PerspectiveCamera::getAspectRatio() const { return _ratio; } float PerspectiveCamera::getNearPlane() const { return _nearPlane; } float PerspectiveCamera::getFarPlane() const { return _farPlane; } void PerspectiveCamera::setFOV(float fov) { _fov = fov; _calcView(); } void PerspectiveCamera::setAspectRatio(float aspectRatio) { _ratio = aspectRatio; _calcView(); } void PerspectiveCamera::setNearPlane(float near) { _nearPlane = near; _calcView(); } void PerspectiveCamera::setFarPlane(float far) { _farPlane = far; _calcView(); } void PerspectiveCamera::setPerspectiveProjection(float fov, float aspectRatio, float near, float far) { _fov = fov; _ratio = aspectRatio; _nearPlane = near; _farPlane = far; _calcView(); } }