]> git.tdb.fi Git - libs/gl.git/blob - source/render/camera.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / render / camera.cpp
1 #include <cmath>
2 #include "camera.h"
3 #include "matrix.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 Camera::Camera()
11 {
12         update_projection_matrix();
13         update_object_matrix();
14 }
15
16 void Camera::copy_parameters(const Camera &source)
17 {
18         fov = source.fov;
19         height = source.height;
20         aspect = source.aspect;
21         clip_near = source.clip_near;
22         clip_far = source.clip_far;
23         frustum_x = source.frustum_x;
24         frustum_y = source.frustum_y;
25         rotate = source.rotate;
26         position = source.position;
27         look_dir = source.look_dir;
28         up_dir = source.up_dir;
29         update_projection_matrix();
30         update_object_matrix();
31 }
32
33 void Camera::set_field_of_view(const Geometry::Angle<float> &f)
34 {
35         fov = f;
36         update_projection_matrix();
37 }
38
39 void Camera::set_orthographic(float w, float h)
40 {
41         fov = Geometry::Angle<float>::zero();
42         height = h;
43         if(w)
44                 aspect = w/h;
45         update_projection_matrix();
46 }
47
48 void Camera::set_aspect_ratio(float a)
49 {
50         aspect = a;
51         update_projection_matrix();
52 }
53
54 void Camera::set_depth_clip(float n, float f)
55 {
56         clip_near = n;
57         clip_far = f;
58         update_projection_matrix();
59 }
60
61 void Camera::set_frustum_axis(float x, float y)
62 {
63         frustum_x = x;
64         frustum_y = y;
65         update_projection_matrix();
66 }
67
68 void Camera::set_frustum_rotation(const Geometry::Angle<float> &r)
69 {
70         rotate = r;
71         update_projection_matrix();
72 }
73
74 void Camera::set_position(const Vector3 &p)
75 {
76         position = p;
77         update_object_matrix();
78 }
79
80 void Camera::set_look_direction(const Vector3 &l)
81 {
82         look_dir = normalize(l);
83         update_object_matrix();
84 }
85
86 void Camera::look_at(const Vector3 &p)
87 {
88         set_look_direction(p-position);
89 }
90
91 void Camera::set_up_direction(const Vector3 &u)
92 {
93         up_dir = normalize(u);
94         update_object_matrix();
95 }
96
97 void Camera::set_object_matrix(const Matrix &m)
98 {
99         position = m.column(3).slice<3>(0);
100         look_dir = normalize(-m.column(2).slice<3>(0));
101         up_dir = normalize(m.column(1).slice<3>(0));
102         update_object_matrix();
103 }
104
105 Vector3 Camera::project(const Vector4 &p) const
106 {
107         Vector4 r = proj_matrix*(view_matrix*p);
108         return r.slice<3>(0)/r.w;
109 }
110
111 Vector3 Camera::project(const Vector3 &p) const
112 {
113         return project(compose(p, 1.0f));
114 }
115
116 Vector4 Camera::unproject(const Vector4 &p) const
117 {
118         Vector4 r = invert(proj_matrix)*Vector4(p.x, p.y, p.z, 1.0f);
119         r = matrix*Vector4(r.x/r.w, r.y/r.w, r.z/r.w, p.w);
120         return r;
121 }
122
123 Vector3 Camera::unproject(const Vector3 &p) const
124 {
125         return unproject(compose(p, 1.0f)).slice<3>(0);
126 }
127
128 bool Camera::is_in_frustum(const Renderable &renderable) const
129 {
130         const Matrix *rmatrix = renderable.get_matrix();
131         const Geometry::BoundingSphere<float, 3> *bsphere = renderable.get_bounding_sphere();
132         if(!rmatrix || !bsphere)
133                 return true;
134
135         Vector4 center = *rmatrix*compose(bsphere->get_center(), 1.0f);
136         Vector3 x_axis = (rmatrix->column(0)*bsphere->get_radius()).slice<3>(0);
137         float radius_sq = inner_product(x_axis, x_axis);
138
139         for(unsigned i=0; i<6; ++i)
140         {
141                 float distance = inner_product(center, frustum_planes[i]);
142                 if(distance<0 && distance*distance>radius_sq)
143                         return false;
144         }
145
146         return true;
147 }
148
149 void Camera::update_projection_matrix()
150 {
151         float frustum_h = (is_orthographic() ? height/2 : tan(fov/2.0f)*clip_near);
152         float frustum_w = frustum_h*aspect;
153         float left = frustum_w*(frustum_x-1.0f);
154         float right = frustum_w*(frustum_x+1.0f);
155         float bottom = frustum_h*(frustum_y-1.0f);
156         float top = frustum_h*(frustum_y+1.0f);
157         if(is_orthographic())
158                 proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far);
159         else
160                 proj_matrix = Matrix::frustum(left, right, bottom, top, clip_near, clip_far);
161         proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix;
162
163         shdata.uniform("clip_eye_matrix", proj_matrix);
164         shdata.uniform("eye_clip_matrix", invert(proj_matrix));
165
166         update_frustum_planes();
167 }
168
169 void Camera::update_object_matrix()
170 {
171         Vector3 right_dir = normalize(cross(look_dir, up_dir));
172         Vector4 columns[4];
173         columns[0] = compose(right_dir, 0.0f);
174         columns[1] = compose(cross(right_dir, look_dir), 0.0f);
175         columns[2] = compose(-look_dir, 0.0f);
176         columns[3] = compose(position, 1.0f);
177         matrix = Matrix::from_columns(columns);
178         view_matrix = invert(matrix);
179
180         shdata.uniform("world_eye_matrix", matrix);
181         shdata.uniform("eye_world_matrix", view_matrix);
182
183         update_frustum_planes();
184 }
185
186 void Camera::update_frustum_planes()
187 {
188         // TODO Handle off-center and rotated frustums
189         if(is_orthographic())
190         {
191                 frustum_planes[0] = Vector4(0, 1, 0, height);
192                 frustum_planes[1] = Vector4(0, -1, 0, height);
193
194                 frustum_planes[2] = Vector4(1, 0, 0, height*aspect);
195                 frustum_planes[3] = Vector4(-1, 0, 0, height*aspect);
196         }
197         else
198         {
199                 float y = tan(fov/2.0f);
200                 float s = sqrt(y*y+1);
201                 frustum_planes[0] = Vector4(0, 1/s, -y/s, 0);
202                 frustum_planes[1] = Vector4(0, -1/s, -y/s, 0);
203
204                 float x = y*aspect;
205                 s = sqrt(x*x+1);
206                 frustum_planes[2] = Vector4(1/s, 0, -x/s, 0);
207                 frustum_planes[3] = Vector4(-1/s, 0, -x/s, 0);
208         }
209
210         frustum_planes[4] = Vector4(0, 0, 1, clip_far);
211         frustum_planes[5] = Vector4(0, 0, -1, -clip_near);
212
213         for(unsigned i=0; i<6; ++i)
214         {
215                 Vector3 normal = frustum_planes[i].slice<3>(0);
216                 normal = (matrix*compose(normal, 0.0f)).slice<3>(0);
217                 frustum_planes[i] = compose(normal, frustum_planes[i].w-dot(normal, matrix.column(3).slice<3>(0)));
218         }
219 }
220
221 void Camera::set_debug_name(const string &name)
222 {
223 #ifdef DEBUG
224         shdata.set_debug_name(name+" [UBO]");
225 #else
226         (void)name;
227 #endif
228 }
229
230
231 Camera::Loader::Loader(Camera &c):
232         DataFile::ObjectLoader<Camera>(c)
233 {
234         add("aspect_ratio", &Loader::aspect_ratio);
235         add("depth_clip", &Loader::depth_clip);
236         add("field_of_view", &Loader::field_of_view);
237         add("look_at", &Loader::look_at);
238         add("look_direction", &Loader::look_direction);
239         add("orthographic", &Loader::orthographic);
240         add("position", &Loader::position);
241         add("up_direction", &Loader::up_direction);
242 }
243
244 void Camera::Loader::aspect_ratio(float a)
245 {
246         obj.set_aspect_ratio(a);
247 }
248
249 void Camera::Loader::depth_clip(float n, float f)
250 {
251         obj.set_depth_clip(n, f);
252 }
253
254 void Camera::Loader::field_of_view(float a)
255 {
256         obj.set_field_of_view(Geometry::Angle<float>::from_degrees(a));
257 }
258
259 void Camera::Loader::look_at(float x, float y, float z)
260 {
261         obj.look_at(Vector3(x, y, z));
262 }
263
264 void Camera::Loader::look_direction(float x, float y, float z)
265 {
266         obj.set_look_direction(Vector3(x, y, z));
267 }
268
269 void Camera::Loader::orthographic(float w, float h)
270 {
271         obj.set_orthographic(w, h);
272 }
273
274 void Camera::Loader::position(float x, float y, float z)
275 {
276         obj.set_position(Vector3(x, y, z));
277 }
278
279 void Camera::Loader::up_direction(float x, float y, float z)
280 {
281         obj.set_up_direction(Vector3(x, y, z));
282 }
283
284 } // namespace GL
285 } // namespace Msp