390 likes | 593 Views
Viewing and Camera Rotations. CSE 781 Prof. Roger Crawfis. Introduction to 3D viewing. 3D is just like taking a photograph! . Viewing Transformation. Position and orient your camera. Projection Transformation. Control the “lens” of the camera Project the object from 3D world to 2D screen.
E N D
Viewing and Camera Rotations CSE 781 Prof. Roger Crawfis
Introduction to 3D viewing • 3D is just like taking a photograph!
Viewing Transformation • Position and orient your camera
Projection Transformation • Control the “lens” of the camera • Project the object from 3D world to 2D screen
(ex, ey, ez) world view up vector (Up_x, Up_y, Up_z) (cx, cy, cz) Viewing Transformation (2) • Important camera parameters to specify • Camera (eye) position (Ex,Ey,Ez) in world coordinate system • Center of interest (coi) (cx, cy, cz) • Orientation (which way is up?) View-up vector (Up_x, Up_y, Up_z)
u v n y Eye coordinate frame coi world x z Viewing Transformation (3) • Transformation? • Form a camera (eye) coordinate frame • Transform objects from world to eye space
world Viewing Transformation (4) • Eye space? • Transform to eye space can simplify many downstream operations (such as projection) in the pipeline (1,0,0) (0,1,0) u v (0,0,1) n y (0,0,0) coi x z
Viewing Transformation (5) • In OpenGL: - gluLookAt (Ex, Ey, Ez, cx, cy, cz, Up_x, Up_y, Up_z) - The view up vector is usually (0,1,0) - Remember to set the OpenGL matrix mode to GL_MODELVIEW first
Viewing Transformation (6) void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,1,0,0,0,0,1,0); display_all(); // your display routine } If this is constant, why do it every frame?
Suppose we have three orthogonal vectors… • v1,v2,v3 • Let’s build a matrix like this: • This will rotate: v1 onto the x axis, v2 onto the y axis, v3 onto the z axis
My Version of gluLookAt() void mygluLookAt(Point3 eye, Point3 center, Point3 up) { Point3 cameraZ = Normalize( eye – center ); // v3 Point3 cameraX = Normalize( Cross(up, cameraZ) ); // v1 Point3 cameraY = Cross( cameraZ, cameraX ); // v2 GLdouble m[16]; // Fill the matrix in row by row m[0] = cameraX.X; m[4] = cameraX.Y; m[8] = cameraX.Z; m[12] = 0.0; m[1] = cameraY.X; m[5] = cameraY.Y; m[9] = cameraY.Z; m[13] = 0.0; m[2] = cameraZ.X; m[6] = cameraZ.Y; m[10] = cameraZ.Z; m[14] = 0.0; m[3] = m[7] = m[11] = 0.0; m[15] = 1.0; glMultMatrixd( m ); glTranslated( -eye.X, -eye.Y, -eye.Z ); } Order of transformations!
Messing with the camera • What if I want to PAN the camera? • We need to define “PAN” • There are two possibilities • Crab • Pan
Panning • Suppose we pan around the camera Y axis • This is NOT “up” in world space. • We need to change the lookAt point.
Operations on Points in Space • LookAt is a point in space • Need these transformations: • Translate by –eye • Rotate frame onto axis (using some M) • Rotate around Y by pan angle • Inverse rotate M • Translate by eye • PP=T(eye) MT RY(q) M T(-eye)
Easier #1 • Just replace the matrix using gluLookAt. • Problems?
Easier #2 • The first 2 operations are already what is done to set the camera up: • M T(-eye) • We just need to add a rotate after this is done. • Implies we want to pre-multiply by a rotation matrix.
Easier #2 • Steps: • Read out the current matrix. • Set the matrix to the identity matrix. • Rotate about the y-axis the amount we want to pan. • Post-multiply by the matrix read out in step #1. With GLSL Shaders, the OpenGL matrix system does not buy you much, so just use your own matrix classes.
Eliot Lash, 2007 (from Wikipedia.org – Camera dolly) Camera Controls • Tilt • Roll • Dolly • Boom • Zoom (same as dolly?) • General camera (or entity) movement and the user interface / control.
Camera Controls • Stationary • 2 degrees of freedom + zoom • QuicktimeVR
Interactive Applications • How do we add interactive control? • Many different paradigms • Examiner => Object in hand • Fly-thru => In a virtual vehicle pod • Walk-thru => Constrained to stay on ground. • Move-to / re-center => Pick a location to fly to. • Collision detection? • Can we pass thru objects like ghosts?
Interactive Applications • What do we use to control the motion? • Mouse • One-button, two-button, three-button • What button does what? • Only when mouse is clicked down, released up, or continuously as the mouse moves? • Keyboard • Arrow keys?
Input Devices • Interactive user control devices • Mouse • 3D pointer - Polhemus, Microscribe, … • Spaceball • Hand-held wand • Data Glove • Gesture • Custom
A Virtual Trackball • A rather standard and easy-to-use interface. • Examiner type of interaction. • Consider a hemi-sphere over the image-plane. • Each point in theimage is projectedonto the hemi-sphere.
A Virtual Trackball • Points inside the projection of the hemi-sphere are mapped up to the surface. • Determine distance from point (mouse position) to the image-plane center. • Scale such that points on the silhouette of the sphere have unit length. • Add the z-coordinate tonormalize the vector.
A Virtual Trackball • Do this for all points. • Keep track of the last trackball (mouse) location and the current location. • This is the direction we want the scene to move in. • Take the direction perpendicular to this and use it as the axis of rotation. • Use the distance between the two points to determine the rotation angle (or amount).
A Virtual Trackball • Rotation axis: Where, v1 and v2 are themouse points mappedto the sphere. v2 | sin q| = v1
z y (x,y,0) x Virtual Trackball • How to calculate p1 and p2? • Assuming the mouse position is (x,y), then the sphere point P also has x and y coordinates equal to x and y • Assume the radius of the hemi-sphere is 1. So the z coordinate of P is • Note: normalize viewport y extend to -1 to 1 • If a point is outside the circle, project it to the nearest point on the circle (set z to 0 and renormalize (x,y))
Virtual Trackball Visualization of the algorithm
Example • Example from Ed Angel’s OpenGL Primer • In this example, the virtual trackball is used to rotate a color cube • The code for the colorcube function is omitted • I will not cover the following code, but I am sure you will find it useful • Note you can use the trackball to move the camera or you can apply the rotations to a transform node in your scene graph to move an object. The rotations are negated from each other though.
Initialization #define bool int /* if system does not support bool type */ #define false 0 #define true 1 #define M_PI 3.14159 /* if not in math.h */ int winWidth, winHeight; float angle = 0.0, axis[3], trans[3]; bool trackingMouse = false; bool redrawContinue = false; bool trackballMove = false; float lastPos[3] = {0.0, 0.0, 0.0}; int curx, cury; int startX, startY;
The Projection Step void trackball_ptov(intx, int y, int width, int height, float v[3]) { float d, a; /* project x,y onto a hemisphere centered within width, height , note z is up here*/ v[0] = (2.0*x - width) / width; v[1] = (height - 2.0F*y) / height; d = sqrt(v[0]*v[0] + v[1]*v[1]); v[2] = cos((M_PI/2.0) * ((d < 1.0) ? d : 1.0)); a = 1.0 / sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] *= a; v[1] *= a; v[2] *= a; }
glutMotionFunc (1) Void mouseMotion(int x, int y) { float curPos[3], dx, dy, dz; /* compute position on hemisphere */ trackball_ptov(x, y, winWidth, winHeight, curPos); if(trackingMouse) { /* compute the change in position on the hemisphere */ dx = curPos[0] - lastPos[0]; dy = curPos[1] - lastPos[1]; dz = curPos[2] - lastPos[2];
glutMotionFunc (2) if (dx || dy || dz) { /* compute theta and cross product */ angle = 90.0 * sqrt(dx*dx + dy*dy + dz*dz); axis[0] = lastPos[1]*curPos[2] – lastPos[2]*curPos[1]; axis[1] = lastPos[2]*curPos[0] – lastPos[0]*curPos[2]; axis[2] = lastPos[0]*curPos[1] – lastPos[1]*curPos[0]; /* update position */ lastPos[0] = curPos[0]; lastPos[1] = curPos[1]; lastPos[2] = curPos[2]; } } glutPostRedisplay(); }
Idle and Display Callbacks void spinCube() { if (redrawContinue) glutPostRedisplay(); } void display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); if (trackballMove) { glRotatef(angle, axis[0], axis[1], axis[2]); } colorcube(); glutSwapBuffers(); }
Mouse Callback void mouseButton(int button, int state, int x, int y) { if(button==GLUT_RIGHT_BUTTON) exit(0); /* holding down left button allows user to rotate cube */ if(button==GLUT_LEFT_BUTTON) switch(state) { case GLUT_DOWN: y=winHeight-y; startMotion( x,y); break; case GLUT_UP: stopMotion( x,y); break; } }
Start Function void startMotion(int x, int y) { trackingMouse = true; redrawContinue = false; startX = x; startY = y; curx = x; cury = y; trackball_ptov(x, y, winWidth, winHeight, lastPos); trackballMove=true; }
Stop Function void stopMotion(int x, int y) { trackingMouse = false; /* check if position has changed */ if (startX != x || startY != y) redrawContinue = true; else { angle = 0.0; redrawContinue = false; trackballMove = false; } }
publicvoidKeyTrackballArrows( object sender, Forms.KeyEventArgse ) { // This provides a simple mapping of the keyboard to rotations of the // object (or the world if used in a camera). // The SHIFT key can be used for gross changes, the CTRL key can be // used for fine-control. Vector3 rotationAxis = XAxis; float sign = 1.0f; if( e.KeyCode == Keys.Up) { rotationAxis = XAxis; sign = -1.0f; } elseif( e.KeyCode == Keys.Down) { rotationAxis = XAxis; } elseif( e.KeyCode == Keys.Left ) { rotationAxis = YAxis; sign = -1.0f; } elseif( e.KeyCode == Keys.Right ) { rotationAxis = Yaxis; } else{ return; } floatrotationAngle = RotationIncrementStandard; if( e.Modifiers == Keys.Shift) rotationAngle = RotationIncrementLarge; elseif( e.Modifiers == Keys.Control) rotationAngle = RotationIncrementSmall; if( rotate != null ) { rotate( sign*rotationAngle, rotationAxis); } }