Stencilbuffer and interlaced rendering

Hello you all,

I want to interlace to differently rendered images of the same scene, one image for the left eye and one image for the right eye. This means that I would like the image to be the following:

line 1 of left eye image
line 2 of right eye image
line 3 of left eye image
line 4 of right eye image
. . . .
. . . .
. . . .

I know that it should be possible to render the left eye in one buffer, the right eye in another and then combine these two into the backbuffer using the stencil buffer. But I don’t know the details about it and was wondering if anyone know exactly how this can be done.

Thanks in advance,

Arno Kamphuis

Hi Arno,

here is a an excerpt (and somehow edited version) of a program I did for that purpose.

Please contact me if we need to exchange more informations or this project.

GLubyte patternEven[128] =
{
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
};

GLubyte patternOdd[128] =
{
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
};

void UpdateStencil(void)
{
// Draw vertical stripes into the stencil buffer to partition the left and right buffer.
// If the first client pixel is on an even screen pixel, use the even pattern.

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (double) nWidth, 0.0, (double) nHeight, -1.0, 1.0);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);

glClear(GL_STENCIL_BUFFER_BIT);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, ~0);
glEnable(GL_STENCIL_TEST);

if ((nScreenOffset & 1) == 0)
{
glPolygonStipple(patternEven);
}
else
{
glPolygonStipple(patternOdd);
}
glEnable(GL_POLYGON_STIPPLE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glRecti(0, 0, nWidth, nHeight);

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_POLYGON_STIPPLE);
glEnable(GL_LIGHTING);
}

// Main drawing routine with stencil buffer filled via PolygonStipple (RECOMMENDED METHOD!)
void Display(void)
{
// glViewport() call is done in WM_SIZE message

glDrawBuffer(GL_BACK);

// This is a quick and dirty method to update the stencil only if the window has been moved or resized.
// The CORRECT but slow thing to do, is to redraw the stencil on each WM_PAINT in the paint region.
// If this is NOT done, the stencil buffer MAY BE ERASED by overlapping applications!
// (Try two of these samples simultaneously and you’ll see.)
if (bUpdateStencil) // Set in WM_MOVE
{
UpdateStencil(); // Fast method to get the correct pattern into the stencil buffer.
// Slow would be glDrawPixels with a bitmap.
bUpdateStencil = FALSE;

glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

}

// Clear both back buffers in one step.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Select back “left” buffer to recieve drawing
// The left image lies in the 0-stripes.
glStencilFunc(GL_EQUAL, 0, ~0); // glDrawBuffer(GL_BACK_LEFT);

// Setup the projection for the left eye
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(aspectViewport * -0.75 - eyeAdjust,
aspectViewport * 0.75 - eyeAdjust,
-0.75, 0.75, 0.65, 4.0);
glTranslatef(eyeOffset, 0.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -PULL_BACK);

// Setup the transformation matrix for the object.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glRotatef(angleZ, 0.0f, 0.0f, 1.0f);
glRotatef(angleY, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1.0f, 0.0f, 0.0f);
glTranslatef(0.0f, 0.0f, translateZ);

DrawSomething();

// Select back “right” buffer to recieve drawing
glStencilFunc(GL_NOTEQUAL, 0, ~0); // glDrawBuffer(GL_BACK_RIGHT);

// Draw the image for the right eye.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(aspectViewport * -0.75 + eyeAdjust,
aspectViewport * 0.75 + eyeAdjust,
-0.75, 0.75, 0.65, 4.0);
glTranslatef(-eyeOffset, 0.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -PULL_BACK);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glRotatef(angleZ, 0.0f, 0.0f, 1.0f);
glRotatef(angleY, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1.0f, 0.0f, 0.0f);
glTranslatef(0.0f, 0.0f, translateZ);

DrawSomething();
}