_Stereoscopic Imaging_ by Andy Ramm Example 1: (a) window (-top * aspect + (half_sep * clip_near / distance), top * aspect + (half_sep * clip_near / distance), -top, top, clip_near, clip_far); translate (half_sep, 0.0, 0.0); (b) window (-top * aspect - (half_sep * clip_near / distance), top * aspect - (half_sep * clip_near / distance), -top, top, clip_near, clip_far); translate (-half_sep, 0.0, 0.0); Listing One #if STEREO #define EYE_OFFSET 0.200 // default viewpoint separation #define EYE_ADJUST -0.070 // default horizontal image shift adjustment int winWidth, winHeight; // client window int winAdjust=30; // Y height adjustment to "above" viewport GLfloat eyeDist=4.5; // Z distance for zero parallax setting GLfloat eyeOffset=EYE_OFFSET; // X offset for left/right viewpoint separation GLfloat eyeAdjust=EYE_ADJUST; // X adjustment for horizontal image shift #endif static void CALLBACK Reshape(int width, int height) { #if STEREO winWidth = width; winHeight = height; // viewport and perspective matrixes must be updated every drawn frame to // render left/right views in above/below format onto same client window #else glViewport(0, 0, (GLint)width, (GLint)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 1, 10); gluLookAt(2, 2, 2, 0, 0, 0, 0, 0, 1); glMatrixMode(GL_MODELVIEW); #endif } static void CALLBACK Draw(void) { #if STEREO // calculate delta-X translation for left or right perspective view GLfloat dx0 = eyeAdjust; // asymmetrical viewing pyramid offset GLfloat dx1 = eyeOffset; // viewpoint separation // set "above" viewport for left eye rendering glViewport(0, (GLint)(winHeight/2 + winAdjust), (GLint)winWidth, (GLint)(winHeight/2 - winAdjust)); // set left-eye perspective glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1-dx0, 1-dx0, -1, 1, 1, 10); // skew viewer symmetry leftward glTranslatef(0+dx1, 0, 0); // move rightward for left eye view glTranslatef(0, 0, -3); // pull back to look at glMatrixMode(GL_MODELVIEW); #endif // STEREO glLoadIdentity(); glRotatef(xRotation, 1, 0, 0); glRotatef(yRotation, 0, 1, 0); glRotatef(zRotation, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); switch (whichQuadric) { case 0: glTranslatef(0, 0, -height/20.0); gluCylinder(quadObj,radius1/10.0,radius2/10.0,height/10.0,slices,stacks); break; case 1: gluSphere(quadObj, radius1/10.0, slices, stacks); break; case 2: gluPartialDisk(quadObj, radius2/10.0, radius1/10.0, slices, stacks, angle1, angle2); break; case 3: gluDisk(quadObj, radius2/10.0, radius1/10.0, slices, stacks); break; } # if STEREO // set "below" viewport for right eye rendering glViewport(0, 0, (GLint)winWidth, (GLint)(winHeight/2 - winAdjust)); // set right-eye perspective glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1+dx0, 1+dx0, -1, 1, 1, 10); // skew viewer symmetry rightward glTranslatef(0-dx1, 0, 0); // move leftward for right eye view glTranslatef(0, 0, -3); // pull back to look at glMatrixMode(GL_MODELVIEW); // render scene again for right-eye view glLoadIdentity(); glRotatef(xRotation, 1, 0, 0); glRotatef(yRotation, 0, 1, 0); glRotatef(zRotation, 0, 0, 1); glColor3f(1.0, 1.0, 1.0); switch (whichQuadric) { case 0: glTranslatef(0, 0, -height/20.0); gluCylinder(quadObj, radius1/10.0, radius2/10.0, height/10.0, slices, stacks); break; case 1: gluSphere(quadObj, radius1/10.0, slices, stacks); break; case 2: gluPartialDisk(quadObj, radius2/10.0, radius1/10.0, slices, stacks, angle1, angle2); break; case 3: gluDisk(quadObj, radius2/10.0, radius1/10.0, slices, stacks); break; } #endif // STEREO glFlush(); if (doubleBuffer) { auxSwapBuffers(); }