GenericCamera.hh 15.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/***********************************************************************
 * Copyright 2011-2013 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/

#pragma once
#include <ACGL/ACGL.hh>
#include <ACGL/Math/Math.hh>
#include <glm/gtx/quaternion.hpp>

12
#include "CameraBase.hh"
13
#include "MoveableObject.hh"
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
 * What you definitly want to set:
 * - a position in 3D space (a vec3)
 * - a viewing direction, this can be defined by:
 *   - roll/pitch/jaw rotations
 *   - up/left/forward vectors
 * - the aspect ratio (width/height)
 *
 * What you maybe want to change:
 * - a lookAtDistance, this is internaly only used for the orthographic
 *   projection, can be be used externaly e.g. for field of view effects
 *   (if no focal distance is given, a default will be used, but often this
 *   value is not used at all), also a lookAt point can be calculated with this
 * - Stereo settings:
 *   - the eyedistance
 *   - the StereoMode
 * - Horizontal/Vertical FoV
 * - near- and far-clipping plane
 *
 * A Camera can calculate:
 * - a ViewMatrix
 * - a ProjectionMatrix for Mono view
 * - ProjectionMatrices for Stereo view
Robert Menzel's avatar
Robert Menzel committed
38
 * - etc.
39
40
 *
 *
Robert Menzel's avatar
Robert Menzel committed
41
42
43
44
45
 * Note: To get from world to camera space, the translation is applied first, then the
 *       rotation. getViewMatrix() provides one matrix for this.
 *       Other camera models rotate first and translate later (e.g. bundler)! The rotation
 *       is the same, the translation differs.
 *
46
 * TODO: support more stereo modes!
47
48
49
50
51
 */

namespace ACGL{
namespace Scene{

52
class GenericCamera : public CameraBase, public MoveableObject
53
54
{
	public:
55
56
57
58
59
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // Helping enums:
        //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        enum ProjectionMode
        {
            ISOMETRIC_PROJECTION   = 0,
            PERSPECTIVE_PROJECTION
        };

        enum StereoMode
        {
            MONO = 0,
            PARALLEL_SHIFT,
            OFF_AXIS,
            TOE_IN
        };

        enum Eye
        {
            EYE_LEFT = 0,
            EYE_RIGHT
        };
        
80
81
82
83
84
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // Constructor / Destructor / save&store
        //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
85
        /**
86
87
         * Default Constructor of a camera.
         */
88
89
90
        GenericCamera();

        /**
91
92
93
94
95
96
97
98
         * Constructs a camera from a string which holds all camera parameters. Note that this sets the viewport which
         * might not fix the currect screen!
         */
        GenericCamera( const std::string &_state );

        /**
         * Destructor of a camera.
         */
99
100
        ~GenericCamera() {}

101
102
103
104
105
106
107
108
109
110
111
        /// Writes all internal state to one string
        std::string storeStateToString() const;

        /// Sets all internal state from a string
        void setStateFromString( const std::string &_state );
	
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // Set / Get basic camera properties:
        //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
112
113
	
        /**
114
115
         * Set the distance between the pupils (only needed for stereo rendering).
         * @param _interpupillaryDistance Inter pupil distance in meter(!) (distance between the centers of the eyes)
116
         */
117
118
        void setInterpupillaryDistance( float _interpupillaryDistance ) { mInterpupillaryDistance = _interpupillaryDistance; }
        float getInterpupillaryDistance() const { return mInterpupillaryDistance; }
119
120
        
		/**
121
         * Set the projection mode of the camera.
122
123
124
125
126
127
         * @param _projection           New projection mode of the camera.
		 */
        void setProjectionMode( ProjectionMode _projection ) { mProjectionMode = _projection; }
        ProjectionMode getProjectionMode() const { return mProjectionMode; }

        /**
128
         * Set the stereo mode of the camera. In mode MONO the set eye will get ignored (see below).
129
130
131
132
133
         * @param _stereoMode New stereo mode of the camera.
         */
        void setStereoMode( StereoMode _stereoMode ) { mStereoMode = _stereoMode; }
        StereoMode getStereoMode() const { return mStereoMode; }

134
135
136
137
138
139
140
        /**
         * Sets the currently active eye. In stereo mode MONO this setting is ignored.
         * In the stereo modes (PARALLEL_SHIFT, OFF_AXIS, TOE_IN) it is used to
         * define the default eye that is assumed for the generic get*Matrix() functions.
         * (Matrices for specific eyes can still get queried directly without setting the
         * eye explicitly before each call).
         */
141
142
143
144
        void setEye( Eye _eye ) { mCurrentEye = _eye; }
        Eye getEye() const { return mCurrentEye; }
	
		/**
145
         * Set the horizontal field of view of the camera in degree.
146
147
148
         * vertical FoV will get (implicitly) changed!
         * @param _fovh         New horizontal field of view of the camera.
		 */
Robert Menzel's avatar
Robert Menzel committed
149
150
        void setHorizontalFieldOfView( float _fovh );
        float getHorizontalFieldOfView() const { return mHorizontalFieldOfView; }
151
152

		/**
153
         * Set the vertical field of view of the camera in degree.
Robert Menzel's avatar
Robert Menzel committed
154
         * Horizontal FoV will get changed!
155
156
         * @param _fovv         New vertical field of view of the camera.
		 */
Robert Menzel's avatar
Robert Menzel committed
157
158
        void setVerticalFieldOfView( float _fovv );
        float getVerticalFieldOfView() const;
159
160
161
162
163
164
	
		/**
        * Set the aspect ratio of the camera. The horizontal FoV stays the same, the
		* vertical FoV gets updated.
		* @param aspectRatio	New aspect ratio (width/height)
		*/
Robert Menzel's avatar
Robert Menzel committed
165
166
        void setAspectRatio( float _aspectRatio ) { mAspectRatio = _aspectRatio; }
        float getAspectRatio() const { return mAspectRatio; }
167
168
169
170
171
172

		/**
		 * Set the near clipping plane of the camera.
		 * The plane is defined only by a distance from the camera.
         * @param _plane        New near clipping plane of the camera.
		 */
Robert Menzel's avatar
Robert Menzel committed
173
        void setNearClippingPlane( float _plane );
174
175
176
177
178
179
180
181
        /// Gets the near clip distance
        float getNearClippingPlane() const { return mNearClippingPlane; }

		/**
		 * Set the far clipping plane of the camera.
		 * The plane is defined only by a distance from the camera.
         * @param _plane        New far clipping plane of the camera.
		 */
Robert Menzel's avatar
Robert Menzel committed
182
        void setFarClippingPlane( float _plane );
183
184
185
        /// Gets the far clip distance
        float getFarClippingPlane() const { return mFarClippingPlane; }

186
        /// Gets size of the viewport
187
        virtual glm::uvec2 getViewportSize() const { return mViewportSize; }
188
189
190
191
192
193
194
195
        /// Gets width of the viewport
        unsigned int getViewportWidth() const { return mViewportSize.x; }
        /// Gets height of the viewport
        unsigned int getViewportHeight() const { return mViewportSize.y; }
        /// Sets size of the viewport. NOTE: DOES NOT CHANGE THE ASPECT RATIO! Use resize() if you want to change that as well!
        void setViewportSize( glm::uvec2 _size ) { mViewportSize = _size; }
        /// Sets size of the viewport. NOTE: DOES NOT CHANGE THE ASPECT RATIO! Use resize() if you want to change that as well!
        void setViewportSize( unsigned int _width, unsigned int _height ) { setViewportSize(glm::uvec2(_width, _height)); }
196

197
198
        /// Sets new viewport size and calculates new aspect ratio
        void resize(int _newWidth, int _newHeight) { setViewportSize(_newWidth, _newHeight); setAspectRatio(_newWidth / (float)_newHeight); }
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
        /// The focal length is coupled to the sensor size in real cameras. As this camera does not model a
        /// sensor size in mm, the focal length is given in pixels and is in relation to the viewports resolution.
        /// This model is also used by bundler.
        /// Note that this gives only useful results if the viewports aspect ratio is the same as the
        /// projections aspect ratio!
        float getFocalLenghtInPixel() const;

        /// Sets the focal length in pixel relative to the viewport dimension. This will change the FoV.
        /// See getFocalLenghtInPixel() for more information.
        void setFocalLengthInPixel( float _focalLengthInPixel );

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // Set / Get the matrices:
        //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////////////////////
        //
        // Generic rotation and translation matrices: In mono rendering these represent the camera.
        // In stereo rendering these represent the virtual camera position between the two cameras
        // actually used.
        //
223

224
225
        /// forward to MovableObject to implement the full CameraBase interface:
        glm::vec3 getPosition() const { return MoveableObject::getPosition(); }
226

227
228
229
230
231
        ///////////////////////////////////////////////////////////////////////////////////////////
        //
        // Generic view and projection matrices. These obey the set stereo/eye settings.
        // (When in doubt, use these!)
        //
232
233

        /// Gets the currently active view matrix (depends on stereo mode and current eye)
234
        virtual glm::mat4 getViewMatrix() const;
235
236
        /// Gets the currently active view matrix (depends on stereo mode and current eye)
        glm::mat4 getInverseViewMatrix() const;
237
        /// Gets the currently active projection matrix (depends on stereo mode and current eye)
238
        virtual glm::mat4 getProjectionMatrix() const;
239
240
241
242
243
244
245
246
247
248


        ///////////////////////////////////////////////////////////////////////////////////////////
        //
        // Explicit view and projection matrices. These DON'T obey the set stereo/eye settings.
        //

        /// Gets the view matrix for non-stereo rendering EVEN IF A STEREO MODE IS SET!
        glm::mat4 getMonoViewMatrix() const;
        glm::mat4 getMonoInverseViewMatrix() const;
249
250
251
252
253
254

        /**
         * Compute a camera view matrix for stereo rendering.
         * In stereo mode, the view matrix is the mono view matrix but also the shift
         * by half the eye distance to the left/right and a small rotation inwards in
         * case of toe in mode.
255
256
         *
         * These methods get the stereo matrix independent of the set mode for this camera.
257
         */
258
259
260
261
262
263
264
265
266
267
268
269
        glm::mat4 getStereoViewMatrix( bool _leftEye, StereoMode _stereoMode = OFF_AXIS ) const;
        glm::mat4 getLeftStereoViewMatrix() const { return getStereoViewMatrix(true,  mStereoMode); }
        glm::mat4 getRightStereoViewMatrix()const { return getStereoViewMatrix(false, mStereoMode); }
        glm::mat4 getLeftParallelShiftStereoViewMatrix() const { return getStereoViewMatrix(true,  PARALLEL_SHIFT); }
        glm::mat4 getRightParallelShiftStereoViewMatrix()const { return getStereoViewMatrix(false, PARALLEL_SHIFT); }
        glm::mat4 getLeftOffAxisStereoViewMatrix()       const { return getStereoViewMatrix(true,  OFF_AXIS); }
        glm::mat4 getRightOffAxisStereoViewMatrix()      const { return getStereoViewMatrix(false, OFF_AXIS); }
        glm::mat4 getLeftToeInStereoViewMatrix()         const { return getStereoViewMatrix(true,  TOE_IN); }
        glm::mat4 getRightToeInStereoViewMatrix()        const { return getStereoViewMatrix(false, TOE_IN); }

        /// Gets the projection matrix for non-stereo rendering EVEN IF A STEREO MODE IS SET!
        glm::mat4 getMonoProjectionMatrix() const;
270

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
        /**
         * Compute a camera projection matrix for stereo rendering.
         * In stereo mode, the Cameras position is the point in the middle between the two eyes.
         * So we just need one additional info to calculate two matrices:
         */
        glm::mat4 getStereoProjectionMatrix( bool _leftEye, StereoMode _stereoMode = OFF_AXIS ) const;
        glm::mat4 getLeftStereoProjectionMatrix()              const { return getStereoProjectionMatrix(true,  mStereoMode); }
        glm::mat4 getRightStereoProjectionMatrix()             const { return getStereoProjectionMatrix(false, mStereoMode); }
        glm::mat4 getLeftParallelShiftStereoProjectionMatrix() const { return getStereoProjectionMatrix(true,  PARALLEL_SHIFT); }
        glm::mat4 getRightParallelShiftStereoProjectionMatrix()const { return getStereoProjectionMatrix(false, PARALLEL_SHIFT); }
        glm::mat4 getLeftOffAxisStereoProjectionMatrix()       const { return getStereoProjectionMatrix(true,  OFF_AXIS); }
        glm::mat4 getRightOffAxisStereoProjectionMatrix()      const { return getStereoProjectionMatrix(false, OFF_AXIS); }
        glm::mat4 getLeftToeInStereoProjectionMatrix()         const { return getStereoProjectionMatrix(true,  TOE_IN); }
        glm::mat4 getRightToeInStereoProjectionMatrix()        const { return getStereoProjectionMatrix(false, TOE_IN); }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // Set / Get properties that move the camera around (or rotate etc.)
        //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
291

292
293
294
295
296
297
298
299
300
301
302
        /**
         * Look around with a mouse, works like a FPS camera:
         *  No roll possible.
         *  Up/down is limited to 90 degree.
         * This method assumes there is no roll in the current camera rotation, if
         * there is a roll component, it will get destroyed -> don't mix this
         * way to stear with other, more flexible methods!
         * @param _deltaX How much the mouse moved on the viewport (0..1, 1 = full viewport width)
         * @param _deltaY How much the mouse moved on the viewport (0..1, 1 = full viewport height)
         */
        void FPSstyleLookAround( float _deltaX, float _deltaY );
303

304
305
306
307
308
309
310
311
        // rotate around the target, x,y,z are angles to rotate by IN RADIANCE
        // the rotation is around the global goordinate system (1,0,0 / 0,1,0 / 0,0,1)
        // "turntable style" rotation if _x is set and _y,_z == 0
        void rotateAroundTaget_GlobalAxes( float _x, float _y, float _z );

        // rotate around the current coordinate system
        void rotateAroundTaget_LocalAxes( float _x, float _y, float _z );

312
	private:
313
314
315
316
        ///
        /// States: update the storeStateToString() & setStateFromString() functions whenever adding a new state!
        ///

317
318
319
320
321
322
323
		/// Current camera projection mode
        ProjectionMode mProjectionMode;
        /// stereo view mode
        StereoMode mStereoMode;
        /// Current eye
        Eye mCurrentEye;
		/// Current camera horizontal field of view
Robert Menzel's avatar
Robert Menzel committed
324
        float mHorizontalFieldOfView;
325
		/// Current aspect ratio: width/height.
Robert Menzel's avatar
Robert Menzel committed
326
        float mAspectRatio;
327
	
328
329
        /// Distance of the eyes for stereo projection. In that case, the left eye is 0.5*InterpupillaryDistance
        /// shifted to the left of position and the right eye is 0.5*InterpupillaryDistance to the right shifted.
330
		/// We assume that 1 unit equals 1 meter. The mean eye distance is 6.5 cm == 0.065 units
331
        float mInterpupillaryDistance;
332
333
	
		/// Current camera near clipping plane
Robert Menzel's avatar
Robert Menzel committed
334
        float mNearClippingPlane;
335
		/// Current camera far clipping plane
Robert Menzel's avatar
Robert Menzel committed
336
        float mFarClippingPlane;
337
338
339

        /// viewport in pixel:
        glm::uvec2 mViewportSize;
340
341
342

        // helper:
        void rotateAroundTaget_helper( float _x, float _y, float _z, const glm::mat3 &_rotationAxes );
343
344
};

345
346
ACGL_SMARTPOINTER_TYPEDEFS(GenericCamera)

347
348
349
} // Scene
} // ACGL