/
Camera.cpp
146 lines (116 loc) · 3.88 KB
/
Camera.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
tdogl::Camera
Copyright 2012 Thomas Dalling - http://tomdalling.com/
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include "Camera.h"
#include <glm/gtc/matrix_transform.hpp>
using namespace tdogl;
static const float MaxVerticalAngle = 85.0f; //must be less than 90 to avoid gimbal lock
static inline float RadiansToDegrees(float radians) {
return radians * 180.0f / (float)M_PI;
}
Camera::Camera() :
_position(0.0f, 0.0f, 1.0f),
_horizontalAngle(0.0f),
_verticalAngle(0.0f),
_fieldOfView(50.0f),
_nearPlane(0.01f),
_farPlane(100.0f),
_viewportAspectRatio(4.0f/3.0f)
{
}
const glm::vec3& Camera::position() const {
return _position;
}
void Camera::setPosition(const glm::vec3& position) {
_position = position;
}
void Camera::offsetPosition(const glm::vec3& offset) {
_position += offset;
}
float Camera::fieldOfView() const {
return _fieldOfView;
}
void Camera::setFieldOfView(float fieldOfView) {
assert(fieldOfView > 0.0f && fieldOfView < 180.0f);
_fieldOfView = fieldOfView;
}
float Camera::nearPlane() const {
return _nearPlane;
}
float Camera::farPlane() const {
return _farPlane;
}
void Camera::setNearAndFarPlanes(float nearPlane, float farPlane) {
assert(nearPlane > 0.0f);
assert(farPlane > nearPlane);
_nearPlane = nearPlane;
_farPlane = farPlane;
}
glm::mat4 Camera::orientation() const {
glm::mat4 orientation;
orientation = glm::rotate(orientation, _verticalAngle, glm::vec3(1,0,0));
orientation = glm::rotate(orientation, _horizontalAngle, glm::vec3(0,1,0));
return orientation;
}
void Camera::offsetOrientation(float upAngle, float rightAngle) {
_horizontalAngle += rightAngle;
_verticalAngle += upAngle;
normalizeAngles();
}
void Camera::lookAt(glm::vec3 position) {
assert(position != _position);
glm::vec3 direction = glm::normalize(position - _position);
_verticalAngle = RadiansToDegrees(asinf(-direction.y));
_horizontalAngle = -RadiansToDegrees(atan2f(-direction.x, -direction.z));
normalizeAngles();
}
float Camera::viewportAspectRatio() const {
return _viewportAspectRatio;
}
void Camera::setViewportAspectRatio(float viewportAspectRatio) {
assert(viewportAspectRatio > 0.0);
_viewportAspectRatio = viewportAspectRatio;
}
glm::vec3 Camera::forward() const {
glm::vec4 forward = glm::inverse(orientation()) * glm::vec4(0,0,-1,1);
return glm::vec3(forward);
}
glm::vec3 Camera::right() const {
glm::vec4 right = glm::inverse(orientation()) * glm::vec4(1,0,0,1);
return glm::vec3(right);
}
glm::vec3 Camera::up() const {
glm::vec4 up = glm::inverse(orientation()) * glm::vec4(0,1,0,1);
return glm::vec3(up);
}
glm::mat4 Camera::matrix() const {
return projection() * view();
}
glm::mat4 Camera::projection() const {
return glm::perspective(_fieldOfView, _viewportAspectRatio, _nearPlane, _farPlane);
}
glm::mat4 Camera::view() const {
return orientation() * glm::translate(glm::mat4(), -_position);
}
void Camera::normalizeAngles() {
_horizontalAngle = fmodf(_horizontalAngle, 360.0f);
//fmodf can return negative values, but this will make them all positive
if(_horizontalAngle < 0.0f)
_horizontalAngle += 360.0f;
if(_verticalAngle > MaxVerticalAngle)
_verticalAngle = MaxVerticalAngle;
else if(_verticalAngle < -MaxVerticalAngle)
_verticalAngle = -MaxVerticalAngle;
}