Difference between revisions of "Tutorial - Stereo rendering"
m |
|||
(8 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
+ | __NOTOC__ __NOEDITSECTION__{{ContentBlock|color=white|content={{!!}} | ||
'''In this tutorial I will describe how to perform quadbuffered stereo rendering with Horde3D. This explicitly requires a graphics card that supports quad-buffering, i.e. rendering to two different output devices(Nvidia Quadro or ATI/AMD FireGL). This has been tested with a stereo projection system and polarization glasses.''' | '''In this tutorial I will describe how to perform quadbuffered stereo rendering with Horde3D. This explicitly requires a graphics card that supports quad-buffering, i.e. rendering to two different output devices(Nvidia Quadro or ATI/AMD FireGL). This has been tested with a stereo projection system and polarization glasses.''' | ||
Line 6: | Line 7: | ||
[http://www.orthostereo.com/geometryopengl.html Stereoscopic Geometry in OpenGL] | [http://www.orthostereo.com/geometryopengl.html Stereoscopic Geometry in OpenGL] | ||
− | In this tutorial we will only use an | + | In this tutorial we will only use an symmetric frustum. |
Line 22: | Line 23: | ||
appWidth = fullscreen ? videoInfo->current_w : width; | appWidth = fullscreen ? videoInfo->current_w : width; | ||
appHeight = fullscreen ? videoInfo->current_h : height; | appHeight = fullscreen ? videoInfo->current_h : height; | ||
− | |||
− | |||
if(fullscreen) | if(fullscreen) | ||
Line 37: | Line 36: | ||
std::cerr << "STEREO initialization failed! Restarting..."<< std::endl; | std::cerr << "STEREO initialization failed! Restarting..."<< std::endl; | ||
SDL_GL_SetAttribute(SDL_GL_STEREO, 0); | SDL_GL_SetAttribute(SDL_GL_STEREO, 0); | ||
− | if (!SDL_SetVideoMode( | + | if (!(surface = SDL_SetVideoMode(appWidth, appHeight, 32, SDL_OPENGL | SDL_FULLSCREEN | SDL_HWSURFACE))) { |
std::cerr << "SDL_SetVideoMode failed: " << SDL_GetError() << std::endl; | std::cerr << "SDL_SetVideoMode failed: " << SDL_GetError() << std::endl; | ||
SDL_Quit(); | SDL_Quit(); | ||
Line 66: | Line 65: | ||
}} | }} | ||
− | This will also work with GLFW. | + | This will also work with GLFW. Just call this line before opening your GLFW window. |
{{CppSourceCode| | {{CppSourceCode| | ||
description= GLFW stereo flag| | description= GLFW stereo flag| | ||
Line 77: | Line 76: | ||
== Render the scene == | == Render the scene == | ||
− | Now we need to calculate the eye offset and render the scene twice for | + | Now we need to calculate the eye offset and render the scene twice (once for each eye). This is done by switching the Horde3D render buffer to the corresponding eye, moving the camera to the desired eye offset and render the scene to the specified buffer. Again, this will only be done if stereo rendering has been enabled successfully. |
− | We will calculate the eye offset by simply "strafing" the camera from its original position slightly to the left and right and rotating it inwards. This example has some keys assigned to adjust the eye offset and strabismus ("cross-eyedness") on the fly. In normal (non-stereo) mode we can switch between the eyes to check | + | We will calculate the eye offset by simply "strafing" the camera from its original position slightly to the left and right and rotating it inwards. This example has some keys assigned to adjust the eye offset and strabismus ("cross-eyedness") on the fly. In normal (non-stereo) mode we can switch between the eyes to check the camera position even if stereo rendering is not available. |
{{CppSourceCode| | {{CppSourceCode| | ||
description= Render the scene (app.cpp)| | description= Render the scene (app.cpp)| | ||
Line 88: | Line 87: | ||
int eye = 0; | int eye = 0; | ||
void Application::mainLoop( int fps ) | void Application::mainLoop( int fps ) | ||
− | |||
{ | { | ||
− | |||
_curFPS = fps; | _curFPS = fps; | ||
− | |||
− | |||
keyHandler(); | keyHandler(); | ||
− | |||
− | |||
if(! _freeze ) | if(! _freeze ) | ||
− | |||
{ | { | ||
− | |||
// calculate eye-offsets for stereo rendering | // calculate eye-offsets for stereo rendering | ||
− | |||
float xEyeOffset = eyOffsetFactor*sinf( degToRad( _ry + 90 ) ); | float xEyeOffset = eyOffsetFactor*sinf( degToRad( _ry + 90 ) ); | ||
− | |||
float zEyeOffset = eyOffsetFactor*cosf( degToRad( _ry + 90 ) ); | float zEyeOffset = eyOffsetFactor*cosf( degToRad( _ry + 90 ) ); | ||
− | |||
− | |||
// ........ | // ........ | ||
// Render scene | // Render scene | ||
− | |||
// render stereo | // render stereo | ||
− | |||
int ga = 0; | int ga = 0; | ||
− | |||
if (SDL_GL_GetAttribute(SDL_GL_STEREO, &ga) == 0 && ga == 1) { | if (SDL_GL_GetAttribute(SDL_GL_STEREO, &ga) == 0 && ga == 1) { | ||
− | |||
Horde3D::setNodeParami(_cam, CameraNodeParams::OutputBufferIndex, 0); | Horde3D::setNodeParami(_cam, CameraNodeParams::OutputBufferIndex, 0); | ||
− | |||
Horde3D::setNodeTransform( _cam, _x-xEyeOffset, _y, _z-zEyeOffset, _rx ,_ry-strabismus, 0, 1, 1, 1 ); | Horde3D::setNodeTransform( _cam, _x-xEyeOffset, _y, _z-zEyeOffset, _rx ,_ry-strabismus, 0, 1, 1, 1 ); | ||
Horde3D::render( _cam ); | Horde3D::render( _cam ); | ||
− | |||
− | |||
− | |||
Horde3D::setNodeParami(_cam, CameraNodeParams::OutputBufferIndex, 1); | Horde3D::setNodeParami(_cam, CameraNodeParams::OutputBufferIndex, 1); | ||
− | |||
Horde3D::setNodeTransform( _cam, _x+xEyeOffset, _y, _z+zEyeOffset, _rx ,_ry+strabismus, 0, 1, 1, 1 ); | Horde3D::setNodeTransform( _cam, _x+xEyeOffset, _y, _z+zEyeOffset, _rx ,_ry+strabismus, 0, 1, 1, 1 ); | ||
Horde3D::render( _cam ); | Horde3D::render( _cam ); | ||
− | |||
− | |||
− | |||
} | } | ||
− | + | else { // non stereo | |
− | else { | ||
− | |||
// Set camera parameters | // Set camera parameters | ||
− | + | if (eye == 1) // left eye | |
− | if (eye == 1) | ||
− | // left eye | ||
Horde3D::setNodeTransform( _cam, _x-xEyeOffset, _y, _z-zEyeOffset, _rx ,_ry-strabismus, 0, 1, 1, 1 ); | Horde3D::setNodeTransform( _cam, _x-xEyeOffset, _y, _z-zEyeOffset, _rx ,_ry-strabismus, 0, 1, 1, 1 ); | ||
− | + | else if (eye == 2) // right eye | |
− | else if (eye == 2) | ||
− | // right eye | ||
Horde3D::setNodeTransform( _cam, _x+xEyeOffset, _y, _z+zEyeOffset, _rx ,_ry+strabismus, 0, 1, 1, 1 ); | Horde3D::setNodeTransform( _cam, _x+xEyeOffset, _y, _z+zEyeOffset, _rx ,_ry+strabismus, 0, 1, 1, 1 ); | ||
− | + | else if(eye == 0) // normal camera (centered) | |
− | else if(eye == 0) | ||
− | // normal camera (centered) | ||
Horde3D::setNodeTransform( _cam, _x, _y, _z, _rx ,_ry, 0, 1, 1, 1 ); | Horde3D::setNodeTransform( _cam, _x, _y, _z, _rx ,_ry, 0, 1, 1, 1 ); | ||
− | |||
Horde3D::render( _cam ); | Horde3D::render( _cam ); | ||
− | |||
− | |||
− | |||
} | } | ||
− | |||
// Remove all overlays | // Remove all overlays | ||
− | |||
Horde3D::clearOverlays(); | Horde3D::clearOverlays(); | ||
− | |||
− | |||
// Write all mesages to log file | // Write all mesages to log file | ||
+ | Horde3DUtils::dumpMessages(); | ||
− | + | Horde3D::finalizeFrame(); // comment this line if you are using Horde3D 1.0.0 beta 2 | |
SDL_GL_SwapBuffers(); | SDL_GL_SwapBuffers(); | ||
− | |||
} | } | ||
− | |||
} | } | ||
void Application::keyPressEvent( SDLKey key ) | void Application::keyPressEvent( SDLKey key ) | ||
− | |||
{ | { | ||
− | |||
// add more key events here... | // add more key events here... | ||
// switch between eyes (0: normal/center, 1: left eye, 2: right eye) | // switch between eyes (0: normal/center, 1: left eye, 2: right eye) | ||
− | |||
if( key == SDLK_F5 ) {// F5 | if( key == SDLK_F5 ) {// F5 | ||
− | |||
++eye; | ++eye; | ||
− | |||
if (eye >= 3) | if (eye >= 3) | ||
− | |||
eye = 0; | eye = 0; | ||
− | |||
std::cout<<"eye: "<<eye<<std::endl; | std::cout<<"eye: "<<eye<<std::endl; | ||
− | |||
} | } | ||
} | } | ||
void Application::keyHandler() | void Application::keyHandler() | ||
− | |||
{ | { | ||
// add more keys if desired... | // add more keys if desired... | ||
Line 201: | Line 150: | ||
// adjust strabismus (cross eyedness) | // adjust strabismus (cross eyedness) | ||
if(_keys[SDLK_0]) | if(_keys[SDLK_0]) | ||
− | |||
{ | { | ||
− | |||
if (strabismus < 45) | if (strabismus < 45) | ||
− | |||
strabismus += 0.3f; | strabismus += 0.3f; | ||
− | |||
− | |||
− | |||
} | } | ||
− | |||
if(_keys[SDLK_9]) | if(_keys[SDLK_9]) | ||
− | |||
{ | { | ||
− | |||
if (strabismus > 0) | if (strabismus > 0) | ||
− | |||
strabismus -= 0.3f; | strabismus -= 0.3f; | ||
− | |||
− | |||
− | |||
} | } | ||
− | |||
− | |||
// adjust eye offset | // adjust eye offset | ||
if(_keys[SDLK_8]) | if(_keys[SDLK_8]) | ||
− | |||
{ | { | ||
− | |||
eyeOffset += 0.3f; | eyeOffset += 0.3f; | ||
− | |||
− | |||
− | |||
} | } | ||
− | |||
if(_keys[SDLK_7]) | if(_keys[SDLK_7]) | ||
− | |||
{ | { | ||
− | |||
if (eyeOffset > 0) { | if (eyeOffset > 0) { | ||
− | |||
eyeOffset -= 0.3f; | eyeOffset -= 0.3f; | ||
− | |||
− | |||
− | |||
} | } | ||
− | |||
} | } | ||
} | } | ||
</source> | </source> | ||
+ | }} | ||
+ | |||
+ | == TODO == | ||
+ | - calculate asymmetric frustum | ||
+ | |||
+ | - add a second camera node for easier camera movement | ||
}} | }} |
Latest revision as of 17:45, 3 January 2010
In this tutorial I will describe how to perform quadbuffered stereo rendering with Horde3D. This explicitly requires a graphics card that supports quad-buffering, i.e. rendering to two different output devices(Nvidia Quadro or ATI/AMD FireGL). This has been tested with a stereo projection system and polarization glasses. To do this we need to render our scene from two different points of view(left and right eye) and send each frame to the corresponding output device. Stereoscopic Geometry in OpenGL In this tutorial we will only use an symmetric frustum. Enable quadbufferingFirst of all we need to tell our graphics card to enable quadbuffering if available. The following code shows how to do this using SDL. We will try to enable stereo rendering by default but it will fall back to non-stereo if the graphics card does not have quadbuffering capabilities. We will enable stereo rendering only in fullscreen mode.
This will also work with GLFW. Just call this line before opening your GLFW window.
Render the sceneNow we need to calculate the eye offset and render the scene twice (once for each eye). This is done by switching the Horde3D render buffer to the corresponding eye, moving the camera to the desired eye offset and render the scene to the specified buffer. Again, this will only be done if stereo rendering has been enabled successfully. We will calculate the eye offset by simply "strafing" the camera from its original position slightly to the left and right and rotating it inwards. This example has some keys assigned to adjust the eye offset and strabismus ("cross-eyedness") on the fly. In normal (non-stereo) mode we can switch between the eyes to check the camera position even if stereo rendering is not available.
TODO- calculate asymmetric frustum - add a second camera node for easier camera movement |