Varrier Combiner

Varrier combiner is an implementation of a Varrier display algorithm that takes advantage of frame buffer objects for scalable off-screen rendering and GLSL shaders for efficient on-screen interleaving of views.

Startup and Shutdown

int vc_init(int width, int height)

Initialize the combiner and all of its OpenGL state. The width and height parameters give the size of the display. These values allow the combiner to preallocate the off-screen render buffers. It also initializes all necessary OpenGL extension entry points and links the fragment and vertex shader objects. Because OpenGL state is initialized, the application must call this function only after acquiring its OpenGL context.

The return value indicates successful initialization. A zero value is returned if a required extension is not supported by the current hardware. An error message indicating the missing extension is displayed.

void vc_fini()

Finalize the combiner and release all OpenGL state.


The Varrier display and line screen configuration is communicated to the combiner via the following structure. All combiner functions recieve a constant pointer to this structure. Structure values may change as often as the application requires. Multi-tile display systems will require multiple display configuration structures.

struct vc_display
    int viewport_x;
    int viewport_y;
    int viewport_w;
    int viewport_h;

    float quality;

    float screen_BL[3];
    float screen_TL[3];
    float screen_BR[3];

    float pitch;
    float angle;
    float thick;
    float shift;
    float cycle;

Viewport position and size. The combiner manipulates viewport parameters to control the off-screen rendering quality.


Rendering quality. This must be a floating point value between 0.0 and 1.0. It determines the degree of decimation of the off-screen render buffers, and thus balances off-screen render performance against on-screen visual quality. Under normal circumstances, values greater than 0.5 are unnecessary.


The world-space positions of the bottom-left, top-left, and bottom-right corners of the display. These values must be given in the same coordinate system as the eye positions submitted to vc_combine and vc_frustum.


Line screen pitch.


Line screen angle.


Line screen optical thickness.


Line screen shift.


Line screen duty cycle.


void vc_prepare(const struct vc_display *V, int eye)

Perpare to render a view of the scene. Applications should call this function just before rendering each eye. The eye argument selects the off-screen buffer to be used: 0 selects the left eye, 1 selects the right eye.

void vc_combine(const struct vc_display *V, const float L[3], const float R[3])

Combine the rendered views to the display. Applications should call this function only after rendering both eyes. The L and R arguments give the positions of the left and right eyes.


void vc_frustum(const struct vc_display *V, const float P[3], float n, float f)

Apply a perspective projection to the OpenGL projection matrix stack. This projection will be correct for the given view position P and the screen corners defined by the given display configuration. The n and f arguments give the near and far plane distances.

CAVELib applications need not call this function, as the proper projection is computed by the CAVELib. In general however, this projection is not trivially computed. Standalone OpenGL applications based on SDL or GLUT will find this function useful.


The following code demonstrates the steps an application must take during a screen update. Assume here that V is a correctly initialized vc_display structure, that L and R are floating point vectors giving the positions of the left and right eyes, and that draw_scene() performs a normal OpenGL rendering of the scene.

/* Render the off-screen left eye view. */

    vc_prepare(&V, 0);
    vc_frustum(&V, L, 0.1f, 100.0f);


/* Render the off-screen right eye view. */

    vc_prepare(&V, 1);
    vc_frustum(&V, R, 0.1f, 100.0f);


/* Combine the views to the on-screen framebuffer. */

    vc_combine(&V, L, R);


Applications should take a few simple precautions to avoid conflicting with the combiner. The vast majority of applications need not be concerned with these issues. These special cases do not impose significant restrictions on the application. Conflict avoidance is merely a matter of clean OpenGL programming style.

Applications should not assume that their destination frame buffer is frame buffer object 0. Applications that generate their own frame buffer objects should query the currently bound frame buffer object before binding their own. This value should then be rebound when the application's off-screen rendering is complete. Unfortunately, the frame buffer object binding is not a pushable attribute. An explicit query is required.

Care should be taken when manipulating the viewport during scene rendering. Depending on the quality setting, the viewport rectangle may differ from the expected value during off-screen rendering. Applications that wish to manipulate the viewport should first query the current rectangle and make changes relative to the returned value. Keep in mind also that the scissor rectangle may need to be set to match the viewport rectangle. Viewport and scissor state are both pushable attributes.