Writing Stereoscopic Software for StereoGraphics® Systems Using Microsoft Windows® OpenGL

来源:互联网 发布:java string isempty 编辑:程序博客网 时间:2024/06/05 14:10

WritingStereoscopic Software for StereoGraphics® Systems Using

MicrosoftWindows® OpenGL

By Bob Akka StereoGraphics Corporation August 13, 1998

www.stereographics.com

Copyright ©1998 StereoGraphicsCorporation; All Rights Reserved.

Introduction| Hardware| Initializinga Window | WritingBuffers | StereoPersective Projections | AssymetricFrustrum Projections | CameraOffset | Aesthetics| Above-BelowStereo | Pontsto Remember | Resources

1.Introduction

NewPC graphics cards which include built-in support for stereoscopic buffering,along with a standardized OpenGL interface to those cards' stereo supportfeatures, now make it easier than ever to add stereo support to PCWindows-based applications. Another big advantage of these new stereo OpenGLgraphics card implementations is that applications are now free to display 3Dgraphics elements stereoscopically without having to fill the entire screen,and in combination with other non-stereo windows and interface elements.

StereoOpenGL buffering is supported by Microsoft Windows NT 4.0 and later. Windows 95(Service Pack 2) and later also support stereo OpenGL buffering, though, insome cases, board manufacturers only provide stereo support with their WindowsNT drivers.

Thisdocument covers the steps that you need to take to:

  • Set up for stereo development,
  • Query the graphics hardware for stereo buffering support,
  • Enable stereo buffering in a display window,
  • Write to separate stereo buffers,
  • Do stereo perspective projections, and
  • Set up your projections for excellent stereo image quality.

Westrongly recommend that you also obtain "OGLPlane", a verysimple stereo example program that illustrates most of the concepts that arediscussed in this document. The "OGLPlane" source code andexecutable files are available from StereoGraphics.

Finally,this document will discuss Above-Below stereo formatting, which is used withsome CrystalEyesâ and Z-Screenâ hardware implementations, and which does notrequire a specially equipped graphics board. Please see "2. SettingUp Your Graphics Hardware To Support Stereo" for a discussionabout the difference between OpenGL stereo buffering and Above-Belowformatting, and "9.Above-Below Stereo Formatting" for programming information that isspecific to the Above-Below format. Sections 5 through 8,relating to stereoscopic projections, are equally applicable regardless ofwhether one uses OpenGL stereo buffering or Above-Below stereo formatting.

2. Setting Up Your Graphics Hardware To Support Stereo

Graphicscards that support stereoscopic buffering are able to simultaneously maintainboth left- and right-eye graphics buffers. This means that, in combination withstandard double-buffering (in which graphics are drawn to a "backbuffer" and then swapped to the "front buffer" when all drawingis completed), the board will typically maintain four buffers when in stereodisplay mode.

Becauseof the additional memory requirements that stereo buffering demands, videoboards will often not be configured to support stereo by default. Afterobtaining a video board that supports OpenGL stereo buffering, you willprobably need to set up your display configuration to support stereo. Stereosupport may be restricted to certain display resolutions and settings. Pleasecheck graphics card documentation and/or special card-specific documentationfrom StereoGraphics for further installation details.

Ifyou are developing software that you want to be able to run on any video card,including those that do not support stereo buffering, you might considerAbove-Below stereo formatting. In addition to the stereo viewing systems thatStereoGraphics makes to work with video cards that directly support stereobuffering, StereoGraphics also makes a stereo viewing system which usessync-doubling technology to enable stereo with just about any PC video card.This ability to use almost any PC video card is the main advantage ofAbove-Below stereo formatting. The disadvantages, compared to stereo OpenGLbuffering, are:

  • Above-Below requires graphics windows that fill the entire screen, whereas stereo buffering systems permit windowed stereoscopy;
  • Above-Below makes it difficult to incorporate standard non-stereo interface elements, such as menus and dialog boxes, into the application while stereo viewing is active, whereas standard interface elements work fine with stereo buffering systems;
  • Above-Below stereo formatting requires graphics viewports whose pixel aspect ratios are vertically squashed; this is not an issue with stereo buffering systems;
  • Above-Below stereo formatting typically requires that the user do a "calibration" step in order for the vertical alignment to be correct; this is not an issue with stereo buffering systems.

Mostcompanies that are currently developing software that supports stereo aretargeting systems whose graphics cards include built-in support for stereoOpenGL buffering. However, if you are interested in the Above-Below method ofsupporting stereo, please see the detailed discussion about Above-Below towardsthe end of this document.

3. Initializing a Window to Enable Stereo

Inorder to utilize OpenGL's stereo buffering support, a graphics window must beinitialized using the Windows API call, SetPixelFormat(), withthe pixel format descriptor flag, PFD_STEREO, set. Here is some sample code,called from a method of the graphics window's class:

PIXELFORMATDESCRIPTOR pfd;
memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR)); //clear all to 0
pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_GDI |
     PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL |PFD_STEREO;

intiPixelFormat = ChoosePixelFormat (hdc, &pfd);
BOOL bSuccess = SetPixelFormat (hdc, iPixelFormat, &pfd);

SetPixelFormat()should be called only after a meaningful device context is available for it; itis generally good to do this right after ShowWindow() has beencalled.

Notethat Microsoft Windows only allows SetPixelFormat() to becalled once for any given window. Subsequent SetPixelFormat() calls,for any given window, are ignored. Thus, the PFD_STEREO flag must beset within a window's very first SetPixelFormat() call.

Ifthe user's graphics configuration is not set up for stereo buffering, Windowswill not allow the PFD_STEREO flag to be set. Thus, after trying to set the PFD_STEREOflag, you should always check to see if the attempted stereo enabling actuallysucceeded in changed the flag. Here's how:

BOOLbStereoAvailable;
// pCDC, iPixelFormat, pfd are declared in above code

iPixelFormat = GetPixelFormat(pCDC->m_hAttribDC);

DescribePixelFormat (pCDC->m_hAttribDC,iPixelFormat, sizeof
   (PIXELFORMATDESCRIPTOR), &pfd);

if((pfd.dwFlags & PFD_STEREO) == 0) // stereo mode not accepted
   bStereoAvailable = FALSE;

else// yes we're now in stereo
   bStereoAvailable = TRUE;

Whatif the outcome of the above test is that stereo display is not supported by thecurrent display configuration? A display configuration might fail to supportstereo for one of several reasons:

  • The graphics card does not support stereo buffering,
  • The graphics driver does not support stereo buffering,
  • Stereo buffering is only supported at certain display resolutions or settings, or
  • Stereo buffering needs to be specially activated using some driver-specific configuration step.

OpenGLalso provides a way to query the availability of stereo buffering support,using the following code:

BOOLbStereoAvailable;
unsigned char ucTest;
glGetBooleanv (GL_STEREO, &ucTest);
if (ucTest)        // yes stereo support available
   bStereoAvailable = TRUE;

else       // stereo support not available
   bStereoAvailable = FALSE;

Unfortunately,this glGetBooleanv() approach has proven unreliable with some graphics driverconfigurations. Thus, we recommend "querying" the graphicsconfiguration for stereo support by actually trying to enable a window tosupport stereo buffering (by doing a SetPixelFormat() callwith PFD_STEREO set), and then checking to see if the attempt succeeded (bychecking whether the PFD_STEREO flag remains set).

4. Writing to Separate Stereo Buffers

TheglDrawBuffer() OpenGL function allows you to specify which buffer subsequentOpenGL drawings and renderings should be directed to. With normal non-stereoOpenGL double-buffering, you will typically draw to the "back buffer"(glDrawBuffer(GL_BACK);), and then "swap buffers" (wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);) in order to put what you had drawn to the back buffer onto the"front buffer", which represents the visible display.

Onceyou have initialized a window to support stereo buffering using SetPixelFormat() (see "3.Initializing a Window to Enable Stereo"), you can specify yourdrawing buffer as GL_BACK_LEFT or GL_BACK_RIGHT, which will result in subsequent OpenGL drawings and renderingsappearing only in one eye's drawing buffer. After drawing to both the left andright back-buffers, do a single wglSwapLayerBuffers() call to put the backstereo buffers' contents to the front (visible) stereo buffers. Here is anexample in which different colored rectangles are drawn to left and right eyebuffers:

// pCDC already declared as pointer tocurrent CDC

     //Clear both back buffers
glDrawBuffer (GL_BACK);
glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);

     //Draw left eye view
glDrawBuffer (GL_BACK_LEFT);
glColor3b (0, 0, 127); // blue
glRectf (-0.8f, -0.8f, 0.2f, 0.2f);

     //Draw right eye view

glDrawBuffer(GL_BACK_RIGHT);

glColor3b (127, 0, 0); // red
glRectf (-0.2f, -0.2f, 0.8f, 0.8f);

     //Put what was just drawn onto the display
BOOL bSuccess = wglSwapLayerBuffers (pCDC->m_hDC, WGL_SWAP_MAIN_PLANE);

Asthe above code example shows, you can still use glDrawBuffer(GL_BACK) todraw to both left and right back-buffers at once. Also note that you can use glDrawBuffer()to access the left and right front-buffers directly (GL_FRONT_LEFTand GL_FRONT_RIGHT).

5. An Introduction to Stereoscopic Perspective Projections

Younow know everything you need to know to put different stuff into left-eye andright-eye buffers. Now comes the interesting part: Doing perspectiveprojections that will result in a stereoscopic effect that is bothgeometrically correct and pleasing to look at.

Agood quality stereo image is composed of two stereo pair elements, each ofwhich being a perspective projection whose "center of projection"(let's use the simpler term, "camera", instead) is offset laterallyrelative to the other camera position.

Let'sstart with the mathematical representation of a simple non-stereo perspectiveprojection. Assuming that the camera lies on the positive zaxis at (0,0, d) (this document uses a "right handed" coordinate system), dbeing the distance from the camera to the xyplane, (x, y, z),projects onto the xyplane at:

(Equation1)          

Thus,for example, if the camera is placed at (0, 0, 9), the arbitrary point (8,5, 3) will project to (6, 3.75). See Figure 1 for a visualrepresentation of perspective projection.

Figure1: A Perspective Projection of Two Points

Next,we'll introduce a camera offset to the projection. To do a left-cameraperspective projection, we'll offset the camera to the left by half the overallcamera separation, (c/2). Except that, to make the math easier, we'lloffset the entire scene to the right instead of offsetting the camera to theleft. So, the left-camera projection of (x, y, z) now calculates to:

(Equation2)          

And,for the right-camera projection, we'll offset the entire scene to the left; theright-camera projection of (x, y, z) now calculates to:

(Equation3)          

Let'sgo back to the example, with the original camera at (0, 0, 9) and thearbitrary point (8, -5, -3). If we use a camera separation of 1,the left camera projects to (6.375, -3.75), and the right cameraprojects to (5.625, -3.75).

Noticehow, in the above example, the arbitrary point ends up projecting 0.75 unitsto the right in the left-camera view relative to its projection in theright-camera view. If one projection is superimposed over the other in a stereoviewing system, this will result in the arbitrary point appearing in what isthe optics folks call "negative parallax", meaning that it willappear to float in front of the display surface. Conversely, if a scene elementappears in the left-camera view to the left of where it appears in theright-camera view, it will appear with "positive parallax", meaningthat it will seem to reside somewhere behind the display surface. "Zeroparallax" is what happens when the left-camera projection of a pointperfectly matches its right-camera projection; a scene element projecting atzero parallax will appear to reside right at the display surface. See Figure 2for an illustration of how one perceives negative and positive parallaxeffects.

Figure2: Perception of Parallax Effects

Generally,a pleasing, well balanced stereo image will make use of both negative parallaxand positive parallax, and at least some of the 3D scene will project at orclose to zero parallax. Unfortunately, if one uses Equations 2 and 3 tocalculate the stereo pair projections all possible 3D points will projectto negative parallax. All negative parallax tends to be uncomfortable to view.

Wecan fix that by simply shifting the projected values leftward for theleft-camera projection, and rightward for the right-camera projection. If weshift the projected points by the same amount of the original camera offset,the resulting geometry will place the original projection plane precisely atzero parallax. Scene elements originally placed in front of the projectionplane will project to negative parallax, and scene elements originally placedbehind the projection plane will project to positive parallax. Here are the newequations for the left eye:

(Equation4)          

...Andfor the right eye:

(Equation5)          

Returningto our example, (8, -5, -3) now projects to (5.875, -3.75) forthe left camera, and (6.125, -3.75) for the right camera, shifting itinto positive parallax, and making it appear behind the display surface. Thismakes sense, since the scene element's original z-coordinate of -3places it behind the projection plane, whose z-coordinate is 0.

Thetwo projections that we have derived in Equations 4 and 5 above are called"parallel axis asymmetric frustum perspective projections". Notethat, even after translating the scene in one x-axis direction, and thentranslating the projected scene in the opposite x-axis direction, theprojection axes, the camera-target vectors of the two stereo pair cameras,remain parallel. Our final step, in which we shift the projected scene, makesthe frustums of the parallel projections asymmetrical, meaning that eachcamera's final projection shows more of the scene to one side of its axis thanthe other.

Tosummarize, the end result is a pair of perspective projections rendered fromdifferently offset camera positions, with frustum asymmetry applied tocomfortably balance the overall stereo parallax effect.

Itis a common error for programmers to do stereo projections using a"toe-in" camera model. With this model, the cameras are still offsetto one side or the other, but the camera-target vectors are not parallel, andconverge on a single point. Some developers use this method because it isconceptually simpler and, sometimes, easier to implement than parallel axisasymmetric frustum projections. Also, with this method, a balance betweenpositive parallax and negative parallax is achieved without the need to shiftthe projections as we do within Equations 4 and 5. Unfortunately, the cameratoe-in approach is geometrically incorrect, and leads to some variable verticalmisalignment between stereo pair elements, which can make for uncomfortableviewing. We do not recommend the "toe-in" camera model.

6. Implementing Asymmetric Frustum Projections

Nowthat I've explained the proper way to do stereo projections mathematically,let's talk about how to do these projections in your application. If yourapplication already does a perspective projection, the elements that you needto add, for each of two otherwise identical stereo pair perspective projectionsare:

  • Center of projection (camera) offset, and
  • Post-projection shift, or frustum asymmetry

Thecamera offset is easily accomplished using OpenGL's glTranslate()functions (this document will use the double-precision version of the function,glTranslated()). In order to effect the pre-projection camera offset, we actuallyneed to call glTranslated() just after the code that does the perspective projection. Asin the mathematical discussion above in "5. AnIntroduction to Stereoscopic Perspective Projections", we willeffectively translate the camera by instead translating the entire scene in theopposite direction. Here's the code (where StereoCameraOffset equalshalf the overall camera separation, negative for the left camera and positivefor the right camera): glTranslated(-StereoCameraOffset, 0, 0);

Thereare a few different ways to make each stereo projection's frustum asymmetrical.One imperfect approach would be to simply apply an offset (towards the left forthe left-camera rendering, towards the right for the right-camera rendering)when viewporting the regular (symmetric frustum) perspective projections.Though this approach is sometimes easy to implement, and the resulting stereoimages are geometrically correct, the disadvantage is that the left and rightedges of the two stereo pair element viewports will not line up with eachother.

Thebest way to implement each stereo projection's frustum asymmetry is tointegrate the frustum asymmetry into the perspective projection. The OpenGL glFrustum()function can be altered to do an asymmetric frustum projection. Here's how: glFrustum (FrustumLeft + FrustumAsymmetry,FrustumRight
    +FrustumAsymmetry, FrustumBottom, FrustumTop,
    NearClipDistance,FarClipDistance);

...WhereFrustumLeft, FrustumRight,FrustumBottom, FrustumTop, NearClipDistance, and FarClipDistance are the arguments of the original symmetric frustum projection(since glFrustum() assumes that the camera is at the coordinate system origin, FrustumLeftshould equal -FrustumRight, and FrustumBottom should equal -FrustumTop), and where FrustumAsymmetry is positive for the left-camera projection, and negative for theright-camera projection.

Ifyour application, rather than using glFrustum(), does itsperspective projections using a transformation matrix of your own creation, youcan still integrate frustum asymmetry into the perspective projection matrix.Just multiply the existing projection matrix by a transformation matrix thatrepresents a lateral translation (leftward for the left-camera projection,rightward for the right-camera projection).

Afew miscellaneous details to mention:

  • glFrustum() assumes that the center of projection (camera) is at the coordinate system origin (unlike the equations used in 5. An Introduction to Stereoscopic Perspective Projections, where the camera was along the positive z-axis). Thus, you may need to apply translation transformations to your scene in order to place the camera at the origin.
  • glFrustum() also assumes that the projection axis (camera-target vector) is along the coordinate system z-axis, in the negative z direction. If that is not already the case, you will need to either apply transformations to your scene, or adapt your projection geometry. Note that the stereo camera offset should always be in a direction that is perpendicular to the original camera-target vector.
  • Finally, glFrustum() does projections such that the projection's "up-vector" (the 3D direction that will appear as "up" in the final rendering) is along the coordinate system's positive yaxis. If you are working with a projection geometry that renders uses some kind of roll angle, remember that the stereo camera offset should always be in a direction that (in addition to being perpendicular to the original camera-target vector) is perpendicular to the projection's up-vector. Also, the projection's frustum asymmetry should always be along an axis that is perpendicular to the projection's up-vector.

7. Appropriate Camera Offset and Frustum Asymmetry

Inthe above discussion about implementing asymmetric frustum projections, twoimportant questions were left unanswered:

  • How much camera-offset should one use, to get a stereo effect that is strong enough to offer an effective sense of depth, yet not so strong that viewing is uncomfortable?
  • How much frustum asymmetry should be applied, in order to yield a pleasing balance between positive and negative parallax?

Bothquestions get into the realm of a lot of evolving research, and a certainamount of controversy. For example, StereoGraphics' own documentation used toadvise "don't exceed parallax values of more than 1.5°". Weknow now that a person's relative acceptance and tolerance of differentparallax magnitudes, on a computer screen or a projection display, is far moreconsistent when parallax is expressed as a percentage of viewport width, thanwhen parallax is computed as an angular measure based on retinal disparity.Which is actually quite convenient for the software developer, since iteliminates the need to guess at variables like the user's display size andseating position.

Thus,we now advise setting up perspective projections suchthat the negative parallax and positive parallax effects (take off the stereoglasses to measure on-screen parallax) each fall within about 3% or soof the image's overall viewport width. Since the viewport widthrepresents a projection plane in the 3D scene, a good starting point foroffsetting each stereo camera is about 3% of the 3D scene's horizontalrange. The 3D scene's horizontal range should be measured along the plane wherethe camera's projection frustum intersects the center of interest in the scene(which is roughly where we will probably want the plane of zero parallax tobe).

So,let's say that we are rendering a mechanical part whose bounding box has awidth of 100 units, and that mechanical part nearly fills the screen.You would probably want to offset each camera laterally by about 3 units.Here's the updated camera translation source code: double StereoCameraOffset = Xrange * 0.035 *UserOffsetAdjustment;
if (WhichEyeProjection ==LEFT_EYE_PROJECTION)
    StereoCameraOffset= -StereoCameraOffset;
glTranslated(-StereoCameraOffset, 0, 0);

...WhereXrange equals the horizontal range of the scene along the desired plane ofzero parallax. One way to derive Xrange is to get the difference between glFrustum()'sfirst two arguments, which represent the projection frustum's horizontal rangeat the near clipping plane, and multiply that difference by the ratio of thedistance to the desired plane of zero parallax to the near clipping planedistance. Another way to calculate Xrange would be tomultiply the distance to the desired plane of zero parallax by two times thetangent of half the horizontal field of view angle.

Alsonote that a "UserOffsetAdjustment" factor was thrown into the equation. It is a good idea toallow users to adjust the strength of the stereo effect to suit theirpreference. UserOffsetAdjustment's default value should be 1.0, and the user shouldbe able to adjust its value downward towards 0.0 (which would resultin no stereo effect at all), or upward (2.0 is usually OK as anupper limit). If your user interface provides some kind of keypad stereoadjustment, UserOffsetAdjustment should ideally be adjusted based on multiplication (i.e.: UserOffsetAdjustment *= 1.1) rather than addition and subtraction.

Next,we need to quantify the amount of each stereo projection's frustum asymmetry.Recall that in "6.Implementing Asymmetric Frustum Projections", we added a factorcalled "FrustumAsymmetry" (positive for the left-camera projection, negative for theright-camera projection) to each of glFrustum()'s first twoarguments: glFrustum(FrustumLeft + FrustumAsymmetry, FrustumRight + FrustumAsymmetry,FrustumBottom, FrustumTop, NearClipDistance, FarClipDistance);

Furtherrecall, from Equations 4 and 5, that the amount of frustum adjustment, when measuredin the projection plane, should equal the amount of the original camera offset(though, in the opposite direction), in order for the frustum adjustment toplace the projection plane at zero parallax. Thus, FrustumAsymmetry shouldequal -StereoCameraOffset.

However,glFrustum()'s interprets its first two parameters as xaxis boundaries,as measured on the near clipping plane. Yet, FrustumAsymmetry is beingcalculated based on the desired amount of frustum asymmetry in what is tobecome the plane of zero parallax. So, FrustumAsymmetry needs tobe adjusted by the ratio of the near clipping distance to the desiredzero-parallax distance. Here's the resulting source code: double FrustumAsymmetry =-StereoCameraOffset * UserBalanceAdjustment;
double n_over_d =NearClipDistance / ZeroParallaxDistance;
FrustumAsymmetry *=n_over_d;
glFrustum (FrustumLeft +FrustumAsymmetry, FrustumRight
    +FrustumAsymmetry, FrustumBottom, FrustumTop,
    NearClipDistance,FarClipDistance);

Noticethat we have introduced yet another user adjustment factor, "UserBalanceAdjustment". As with the stereo camera offset, it's a good idea to letthe user adjust the parallax balance to their liking. UserBalanceAdjustment's default value should also be 1.0, and the user should be able toadjust its value downward towards 0.0 (which would result in no frustumasymmetry, hence all negative parallax), or upward (2.0 is once again a goodupper limit). And, like the camera offset adjustment factor, UserBalanceAdjustment should be adjusted multiplicatively (or, perhaps, via a dialog box)rather than by addition or subtraction.

Alsonote that the above code is set up such that UserOffsetAdjustmentaffects both the amount of camera offset and the amount of frustum asymmetry.This is appropriate because, if the amount of frustum asymmetry is not adjustedproportionally whenever the camera offset is changed, camera offset changeswill have the side-effect of changing the scene's parallax balance.

Otherstereo camera adjustment issues:

  • The horizontal frustum range (Xrange) is directly proportional to the tangent of half the horizontal field of view angle. So, if the field of view angle is changed, the stereo camera offset and frustum asymmetry both need to be recalculated.
  • The horizontal frustum range (Xrange) is also directly proportional to the distance from the camera to the desired plane of zero parallax. So, if you "dolly" the camera to get closer to an object, and want the plane of zero parallax to remain the same relative to that object's position, both the stereo camera offset and the frustum asymmetry factors will need to be recalculated. In fact, stereo camera offset and frustum asymmetry factors should be recalculated any time the distance from the camera to the desired plane of zero parallax changes.
  • Depending on the application's rendering architecture, the projection frustum may be calculated using different units from those used in the 3D scene. In such unusual cases, it may be best to keep the frustum asymmetry factor constant and independent of the camera-offset amount (though both UserOffsetAdjustment and UserBalanceAdjustment should still affect the frustum asymmetry).

8. Other Stereo Aesthetic Issues

Thelast few sections have discussed stereoscopic perspective projections. Somehave wondered if it is possible to do stereoscopy with orthographicprojections. Though it is technically possible to do stereo orthographicprojections using the camera toe-in approach, the results are so uncomfortablethat we strongly advise against it. Thus, developers should design theirapplications such that available stereo display options will always be used incombination with perspective projection.

Similarly,for the best quality stereo, the stereo pair perspective projections should usea moderately wide field of view angle (note that a narrow "telephoto"field of view angle results in a projection geometry that is quite similar tothat of an orthographic projection). For the best results, we recommend ahorizontal field of view angle of 50° or more.

One significant issue relating to negative parallax is aphenomenon that occurs when a scene element at negative parallax is clipped byan edge of the rendering window. The problem is that ascene element that appears to be floating somewhere in front of the displaysurface is occluded by an edge that is at the display surface. This results ina somewhat disturbing optical contradiction in which the occluding edge isfarther away than the scene element that it occludes.

Somepeople firmly believe that this negative parallax edge-clipping effect must beavoided at all costs, even if that means not ever using any negative parallaxat all (to do this, they place the zero parallax setting at the near clippingplane). We have found that approach to be too extreme. Eliminating negativeparallax tends to result in either uncomfortable amounts of positive parallax,a flattening of the stereo effect within a narrow portion of the positiveparallax range, or both. Using some balance of positive parallax and negative parallaxresults in stereo images that are more comfortable to view, even if thatapproach inevitably results in some amount of negative parallax edge-clipping.

Howyou should deal with the negative parallax edge-clipping issue depends on thenature of your application. In a mechanical CAD application where the sceneelements of interest will usually not be clipped by the window edge, it isusually safe to place the zero-parallax plane at or just in front of theobject's center. However, with a "flythrough" type of application, itis often best to set the zero-parallax distance such that most (though not all)of the scene projects to positive parallax.

Finally,it should be mentioned that very high contrast values in a stereo image willoften result in "ghosting", in which some of one eye's view appearsas a "ghost" in the other eye's view. This tends to be caused by CRTphosphor persistence (ghosting can also be an issue when using projectiondisplays). Green tends to be the worst offender. The workaround to this problemis to avoid extreme amounts of contrast if at all possible. Use a graybackground instead of a black background (even dark gray is better than black),and if possible, try to avoid using bright white, green, and cyan sceneelements against a dark background.

9. Above-Below Stereo Formatting

Inaddition to supporting the OpenGL stereo buffering standard, StereoGraphicsalso makes a stereo viewing system that permits full-screen stereo viewing withalmost any PC graphics card. Stereo software designed for this type of stereosystem needs to use Above-Below stereo formatting. (Note that this sectionis not relevant to you if you are developing software using OpenGL stereobuffering. For more information about the differences between these twostereo hardware systems, please see "2.Setting Up Your Graphics Hardware To Support Stereo".)

TheAbove-Below system's stereo emitter includes circuitry which, when in stereo displaymode, doubles the frequency of the vertical sync signal. This causes thedisplay to refresh at twice its normal rate, which has the effect of verticallystretching the screen display. At this doubled display frequency, whatever waspreviously on the top half of the display, and whatever was previously on thebottom half of the display, each take up the full display on alternaterefreshes.

Thus,to put up a stereo image which will appear stereoscopically using this hardwaresystem, you need to viewport the left camera's rendering to the top half of theoverall display, and viewport the right camera's rendering to the bottom halfof the overall display. Since the sync-doubling circuitry stretches everythingvertically, each rendering should have a 1:2 pixel aspect ratio suchthat everything originally appears vertically squashed.

Thereis one more important detail to Above-Below stereo formatting: Normally, everyvertical scan of the display includes hundreds of visible horizontal scanlines, followed by 20 to 50 invisible ones (the "blankinterval"). When sync-doubling, we need to insert a second blank interval(draw it as a black field) across the middle of the original display. The twostereo pair viewports end up with the remainder of the display, each getting alittle less than half of the original vertical display resolution.

Forexample, if the original display resolution is 1024x768, and the blankinterval thickness is 40, each stereo pair viewport ends up with half ofthe remainder of the vertical resolution, (768-40)/2, or 364.Thus, each stereo pair viewport will have a pixel size of 1024x364, andthe two stereo pair viewports will be separated by a black blank intervalregion whose pixel size is 1024x40. The left-camera projection would bemapped to the top viewport (pixel-rows 0 through 363), theright-camera projection would be mapped to the bottom viewport (pixel-rows 404through 767), and the new blank interval would appear exactlymid-display (pixel-rows 364 through 403).

Inorder for the two stereo pair viewports to be positioned with proper verticalalignment, the newly created blank interval must have a vertical thickness thatperfectly matches the original blank interval. Since blank interval thicknessvaries, depending on the user's graphics card, display resolution, and otherdisplay settings, Above-Below stereo software must be designed to accommodatedifferent blank interval thicknesses. This usually means providing the userwith some kind of calibration screen, in which the user lines up two arrowswhile in stereo mode.

Remember:Sync-doubling affects the entire display, including window borders, menu bars,the Windows Taskbar, other application windows, etc. For this reason, anAbove-Below application window needs to fill the entire display,blocking out all other application windows including the Windows Taskbar.Additionally, an Above-Below application window should neither have a border,nor standard title bars, menu bars, or status bars. Interface design usingAbove-Below stereo formatting can be a challenge.

OtherAbove-Below programming notes:

  • With the StereoGraphics sync-doubling hardware that supports Above-Below stereo formatting, the user toggles stereo display mode on and off manually using a physical switch. Thus, stereo display mode switching is not controlled by software.
  • Sections 5 through 8, relating to stereoscopic projections, apply to Above-Below stereo formatting, as well as OpenGL stereo buffering.

10. Points to Remember

  • With OpenGL stereo buffering, the necessary elements are:
    - Check for stereo display configuration availability, and enable stereo buffering support when initializing each graphics window.
    - Render two asymmetric frustum perspective projections, one to each of the two stereo back-buffers. Then swap buffers to put the stereo pair on the display.
    - Offset each stereo camera using a lateral translation (
    glTranslate()). Stereo projection axes should remain parallel to the original projection axis.
    - Balance the stereo parallax by making the perspective projection frustums asymmetrical. This can be done by changing the first two arguments of
    glFrustum(), or by altering the transformation matrix that does the projection.
  • Use enough stereo camera separation to yield a pleasing stereo effect, but not so much as to be uncomfortable. In general, on-screen parallax should be limited to about 3% or so of viewport width, for both negative and positive parallax effects. For the best stereo effect, use a wide-angle perspective projection, with a field of view angle of 50° or more.
  • Parallax effects should be balanced such that there is some negative parallax, and some positive parallax. To do this, apply the right amount of projection frustum asymmetry to put the plane of zero parallax near the center of interest in any given scene. (For some applications such as "flythrough" applications, it may be desirable to use more positive parallax than negative parallax, in order to reduce the amount of negative parallax that is clipped by the window edges.)
  • Stereo projection settings should not be fixed quantities. Recalculate the camera separation and frustum asymmetry any time that the field of view angle or the camera-to-target distance changes. Stereo projection setting calculations should also include user-adjustable factors.
  • Above-Below formatting is another approach to doing stereo display on a PC. OpenGL stereo buffering and Above-Below formatting use different StereoGraphics stereo display hardware.

11. Resources

As previously mentioned, many of theconcepts discussed in this document are illustrated in the example program,"OGLPlane", which is available from StereoGraphics. Anothersimpler example program, "RedBlue", illustrates stereo OpenGLbuffering without doing any stereo projections (it simply draws colored rectanglesto each stereo buffer). Other example programs may additionally be available atour website, http://www.stereographics.com, and in the "Developers" directory of our ftp site, ftp.stereographics.com. StereoGraphicsdeveloper support can also be reached at support@crystaleye.com,or 415-459-4500.

 

原创粉丝点击