MVE - Multi-View Environment mve-devel
Loading...
Searching...
No Matches
camera_trackball.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015, Simon Fuhrmann
3 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
4 * All rights reserved.
5 *
6 * This software may be modified and distributed under the terms
7 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
8 */
9
10#include <iostream>
11
12#include "math/matrix_tools.h"
13#include "math/quaternion.h"
14#include "math/functions.h"
15#include "ogl/opengl.h"
17
19
20CamTrackball::CamTrackball (void)
21{
22 this->cam = nullptr;
23 this->tb_radius = 1.0f;
24 this->tb_center = math::Vec3f(0.0f);
25 this->tb_tocam = math::Vec3f(0.0f, 0.0f, 1.0f);
26 this->tb_upvec = math::Vec3f(0.0f, 1.0f, 0.0f);
27}
28
29/* ---------------------------------------------------------------- */
30
31bool
32CamTrackball::consume_event (MouseEvent const& event)
33{
34 bool is_handled = false;
35
36 if (event.type == MOUSE_EVENT_PRESS)
37 {
38 if (event.button == MOUSE_BUTTON_LEFT)
39 {
40 this->rot_mouse_x = event.x;
41 this->rot_mouse_y = event.y;
42 this->rot_tb_tocam = this->tb_tocam;
43 this->rot_tb_upvec = this->tb_upvec;
44 }
45 else if (event.button == MOUSE_BUTTON_MIDDLE)
46 {
47 this->zoom_mouse_y = event.y;
48 this->zoom_tb_radius = this->tb_radius;
49 }
50 else if (event.button == MOUSE_BUTTON_RIGHT)
51 {
52 math::Vec3f center = this->get_center(event.x, event.y);
53 if (center != math::Vec3f(0.0f))
54 this->tb_center = center;
55 }
56 is_handled = true;
57 }
58 else if (event.type == MOUSE_EVENT_MOVE)
59 {
61 {
62 if (event.x == this->rot_mouse_x && event.y == this->rot_mouse_y)
63 {
64 this->tb_tocam = this->rot_tb_tocam;
65 this->tb_upvec = this->rot_tb_upvec;
66 }
67 else
68 {
69 this->handle_tb_rotation(event.x, event.y);
70 }
71 is_handled = true;
72 }
73
75 {
76 int mouse_diff = this->zoom_mouse_y - event.y;
77 float zoom_speed = this->zoom_tb_radius / 100.0f;
78 float cam_diff = (float)mouse_diff * zoom_speed;
79 float new_radius = this->zoom_tb_radius + cam_diff;
80 this->tb_radius = math::clamp(new_radius, this->cam->z_near, this->cam->z_far);
81 is_handled = true;
82 }
83 }
84 else if (event.type == MOUSE_EVENT_WHEEL_UP)
85 {
86 this->tb_radius = this->tb_radius + this->tb_radius / 10.0f;
87 this->tb_radius = std::min(this->cam->z_far, this->tb_radius);
88 is_handled = true;
89 }
90 else if (event.type == MOUSE_EVENT_WHEEL_DOWN)
91 {
92 this->tb_radius = this->tb_radius - this->tb_radius / 10.0f;
93 this->tb_radius = std::max(this->cam->z_near, this->tb_radius);
94 is_handled = true;
95 }
96
97 return is_handled;
98}
99
100/* ---------------------------------------------------------------- */
101
102bool
103CamTrackball::consume_event (KeyboardEvent const& /*event*/)
104{
105 return false;
106}
107
108/* ---------------------------------------------------------------- */
109
110void
111CamTrackball::handle_tb_rotation (int x, int y)
112{
113 /* Get ball normals. */
114 math::Vec3f bn_start = this->get_ball_normal
115 (this->rot_mouse_x, this->rot_mouse_y);
116 math::Vec3f bn_now = this->get_ball_normal(x, y);
117
118 /* Rotation axis and angle. */
119 math::Vec3f axis = bn_now.cross(bn_start);
120 float angle = std::acos(bn_now.dot(bn_start));
121
122 /* Rotate axis to world coords. Build inverse viewing matrix from
123 * values stored at the time of mouse click.
124 */
125 math::Matrix4f cam_to_world;
126 math::Vec3f campos = this->tb_center + this->rot_tb_tocam * this->tb_radius;
127 math::Vec3f viewdir = -this->rot_tb_tocam;
128 cam_to_world = math::matrix_inverse_viewtrans(
129 campos, viewdir, this->rot_tb_upvec);
130 axis = cam_to_world.mult(axis, 0.0f);
131 axis.normalize();
132
133 /* Rotate camera and up vector around axis. */
134 math::Matrix3f rot = matrix_rotation_from_axis_angle(axis, angle);
135 this->tb_tocam = rot * this->rot_tb_tocam;
136 this->tb_upvec = rot * this->rot_tb_upvec;
137}
138
139/* ---------------------------------------------------------------- */
140
142CamTrackball::get_center (int x, int y)
143{
144 /* Try to find a valid depth value in a spiral around the click point. */
145 float depth = 1.0f;
146 {
147 /* Patchsize should be odd and larger than one. */
148 int const patch_size = 9;
149 int const patch_halfsize = patch_size / 2;
150 int const screen_width = this->cam->width;
151 int const screen_height = this->cam->height;
152 int const center_x = x;
153 int const center_y = y;
154 int dx = 1;
155 int dy = 0;
156 int radius = 0;
157 while (radius <= patch_halfsize)
158 {
159 if (x >= 0 && x < screen_width && y > 0 && y < screen_height)
160 glReadPixels(x, screen_height - y - 1, 1, 1,
161 GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
162 if (depth != 1.0f)
163 break;
164
165 x += dx;
166 y += dy;
167 if (x > center_x + radius)
168 {
169 radius += 1;
170 dx = 0;
171 dy = -1;
172 }
173 if (y <= center_y - radius)
174 {
175 dx = -1;
176 dy = 0;
177 }
178 if (x <= center_x - radius)
179 {
180 dx = 0;
181 dy = 1;
182 }
183 if (y >= center_y + radius)
184 {
185 dx = 1;
186 dy = 0;
187 }
188 }
189 }
190
191 /* Exit if depth value is not set. */
192 if (depth == 1.0f)
193 return math::Vec3f(0.0f); // TODO: Better "error" reporting
194
195 float const fx = static_cast<float>(x);
196 float const fy = static_cast<float>(y);
197 float const fw = static_cast<float>(this->cam->width);
198 float const fh = static_cast<float>(this->cam->height);
199
200 /* Calculate camera-to-surface distance (orthographic). */
201 float dist = (this->cam->z_far * this->cam->z_near)
202 / ((this->cam->z_near - this->cam->z_far) * depth + this->cam->z_far);
203
204 /* Fix distance value caused by projection. */
205 {
206 /* Create point on near plane corresponding to click coords. */
207 math::Vec3f pnp((2.0f * fx / (fw - 1.0f) - 1.0f) * this->cam->right,
208 (1.0f - 2.0f * fy / (fh - 1.0f)) * this->cam->top,
209 this->cam->z_near);
210 float cosangle = pnp.normalized()[2];
211 dist /= cosangle;
212 }
213
214 /* Create a point in unit cube corresponding to the click coords. */
215 math::Vec3f ray(2.0f * fx / (fw - 1.0f) - 1.0f,
216 1.0f - 2.0f * fy / (fh - 1.0f), 0.0f);
217 /* Convert cube click coords to ray in camera corrds. */
218 ray = this->cam->inv_proj.mult(ray, 1.0f);
219 /* Ray to new camera center in camera coords. */
220 ray = ray.normalized() * dist;
221 /* Ray to new camera center in world coords. */
222 ray = this->cam->inv_view.mult(ray, 0.0f);
223
224 return this->cam->pos + ray;
225}
226
227/* ---------------------------------------------------------------- */
228
230CamTrackball::get_ball_normal (int x, int y)
231{
232 /* Calculate normal on unit sphere. */
233 math::Vec3f sn;
234 sn[0] = 2.0f * (float)x / (float)(this->cam->width - 1) - 1.0f;
235 sn[1] = 1.0f - 2.0f * (float)y / (float)(this->cam->height - 1);
236 float z2 = 1.0f - sn[0] * sn[0] - sn[1] * sn[1];
237 sn[2] = z2 > 0.0f ? std::sqrt(z2) : 0.0f;
238
239 return sn.normalize();
240}
241
242/* ---------------------------------------------------------------- */
243
244void
245CamTrackball::set_camera_params (math::Vec3f const& center,
246 math::Vec3f const& lookat, math::Vec3f const& upvec)
247{
248 this->tb_radius = (center - lookat).norm();
249 this->tb_center = lookat;
250 this->tb_tocam = (center - lookat).normalized();
251 this->tb_upvec = upvec;
252}
253
Matrix class for arbitrary dimensions and types.
Definition matrix.h:54
Matrix< T, N, U > mult(Matrix< T, M, U > const &rhs) const
Matrix with matrix multiplication.
Definition matrix.h:462
Vector class for arbitrary dimensions and types.
Definition vector.h:87
Vector< T, N > cross(Vector< T, N > const &other) const
Cross product between this and another vector.
Definition vector.h:549
T dot(Vector< T, N > const &other) const
Dot (or scalar) product between self and another vector.
Definition vector.h:542
Vector< T, N > & normalize(void)
Normalizes self and returns reference to self.
Definition vector.h:448
T const & clamp(T const &v, T const &min=T(0), T const &max=T(1))
Returns value 'v' clamped to the interval specified by 'min' and 'max'.
Definition functions.h:204
Matrix< T, 4, 4 > matrix_inverse_viewtrans(Vector< T, 3 > const &campos, Vector< T, 3 > const &viewdir, Vector< T, 3 > const &upvec)
Creates an inverse view transformation matrix.
Vector< float, 3 > Vec3f
Definition vector.h:31
@ MOUSE_EVENT_MOVE
Definition events.h:22
@ MOUSE_EVENT_PRESS
Definition events.h:20
@ MOUSE_EVENT_WHEEL_UP
Definition events.h:23
@ MOUSE_EVENT_WHEEL_DOWN
Definition events.h:24
@ MOUSE_BUTTON_RIGHT
Definition events.h:32
@ MOUSE_BUTTON_MIDDLE
Definition events.h:33
@ MOUSE_BUTTON_LEFT
Definition events.h:31
#define OGL_NAMESPACE_END
Definition defines.h:14
#define OGL_NAMESPACE_BEGIN
Definition defines.h:13
Keyboard event.
Definition events.h:57
Mouse event.
Definition events.h:40
MouseEventType type
Type of event.
Definition events.h:41
int x
Mouse X-position.
Definition events.h:44
MouseButton button
Button that caused the event.
Definition events.h:42
int button_mask
Button state when event was generated.
Definition events.h:43
int y
Mouse Y-position.
Definition events.h:45