Xinerama OpenGL Stereo Rendering
This article describes how to use OpenGL to let your application render in xinerama stereo mode. I am also calling this mode: passive stereo mode, because it renders both views of the scene (for left and right eye) on the screen without at the same time. The description use native OpenGL function calls and provide also at the end a camera class, which can be used for this purpose.
There are some examples how it will looks like in real time (rendered with OpenGL in widescreen mode 16:9)
Here is a list of steps (in my own words) on how to create such stereo rendering view:
- open rendering window with double width (i.e. 2560x1024 instead of 1280x1024)
- precalculate projection matrices for both eyes (left, right) using this parameters: eye separation=0.04 (4 cm), focal length=~1 (1 m).
Better you find out what parameters are best for your application. But this should be optimal. The focal length should also be used in the way that it corresponds to the distance of your stereo projectors (or screen) to your eyes. - let OpenGL do this calculation for you:
// Calculate some variables
float halfEyeSeparation = eyeSeparation / 2;
float ratio = float(viewPortWidth)/float(viewPortHeight); //use your vieport settings
float radiance = DEGTORAD * fieldOfView / 2; //DEGTORAD = (PI / 180.0f)
float wd2 = nearPlane * tan(radiance); // nearPlane is the near plane of your view frustum
float ndfl = nearPlane / focalLength;
// Calculaions for right eye
float left = -ratio * wd2 - 0.5 * eyeSeparation * ndfl;
float right = ratio * wd2 - 0.5 * eyeSeparation * ndfl;
float top = wd2;
float bottom = -wd2;
// Use OpenGL to calculate projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glFrustum(left,right,bottom,top,nearPlane,farPlane);
glGetFloatv(GL_PROJECTION_MATRIX, asymmetricProjectionRight); // store projection matrix for right eye in float[16] array
// Calculation for left eye
left = -ratio * wd2 + 0.5 * eyeSeparation * ndfl;
right = ratio * wd2 + 0.5 * eyeSeparation * ndfl;
top = wd2;
bottom = -wd2;
// Use OpenGL to do calculations for us
glLoadIdentity();
glFrustum(left,right,bottom,top,nearPlane,farPlane);
glGetFloatv(GL_PROJECTION_MATRIX, asymmetricProjectionLeft); //store projection of left eye
// Return back to modelview matrix mode
glPopMatrix();
glMatrixMode(GL_MODELVIEW)
- in your rendering code, do something like this:
- set viewport to left eye (glViewport(0,0, 1280, height))
- load your precalculated left eye projection matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(asymmetricProjectionLeft);
glMatrixMode(GL_MODELVIEW - Set camera to the position of the left eye
camera.pos -= camera.rightDirection * eyeSeparatio - render your stuff (NOTE: be careful if you use render to texture, because now you render only on a left half of your framebuffer)
- switch the viewport to the right eye (glViewport(1280,0,2560,height))
- move your camera again but now to the right (according to what you have done before: restore modelview and move with eyeSeparation/2 or with eyeSeparation, if you moved your camera without pushing the modelview matrix on the stack)
- load the projection matrix for the right eye
- render your stuff
You can also download cCamera-class and let cCamera do this work for you :-)
This class also provides some more useful methods: for example frustum culling. You are free to use it in your applications.
I hope this article does help somebody to understand how "passive" stereo mode works. The screenshots were taken from my first OpenGL project "newReality" made for the rendering competition in Computer Graphics I Lecture in the WS04/05 at the University of Saarland, Germany.
Art Tevs, 05. April 2007 22:03:41.
Der Artikel wurde 21659 mal aufgerufen.