binocularity.org
Knowledge about all aspects of 3D displays and their application.
Home3D DisplaysHuman 3D VisionCreating 3D ImagesResources

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)
                           Download Binocularity OpenGL Examples (C++)



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[0], f[1], f[2], f[3], f[4], f[5] )
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt( l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8] )


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.


Home3D DisplaysHuman 3D VisionCreating 3D ImagesResources