Open topic with navigation

# Stereo: Beyond the Basics

## Optimizing the Stereo Display

The quality and comfort of your stereoscopic 3D application is partly controlled by the stereo frustum and its settings. Another contributing factor is where you place objects in your scene. Although the zSpace Core SDK cannot set that for you, it can provide information that helps in that placement.

One of the most important functions for stereo optimization is zsSetFrustumAttribute(). The list of attributes is defined in the ZSFrustumAttribute enum. To understand how these attributes affect your viewer's comfortable viewing, read Understanding the zSpace 3D System for Better Spatial Design & Aesthetics.

The following OpenGL code example shows how to use zsCalculateFrustumFit() to calculate a new camera position, orientation, and viewer scale that will fit a specified camera-space bounds nicely within the extents of the application's viewport. Since zsCalculateFrustumFit() does not modify the frustum's viewer scale, zsSetFrustumAttribute() must be explicitly called. Viewer scale, previously called world scale, adjusts the global scale of the scene from the viewer's perspective. Viewer scale values larger than 1.0f shrink the scene, while values smaller than 1.0f enlarge the scene.

After setting the frustum's viewer scale, use the camera matrix calculated by zsCalculateFrustumFit() to update the monoscopic model-view matrix.

Note: This code example is not part of a sample application provided by the SDK.

      // zSpaceContext set during initialization.
      ZSContext zSpaceContext = ...;
      ZSHandle viewportHandle = NULL;
      ZSHandle frustumHandle  = NULL;

      // Create and get frustum
      zsCreateViewport(zSpaceContext, &viewportHandle);
      zsFindFrustum(viewportHandle, &frustumHandle);

      // Set up a bounding box that is centered about the origin (0, 0, 0) and
      // has a width, height, and depth of 0.12 meters.
      float halfSize = 0.06f;
      ZSBoundingBox b;
      b.lower.x = -halfSize;
      b.lower.y = -halfSize;
      b.lower.z = -halfSize;
      b.upper.x =  halfSize;
      b.upper.y =  halfSize;
      b.upper.z =  halfSize;

      // Calculate the appropriate viewer scale and camera position/orientation
      // such that content in the above bounding box will take up the entire
      // viewport without being clipped.
      ZSMatrix4 lookAtMatrix;
      ZSFloat   viewerScale = 1.0f;
      zsCalculateFrustumFit(frustumHandle, &b, &viewerScale, &lookAtMatrix);

      // Set the frustum's viewer scale with the value that was calculated
      // by zsCalculateFrustumFit().
      zsSetFrustumAttribute(frustumHandle,
                            ZS_FRUSTUM_ATTRIBUTE_VIEWER_SCALE,
                            viewerScale);

      // Set the monoscopic model-view matrix using the camera matrix that was
      // calculated by zsCalculateFrustumFit().
      glMatrixMode(GL_MODELVIEW);
      glLoadMatrixf(lookAtMatrix.f);

Another useful function in the Stereo Frustum API is zsCalculateFrustumFovScale(). This function calculates the field of view (FOV) scale for a specified field of view. As in the above example, you can use the resulting information as input to zsSetFrustumAttribute().

Other functions in the Stereo Frustum API provide important information about stereo comfort. zsCalculateFrustumDisparity() calculates the pixel disparity of a given point in camera space. The pixel disparity tells you whether that location is in the coupled or decoupled zone. The coupled zone is that range in the zSpace display where your eyes are comfortably focused on the surface of the display and converging on an object that is a moderate distance from the screen's surface. The decoupled zone is where the viewer's eyes must focus on the screen surface, but converge on an object an uncomfortable distance from the screen surface.

In the coupled zone, in negative parallax, the maximum pixel disparity should be -100. In positive parallax, the maximum pixel disparity zone should be 100. Although you can place objects in the decoupled zone, you should use this area sparingly to avoid viewer discomfort.

The zsGetFrustumCoupledBoundingBox() function serves a similar purpose. This function provides the axis-aligned bounding box of the coupled zone. You can use zsGetFrustumCoupledBoundingBox() to determine if an object is within the coupled comfort zone.

Open topic with navigation