summaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/unicam.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dev/MinGfx/src/unicam.h512
1 files changed, 256 insertions, 256 deletions
diff --git a/dev/MinGfx/src/unicam.h b/dev/MinGfx/src/unicam.h
index 999232b..d01634a 100644
--- a/dev/MinGfx/src/unicam.h
+++ b/dev/MinGfx/src/unicam.h
@@ -1,256 +1,256 @@
-/*
- This file is part of the MinGfx Project.
-
- Copyright (c) 2017,2018 Regents of the University of Minnesota.
- All Rights Reserved.
-
- Original Author(s) of this File:
- Dan Keefe, 2018, University of Minnesota
-
- Author(s) of Significant Updates/Modifications to the File:
- ...
- */
-
-#ifndef SRC_UNICAM_H_
-#define SRC_UNICAM_H_
-
-#include "quick_shapes.h"
-#include "point2.h"
-#include "point3.h"
-#include "vector2.h"
-#include "vector3.h"
-
-
-namespace mingfx {
-
-
-/** This implements a user interface for controlling the camera with the mouse.
- It is a special interface inspired by the "Unicam" technique developed by
- Zeleznik et al.
-
- The key feature is that this interface makes it possible to control camera pan,
- dolly, and rotation with only a single mouse button. That is quite useful
- because it leaves the other mouse buttons free for pointing, sketching, or
- other interaction techniques.
-
- The only downside of this technique is that it can take some time to learn. In
- order to enjoy it, you will need to read these brief instructions on how to Pan,
- Dolly, Rotate, and Spin:
-
- - Pan: Click and drag horizontally with the mouse. Once you make an initial
- horizontal movement you can than pan up and down as well, but the key to entering
- pan mode is to start with a horizontal movement.
-
- - Dolly: Click and drag vertically with the mouse. The initial movement must
- be vertical. If you click on some object in the scene, then the speed of dollying
- is set so that the object will come all the up to the camera lens if you drag
- the mouse to the bottom of the screen.
-
- - Rotate: Start with a quick click and release to set the center of rotation.
- This is most useful if you click on some object in the scene. You will see a
- black dot appear to mark the center of rotation. If you click on the background
- then a center of rotation will be selected for you. It will be a point straight
- ahead and at a depth 4.0 units away. The depth can be adjusted for your application
- with set_default_depth(). Once your center of rotation is established, move
- your mouse away a bit and then click and drag to do a trackball rotatation of
- the scene around this point. Come to a stop before letting go of the mouse
- button in order to avoid entering the spin state!
-
- - Spin: For some fun, try "throwing" the scene so that it continues to rotate
- even after you let go. To do this, start a rotation and then let go of the
- mouse button while your mouse is still moving. To stop spinning just click and
- release the mouse once to "catch" the scene.
-
-
- Example usage:
-~~~
-// Create a global or member variable in your MyGraphicsApp class:
-UniCam unicam_;
-
-
-void MyGraphicsApp::OnLeftMouseDown(const Point2 &pos) {
- Point2 mouse_xy = PixelsToNormalizedDeviceCoords(pos);
- float mouse_z = ReadZValueAtPixel(pos);
- unicam_.OnButtonDown(mouse_xy, mouse_z);
-}
-
-void MyGraphicsApp::OnLeftMouseDrag(const Point2 &pos, const Vector2 &delta) {
- Point2 mouse_xy = PixelsToNormalizedDeviceCoords(pos);
- unicam_.OnDrag(mouse_xy);
-}
-
-void MyGraphicsApp::OnLeftMouseUp(const Point2 &pos) {
- Point2 mouse_xy = PixelsToNormalizedDeviceCoords(pos);
- unicam_.OnButtonUp(mouse_xy);
-}
-
-void MyGraphicsApp::InitOpenGL() {
- projMatrix_ = Matrix4::perspective(30, aspect_ratio(), 1, 20);
- unicam_.set_view_matrix(Matrix4::lookAt(Point3(2.5,1,2.5), Point3(0,0,0), Vector3(0,1,0)););
-}
-
-void MyGraphicsApp::DrawOpenGL() {
- // draw your scene using the view matrix from UniCam
- Matrix4 proj_matrix = Matrix4::Perspective(60, aspect_ratio(), 0.001, 10);;
- Matrix4 view_matrix = uniCam.view_matrix();
- Matrix4 model_matrix = Matrix4::RotateY(to_radians(45.0));
- quickShapes.DrawCube(model_matrix, view_matirx, proj_matrix, Color(1,1,1));
-
- // tell unicam to draw itself (i.e., the small sphere that marks the center of
- // rotation when in rotation mode)
- unicam_.Draw(proj_matrix);
-}
-~~~
-*/
-class UniCam {
-public:
-
- /// Creates a UniCam object with an initial view matrix = identity.
- UniCam();
-
- /// Creates a UniCam object with the supplied initial view matrix.
- UniCam(const Matrix4 &initialViewMatrix);
-
- virtual ~UniCam();
-
-
- // To make the interaction work, the following set of functions need to be
- // called from your GraphicsApp or whatever main application class you use
- // to receive user input events and a draw callback.
-
- /// Attach this to whatever mouse button you wish, for example, call this
- /// from within GraphicsApp::OnRightMouseDown(). If your mousePos is reported
- /// in pixels, you will need to convert it to normalized device coordinates
- /// before passing it on to this routine. The depth buffer value for the
- /// pixel under the mouse is also needed. If you are using GraphicsApp, you
- /// can access both of these as follows:
- /// ~~~
- /// Point2 mouse_xy = PixelsToNormalizedDeviceCoords(mouse_in_pixels);
- /// float mouse_z = ReadZValueAtPixel(mouse_in_pixels);
- /// uniCam.OnButtonDown(mouse_xy, mouse_z);
- /// ~~~
- void OnButtonDown(const Point2 &normalizedMousePos, float mouseZ);
-
- /// Attach this to the corresponding mouse move event, for example, call this
- /// from within GraphicsApp::OnRightMouseDrag(). If your mousePos is reported
- /// in pixels, you will need to convert it to normalized device coordinates
- /// before passing it on to this routine. Within GraphicsApp, use:
- /// ~~~
- /// Point2 mouse_xy = PixelsToNormalizedDeviceCoords(mouse_in_pixels);
- /// uniCam.OnDrag(mouse_xy);
- /// ~~~
- void OnDrag(const Point2 &normalizedMousePos);
-
- /// Attach this to the corresponding button up event, for example, call this
- /// from within GraphicsApp::OnRightMouseUp(). If your mousePos is reported
- /// in pixels, you will need to convert it to normalized device coordinates
- /// before passing it on to this routine. Within GraphicsApp, use:
- /// ~~~
- /// Point2 mouse_xy = PixelsToNormalizedDeviceCoords(mouse_in_pixels);
- /// uniCam.OnButtonUp(mouse_xy);
- /// ~~~
- void OnButtonUp(const Point2 &normalizedMousePos);
-
- /// Attach this to a callback that can be used to control animation. Within
- /// GraphicsApp::UpdateSimulation(), use:
- /// ~~~
- /// uniCam.AdvanceAnimation(dt);
- /// ~~~
- void AdvanceAnimation(double dt);
-
- /// Finally, attach this to your draw callback routine. Within
- /// GraphicsApp::DrawUsingOpenGL(), use:
- /// ~~~
- /// uniCam.Draw(projMatrix);
- /// ~~~
- void Draw(const Matrix4 &projectionMatrix);
-
-
- /// Access the camera view matrix created by the UniCam interactions via
- /// this method and use it to draw the geometry in your scence.
- /// For example, within GraphicsApp::DrawUsingOpenGL(), you might have:
- /// ~~~
- /// Matrix4 P = Matrix4::Perspective(30, aspect_ratio(), 1, 20);
- /// Matrix4 V = unicam.view_matrix();
- /// Matrix4 M = Matrix4::RotateY(GfxMath::ToRadians(45.0));
- /// quick_shapes.DrawCube(M, V, P, Color(1,1,1));
- /// ~~~
- Matrix4 view_matrix();
-
-
- /// Returns the "eye" point (i.e., focal point) of the camera in world
- /// space coordinates.
- Point3 eye();
-
- /// Returns the look direction (i.e., -Z axis of the camera matrix) in world
- /// space coordinates.
- Vector3 look();
-
-
- // -------------
-
- /// This is not required, but you may use this if you wish to set an initial
- /// view matrix or reset the view matrix
- void set_view_matrix(Matrix4 viewMatrix);
-
- /// This sets the depth of the center of rotation for the case when the user's
- /// click does not intersect any geometry. It defaults to 4 units, but the
- /// right value to use depends very much on the current scene. For example,
- /// you could set a very good value by calculating the current centroid of
- /// your scene and the finding the depth of this point (the distance along
- /// the look vector) relative to the camera.
- void set_default_depth(float d);
-
-
-private:
-
- void recalc_angular_vel();
-
- enum class UniCamState {
- START,
- PAN_DOLLY_ROT_DECISION,
- PAN_DOLLY_DECISION,
- ROT_WAIT_FOR_SECOND_CLICK,
- PAN,
- DOLLY,
- ROT,
- SPINNING
- };
- UniCamState state_;
-
- Point2 mouseLast_;
- double elapsedTime_;
-
- Point2 initialClickPos_;
- bool hitGeometry_;
- Point3 hitPoint_;
-
- bool rotInitialized_;
- Point3 rotLastIPoint_;
- float boundingSphereRad_;
- Point3 boundingSphereCtr_;
- double rotLastTime_;
- std::vector<std::pair<double, double>> rotAngularVelBuffer_;
- double rotAngularVel_;
- Vector3 rotAxis_;
-
- bool dollyInitialized_;
- float dollyFactor_;
- float defaultDepth_;
-
- bool showIcon_;
- QuickShapes quickShapes_;
-
- Matrix4 V_;
- Matrix4 Vstart_;
-
- // saved from the last draw call in order to unproject the mouse pos
- Matrix4 Pdraw_;
-};
-
-
-} // end namespace
-
-#endif
-
-
+/*
+ This file is part of the MinGfx Project.
+
+ Copyright (c) 2017,2018 Regents of the University of Minnesota.
+ All Rights Reserved.
+
+ Original Author(s) of this File:
+ Dan Keefe, 2018, University of Minnesota
+
+ Author(s) of Significant Updates/Modifications to the File:
+ ...
+ */
+
+#ifndef SRC_UNICAM_H_
+#define SRC_UNICAM_H_
+
+#include "quick_shapes.h"
+#include "point2.h"
+#include "point3.h"
+#include "vector2.h"
+#include "vector3.h"
+
+
+namespace mingfx {
+
+
+/** This implements a user interface for controlling the camera with the mouse.
+ It is a special interface inspired by the "Unicam" technique developed by
+ Zeleznik et al.
+
+ The key feature is that this interface makes it possible to control camera pan,
+ dolly, and rotation with only a single mouse button. That is quite useful
+ because it leaves the other mouse buttons free for pointing, sketching, or
+ other interaction techniques.
+
+ The only downside of this technique is that it can take some time to learn. In
+ order to enjoy it, you will need to read these brief instructions on how to Pan,
+ Dolly, Rotate, and Spin:
+
+ - Pan: Click and drag horizontally with the mouse. Once you make an initial
+ horizontal movement you can than pan up and down as well, but the key to entering
+ pan mode is to start with a horizontal movement.
+
+ - Dolly: Click and drag vertically with the mouse. The initial movement must
+ be vertical. If you click on some object in the scene, then the speed of dollying
+ is set so that the object will come all the up to the camera lens if you drag
+ the mouse to the bottom of the screen.
+
+ - Rotate: Start with a quick click and release to set the center of rotation.
+ This is most useful if you click on some object in the scene. You will see a
+ black dot appear to mark the center of rotation. If you click on the background
+ then a center of rotation will be selected for you. It will be a point straight
+ ahead and at a depth 4.0 units away. The depth can be adjusted for your application
+ with set_default_depth(). Once your center of rotation is established, move
+ your mouse away a bit and then click and drag to do a trackball rotatation of
+ the scene around this point. Come to a stop before letting go of the mouse
+ button in order to avoid entering the spin state!
+
+ - Spin: For some fun, try "throwing" the scene so that it continues to rotate
+ even after you let go. To do this, start a rotation and then let go of the
+ mouse button while your mouse is still moving. To stop spinning just click and
+ release the mouse once to "catch" the scene.
+
+
+ Example usage:
+~~~
+// Create a global or member variable in your MyGraphicsApp class:
+UniCam unicam_;
+
+
+void MyGraphicsApp::OnLeftMouseDown(const Point2 &pos) {
+ Point2 mouse_xy = PixelsToNormalizedDeviceCoords(pos);
+ float mouse_z = ReadZValueAtPixel(pos);
+ unicam_.OnButtonDown(mouse_xy, mouse_z);
+}
+
+void MyGraphicsApp::OnLeftMouseDrag(const Point2 &pos, const Vector2 &delta) {
+ Point2 mouse_xy = PixelsToNormalizedDeviceCoords(pos);
+ unicam_.OnDrag(mouse_xy);
+}
+
+void MyGraphicsApp::OnLeftMouseUp(const Point2 &pos) {
+ Point2 mouse_xy = PixelsToNormalizedDeviceCoords(pos);
+ unicam_.OnButtonUp(mouse_xy);
+}
+
+void MyGraphicsApp::InitOpenGL() {
+ projMatrix_ = Matrix4::perspective(30, aspect_ratio(), 1, 20);
+ unicam_.set_view_matrix(Matrix4::lookAt(Point3(2.5,1,2.5), Point3(0,0,0), Vector3(0,1,0)););
+}
+
+void MyGraphicsApp::DrawOpenGL() {
+ // draw your scene using the view matrix from UniCam
+ Matrix4 proj_matrix = Matrix4::Perspective(60, aspect_ratio(), 0.001, 10);;
+ Matrix4 view_matrix = uniCam.view_matrix();
+ Matrix4 model_matrix = Matrix4::RotateY(to_radians(45.0));
+ quickShapes.DrawCube(model_matrix, view_matirx, proj_matrix, Color(1,1,1));
+
+ // tell unicam to draw itself (i.e., the small sphere that marks the center of
+ // rotation when in rotation mode)
+ unicam_.Draw(proj_matrix);
+}
+~~~
+*/
+class UniCam {
+public:
+
+ /// Creates a UniCam object with an initial view matrix = identity.
+ UniCam();
+
+ /// Creates a UniCam object with the supplied initial view matrix.
+ UniCam(const Matrix4 &initialViewMatrix);
+
+ virtual ~UniCam();
+
+
+ // To make the interaction work, the following set of functions need to be
+ // called from your GraphicsApp or whatever main application class you use
+ // to receive user input events and a draw callback.
+
+ /// Attach this to whatever mouse button you wish, for example, call this
+ /// from within GraphicsApp::OnRightMouseDown(). If your mousePos is reported
+ /// in pixels, you will need to convert it to normalized device coordinates
+ /// before passing it on to this routine. The depth buffer value for the
+ /// pixel under the mouse is also needed. If you are using GraphicsApp, you
+ /// can access both of these as follows:
+ /// ~~~
+ /// Point2 mouse_xy = PixelsToNormalizedDeviceCoords(mouse_in_pixels);
+ /// float mouse_z = ReadZValueAtPixel(mouse_in_pixels);
+ /// uniCam.OnButtonDown(mouse_xy, mouse_z);
+ /// ~~~
+ void OnButtonDown(const Point2 &normalizedMousePos, float mouseZ);
+
+ /// Attach this to the corresponding mouse move event, for example, call this
+ /// from within GraphicsApp::OnRightMouseDrag(). If your mousePos is reported
+ /// in pixels, you will need to convert it to normalized device coordinates
+ /// before passing it on to this routine. Within GraphicsApp, use:
+ /// ~~~
+ /// Point2 mouse_xy = PixelsToNormalizedDeviceCoords(mouse_in_pixels);
+ /// uniCam.OnDrag(mouse_xy);
+ /// ~~~
+ void OnDrag(const Point2 &normalizedMousePos);
+
+ /// Attach this to the corresponding button up event, for example, call this
+ /// from within GraphicsApp::OnRightMouseUp(). If your mousePos is reported
+ /// in pixels, you will need to convert it to normalized device coordinates
+ /// before passing it on to this routine. Within GraphicsApp, use:
+ /// ~~~
+ /// Point2 mouse_xy = PixelsToNormalizedDeviceCoords(mouse_in_pixels);
+ /// uniCam.OnButtonUp(mouse_xy);
+ /// ~~~
+ void OnButtonUp(const Point2 &normalizedMousePos);
+
+ /// Attach this to a callback that can be used to control animation. Within
+ /// GraphicsApp::UpdateSimulation(), use:
+ /// ~~~
+ /// uniCam.AdvanceAnimation(dt);
+ /// ~~~
+ void AdvanceAnimation(double dt);
+
+ /// Finally, attach this to your draw callback routine. Within
+ /// GraphicsApp::DrawUsingOpenGL(), use:
+ /// ~~~
+ /// uniCam.Draw(projMatrix);
+ /// ~~~
+ void Draw(const Matrix4 &projectionMatrix);
+
+
+ /// Access the camera view matrix created by the UniCam interactions via
+ /// this method and use it to draw the geometry in your scence.
+ /// For example, within GraphicsApp::DrawUsingOpenGL(), you might have:
+ /// ~~~
+ /// Matrix4 P = Matrix4::Perspective(30, aspect_ratio(), 1, 20);
+ /// Matrix4 V = unicam.view_matrix();
+ /// Matrix4 M = Matrix4::RotateY(GfxMath::ToRadians(45.0));
+ /// quick_shapes.DrawCube(M, V, P, Color(1,1,1));
+ /// ~~~
+ Matrix4 view_matrix();
+
+
+ /// Returns the "eye" point (i.e., focal point) of the camera in world
+ /// space coordinates.
+ Point3 eye();
+
+ /// Returns the look direction (i.e., -Z axis of the camera matrix) in world
+ /// space coordinates.
+ Vector3 look();
+
+
+ // -------------
+
+ /// This is not required, but you may use this if you wish to set an initial
+ /// view matrix or reset the view matrix
+ void set_view_matrix(Matrix4 viewMatrix);
+
+ /// This sets the depth of the center of rotation for the case when the user's
+ /// click does not intersect any geometry. It defaults to 4 units, but the
+ /// right value to use depends very much on the current scene. For example,
+ /// you could set a very good value by calculating the current centroid of
+ /// your scene and the finding the depth of this point (the distance along
+ /// the look vector) relative to the camera.
+ void set_default_depth(float d);
+
+
+private:
+
+ void recalc_angular_vel();
+
+ enum class UniCamState {
+ START,
+ PAN_DOLLY_ROT_DECISION,
+ PAN_DOLLY_DECISION,
+ ROT_WAIT_FOR_SECOND_CLICK,
+ PAN,
+ DOLLY,
+ ROT,
+ SPINNING
+ };
+ UniCamState state_;
+
+ Point2 mouseLast_;
+ double elapsedTime_;
+
+ Point2 initialClickPos_;
+ bool hitGeometry_;
+ Point3 hitPoint_;
+
+ bool rotInitialized_;
+ Point3 rotLastIPoint_;
+ float boundingSphereRad_;
+ Point3 boundingSphereCtr_;
+ double rotLastTime_;
+ std::vector<std::pair<double, double>> rotAngularVelBuffer_;
+ double rotAngularVel_;
+ Vector3 rotAxis_;
+
+ bool dollyInitialized_;
+ float dollyFactor_;
+ float defaultDepth_;
+
+ bool showIcon_;
+ QuickShapes quickShapes_;
+
+ Matrix4 V_;
+ Matrix4 Vstart_;
+
+ // saved from the last draw call in order to unproject the mouse pos
+ Matrix4 Pdraw_;
+};
+
+
+} // end namespace
+
+#endif
+
+