  binocularity.org Knowledge about all aspects of 3D displays and their application.  Home 3D Displays Human 3D Vision Creating 3D Images Resources   Drawing stereo pairs  Toed-in cameras  Parallel cameras  3D photography method  ..3D photography equipment  3D filming  Stereoscopic OpenGL  ..Toed-in OpenGL example  ..Parallel OpenGL example ..Parallel OpenGL example Contributors: Jimmy Kay, Peter Hughes, Nick Holliman Source code files:  Download Binocularity OpenGL Examples (Python) A parallel camera set up avoids many of the issues associated with Toed-in camera implementation. As the name suggests the cameras are parallel, with no inward rotation or vergence point. The above diagram shows the Parallel camera setup, again in relation to the ANAGLYPH option in the demos. The diagram clearly shows no rotation, and therefore no risk of producing vertical parallax. When running the parallel.py demo, no vertical parallax is shown, allowing for more effective, and more comfortable stereo viewing, as can be seen below. The image magnifies the top left cube for clarity. Note, unlike the toed-in approach, the absence of vertical disparity, and associated effects of rotation such as the apparent curvature of the image when viewed in stereo. Setting the camera parameters (Parallel) The main differences between the Toed-in and Parallel approaches, are found within stereoCamera.py                 def update( self ):         w = 518.4         h = 324.0                 Z = 1000.0                A = 65.0         Near = 800.0          Far = 1200.0         L_l =  -( Near * ( ( w/2.0 - A/2.0 )/ Z ) )         L_r =   ( Near * ( ( w/2.0 + A/2.0 )/ Z ) )         L_b = - ( Near * ( (h/2.0)/Z) )         L_t =   ( Near * ( (h/2.0)/Z) )         R_l =  -( Near * ( ( w/2.0 + A/2.0 )/ Z ) )         R_r =   ( Near * ( ( w/2.0 - A/2.0 )/ Z ) )         R_b = - ( Near * ( (h/2.0)/Z) )         R_t =   ( Near * ( (h/2.0)/Z) )                 self.lookAtLeft = ( -A/2, 0, 0, -A/2, 0, -Z, 0, 1, 0 )                     self.lookAtRight = ( A/2, 0, 0, A/2, 0, -Z, 0, 1, 0 )                 self.frustumLeft = ( L_l, L_r, L_b, L_t, Near, Far )         self.frustumRight = ( R_l, R_r, R_b, R_t, Near, Far ) The lookAt references are almost identical to that of Toed-in lookAt points, with the exception of the X axis for centre position of the reference point (the point at which the cameras aim). This value must be equal to the eye (camera position) point to achieve the parallel camera orientation. The most significant difference in the two implementations originates from the absence of gluPerspective, and the introduction of a left and right frustum for the perspective viewing matrix. Frustums for both left and right views require parameters for Left, Right, Bottom, and Top clipping panes, in addition to the Near and Far values for depth of the scene. Bottom and Top values will be identical for both the Left and Right viewing perspective, but Left and Right clipping panes will differ to account for eye separation (A) as used for both LookAt points. Accurate values for both the left and right frustum parameters are calculated below:    Calculating left clipping pane Left Eye view (L_l) And right clipping pane Right Eye view (R_r)                         ( Near * ( ( w/2.0 - A/2.0 )/ Z ) )             w = 518.4        518.4/2 = 259.2       65/2 = 32.5 A = 65            259.2 – 32.5 =     226.7 Z = 1000            Near = 800        226.7/1000 = 0.2267                         800 * 0.2267 = 181.36                         L_l  =  -181.36             R_r =  181.36 Calculating right clipping pane Left Eye view (L_r) And left clipping pane Right Eye view (R_l)                 ( Near * ( ( w/2.0 + A/2.0 )/ Z ) ) w = 518.4        518.4/2 = 259.2       65/2 = 32.5 A = 65            259.2 + 32.5 =     291.7 Z - 1000 Near = 800        29.17/1000 = 0.2917             800 * 0.2917 = 233.36                         L_r =  233.36             R_l =  -233.36 Calculating top and bottom clipping panes Left and Right Eye views (L_t, R_t, L_b, R_b) ( Near * ( (h/2.0)/Z) ) H = 324            324/2 = 162 Z = 1000            Near = 800        162/1000 = 0.162             800 * 0.162 = 129.6             L_t and R_t  =  129.6             L_b and R_b  =  -129.6 NB Frustum values above should be calculated to correspond to the near depth clipping pane, and not the screen plane (Z). from the source file parallel.py def render( side ):     """Render scene in either GLU_BACK_LEFT or GLU_BACK_RIGHT buffer"""     boxSize = 50     separate = 100     glViewport( 0, 0,         glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT ))     if side == GL_BACK_LEFT:         f = sC.frustumLeft         l = sC.lookAtLeft     else:         f = sC.frustumRight         l = sC.lookAtRight     glMatrixMode(GL_PROJECTION)     glLoadIdentity()     glFrustum( f, f, f, f, f, f )     glMatrixMode(GL_MODELVIEW)     glLoadIdentity()     gluLookAt( l, l, l, l, l, l, l, l, l ) Both toedin.py and parallel.py are virtually identical, only a small portion of the above code varies. In parallel.py the Left and Right buffers are rendered using f as the instantiated variable for glFrustum, and l for gluLookAt. Home 3D Displays Human 3D Vision Creating 3D Images Resources