I set
Code: Select all
mStereoManager.init(mWindow->getViewport(0), NULL, Ogre::StereoManager::SM_ANAGLYPH_RC);
Code: Select all
mStereoManager.init(mWindow->getViewport(0), NULL, Ogre::StereoManager::SM_ANAGLYPH_RC);
Code: Select all
float EYES_SPACING=0.5f;
float SCREEN_DIST=30.0f;
Ogre::Viewport *vp = mWindow->addViewport(mCamera); //Our Viewport linked to the camera
viewportLeft=vp;
// init the manager with defaults parameters
mStereoManager.init(viewportLeft, NULL, StereoManager::SM_ANAGLYPH_RC);
mStereoManager.setEyesSpacing(EYES_SPACING);
mStereoManager.setFocalLength(SCREEN_DIST);
Code: Select all
/*
-----------------------------------------------------------------------------
This source is part of the Stereoscopy manager for OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
-----------------------------------------------------------------------------
* Copyright (c) 2008, Mathieu Le Ber, AXYZ-IMAGES
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the AXYZ-IMAGES nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Mathieu Le Ber ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Mathieu Le Ber BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
// Last update jan 19 2010
#include "stdafx.h"
#include "StereoManager.h"
#include <limits>
using namespace Ogre;
//-------------- Stereo Camera listener -------------------------------
StereoManager::StereoCameraListener::StereoCameraListener(void)
:mStereoMgr(0),
mCamera(0),
mViewport(0)
{
}
void StereoManager::StereoCameraListener::init(StereoManager *stereoMgr, Viewport *viewport, bool isLeftEye)
{
mStereoMgr = stereoMgr;
mCamera = NULL;
mIsLeftEye = isLeftEye;
mViewport = viewport;
}
//void StereoManager::StereoCameraListener::preRenderTargetUpdate(const RenderTargetEvent& evt)
void StereoManager::StereoCameraListener::preViewportUpdate (const RenderTargetViewportEvent& evt)
{
if(evt.source != mViewport)
return;
mCamera = mViewport->getCamera();
if(!mCamera)
return;
mStereoMgr->setCamera(mCamera);
SceneManager *sceneMgr = mCamera->getSceneManager();
mOldVisibilityMask = sceneMgr->getVisibilityMask();
if(mIsLeftEye)
{
sceneMgr->setVisibilityMask(mStereoMgr->mLeftMask & mOldVisibilityMask);
}
else
{
sceneMgr->setVisibilityMask(mStereoMgr->mRightMask & mOldVisibilityMask);
}
// update the frustum offset
Real offset = (mIsLeftEye ? -0.5f : 0.5f) * mStereoMgr->getEyesSpacing();
if(!mStereoMgr->mIsCustomProjection)
{
mOldOffset = mCamera->getFrustumOffset();
if(!mStereoMgr->isFocalLengthInfinite())
mCamera->setFrustumOffset(mOldOffset - Vector2(offset,0));
}
else
{
if(mIsLeftEye)
{
mCamera->setCustomProjectionMatrix(true, mStereoMgr->mLeftCustomProjection);
}
else
{
mCamera->setCustomProjectionMatrix(true, mStereoMgr->mRightCustomProjection);
}
}
// update position
mOldPos = mCamera->getPosition();
Vector3 pos = mOldPos;
pos += offset * mCamera->getRight();
mCamera->setPosition(pos);
// mCamera->moveRelative(Vector3(offset, 0, 0));
mStereoMgr->updateAllDependentRenderTargets(mIsLeftEye);
mStereoMgr->chooseDebugPlaneMaterial(mIsLeftEye);
}
//void StereoManager::StereoCameraListener::postRenderTargetUpdate(const RenderTargetEvent& evt)
void StereoManager::StereoCameraListener::postViewportUpdate (const RenderTargetViewportEvent& evt)
{
if(evt.source != mViewport)
return;
if(!mStereoMgr->mIsCustomProjection)
mCamera->setFrustumOffset(mOldOffset);
else
mCamera->setCustomProjectionMatrix(false);
mCamera->setPosition(mOldPos);
mCamera->getSceneManager()->setVisibilityMask(mOldVisibilityMask);
}
//-------------- Device Lost listener -------------------------------
void StereoManager::DeviceLostListener::init(StereoManager *stereoMgr)
{
mStereoMgr = stereoMgr;
}
void StereoManager::DeviceLostListener::eventOccurred (const String &eventName, const NameValuePairList *parameters)
{
if(eventName == "DeviceRestored")
{
if(mStereoMgr->mCompositorInstance)
{
Viewport *leftViewport, *rightViewport;
mStereoMgr->shutdownListeners();
leftViewport = mStereoMgr->mCompositorInstance->getRenderTarget("Stereo/Left")->getViewport(0);
rightViewport = mStereoMgr->mCompositorInstance->getRenderTarget("Stereo/Right")->getViewport(0);
mStereoMgr->initListeners(leftViewport, rightViewport);
}
}
}
//------------------------ init Stereo Manager --------------------------
StereoManager::StereoManager(void)
{
mStereoMode = SM_NONE;
mDebugPlane = NULL;
mDebugPlaneNode = NULL;
mLeftViewport = NULL;
mRightViewport = NULL;
mCamera = NULL;
mCompositorInstance = NULL;
mIsFocalPlaneFixed = false;
mScreenWidth = 1.0f;
mEyesSpacing = 0.06f;
mFocalLength = 10.0f;
mFocalLengthInfinite = false;
mIsInversed = false;
mIsCustomProjection = false;
mLeftCustomProjection = Matrix4::IDENTITY;
mRightCustomProjection = Matrix4::IDENTITY;
mRightMask = ~((uint32)0);
mLeftMask = ~((uint32)0);
// mAvailableModes[SM_ANAGLYPH] = StereoModeDescription("ANAGLYPH", "Stereo/RedCyanAnaglyph");
mAvailableModes[SM_ANAGLYPH_RC] = StereoModeDescription("ANAGLYPH_RED_CYAN", "Stereo/RedCyanAnaglyph");
mAvailableModes[SM_ANAGLYPH_YB] = StereoModeDescription("ANAGLYPH_YELLOW_BLUE", "Stereo/YellowBlueAnaglyph");
mAvailableModes[SM_INTERLACED_H] = StereoModeDescription("INTERLACED_HORIZONTAL", "Stereo/HorizontalInterlace");
mAvailableModes[SM_INTERLACED_V] = StereoModeDescription("INTERLACED_VERTICAL", "Stereo/VerticalInterlace");
mAvailableModes[SM_INTERLACED_CB] = StereoModeDescription("INTERLACED_CHECKBOARD", "Stereo/CheckboardInterlace");
mAvailableModes[SM_DUALOUTPUT] = StereoModeDescription("DUALOUTPUT");
mAvailableModes[SM_NONE] = StereoModeDescription("NONE");
mLeftCameraListener=new StereoCameraListener();
mRightCameraListener=new StereoCameraListener();
}
StereoManager::~StereoManager(void)
{
shutdown();
destroyDebugPlane();
}
void StereoManager::init(Viewport* leftViewport, Viewport* rightViewport, StereoMode mode)
{
if(mStereoMode != SM_NONE)
return;
mStereoMode = mode;
init(leftViewport, rightViewport);
}
void StereoManager::init(Viewport* leftViewport, Viewport* rightViewport, const String &fileName)
{
if(mStereoMode != SM_NONE)
return;
mStereoMode = loadConfig(fileName);
init(leftViewport, rightViewport);
}
void StereoManager::init(Viewport* leftViewport, Viewport* rightViewport)
{
if(mStereoMode == SM_NONE)
return;
if(!leftViewport)
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "At least left viewport must be provided",
"StereoManager::init");
mCamera = leftViewport->getCamera();
if(!mCamera && rightViewport && !rightViewport->getCamera())
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Viewports must have cameras associated",
"StereoManager::init");
if(rightViewport && mCamera != rightViewport->getCamera())
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Left and right viewports must have the same camera associated",
"StereoManager::init");
if(mAvailableModes[mStereoMode].mUsesCompositor)
{
Viewport *newLeft, *newRight;
initCompositor(leftViewport, mAvailableModes[mStereoMode].mMaterialName, newLeft, newRight);
leftViewport = newLeft;
rightViewport = newRight;
}
initListeners(leftViewport, rightViewport);
RenderTargetList::iterator it;
RenderTargetList::iterator end = mRenderTargetList.end();
for(it = mRenderTargetList.begin(); it != end; ++it)
{
it->first->setAutoUpdated(false);
}
bool infinite = mFocalLengthInfinite;
setFocalLength(mFocalLength); // setFocalLength will erase the infinite focal length option, so backup it and restore it
setFocalLengthInfinite(infinite);
if(mIsFocalPlaneFixed)
updateCamera(0);
}
void StereoManager::initListeners(Viewport* leftViewport, Viewport* rightViewport)
{
if(mLeftCameraListener==NULL)
{
mLeftCameraListener=new StereoCameraListener();
}
if(mRightCameraListener==NULL)
{
mRightCameraListener=new StereoCameraListener();
}
if(leftViewport)
{
mLeftCameraListener->init(this, leftViewport, !mIsInversed);
leftViewport->getTarget()->addListener(mLeftCameraListener);
mLeftViewport = leftViewport;
}
if(rightViewport)
{
mRightCameraListener->init(this, rightViewport, mIsInversed);
rightViewport->getTarget()->addListener(mRightCameraListener);
mRightViewport = rightViewport;
}
}
void StereoManager::shutdownListeners(void)
{
if(mLeftViewport)
{
mLeftViewport->getTarget()->removeListener(mLeftCameraListener);
mLeftViewport = NULL;
}
if(mRightViewport)
{
mRightViewport->getTarget()->removeListener(mRightCameraListener);
mRightViewport = NULL;
}
}
void StereoManager::initCompositor(Viewport *viewport, const String &materialName, Viewport *&out_left, Viewport *&out_right)
{
mCompositorViewport = viewport;
mCompositorInstance = CompositorManager::getSingleton().addCompositor(viewport, "Stereo/BaseCompositor");
if(!mCompositorInstance)
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Cannot create compositor, missing StereoManager resources",
"StereoManager::initCompositor");
CompositorManager::getSingleton().setCompositorEnabled(viewport, "Stereo/BaseCompositor", true);
MaterialPtr mat = static_cast<MaterialPtr>(MaterialManager::getSingleton().getByName(materialName));
if(mat.isNull())
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, materialName + " not found, missing StereoManager resources",
"StereoManager::initCompositor");
mCompositorInstance->getTechnique()->getOutputTargetPass()->getPass(0)->setMaterial(mat);
out_left = mCompositorInstance->getRenderTarget("Stereo/Left")->getViewport(0);
out_right = mCompositorInstance->getRenderTarget("Stereo/Right")->getViewport(0);
/*
// extract all the compositors added to the main viewport and attach them to the left/right vewports
CompositorManager &compositorManager = CompositorManager::getSingleton();
if(compositorManager.hasCompositorChain(mCompositorViewport))
{
CompositorChain *oldChain = compositorManager.getCompositorChain(mCompositorViewport);
for(unsigned int i = 0; i < oldChain->getNumCompositors(); i++)
{
CompositorInstance *compositorInstance = oldChain->getCompositor(i);
Compositor *compositor = compositorInstance->getCompositor();
compositorManager.addCompositor(leftViewport, compositor->getName());
compositorManager.setCompositorEnabled(leftViewport, compositor->getName(),compositorInstance->getEnabled());
compositorManager.addCompositor(rightViewport, compositor->getName());
compositorManager.setCompositorEnabled(rightViewport, compositor->getName(),compositorInstance->getEnabled());
}
// remove the compositors from the main viewport since they are now on the left/right vewports
oldChain->removeAllCompositors();
}
*/
/*
// enable the overlays on the new viewports and disable them from the main viewport
mAreOverlaysEnabled = viewport->getOverlaysEnabled();
out_left->setOverlaysEnabled(mAreOverlaysEnabled);
out_right->setOverlaysEnabled(mAreOverlaysEnabled);
viewport->setOverlaysEnabled(false);
*/
mDeviceLostListener.init(this);
Root::getSingleton().getRenderSystem()->addListener(&mDeviceLostListener);
}
void StereoManager::shutdownCompositor()
{
CompositorManager::getSingleton().setCompositorEnabled(mCompositorViewport, "Stereo/BaseCompositor", false);
CompositorManager::getSingleton().removeCompositor(mCompositorViewport, "Stereo/BaseCompositor");
/*
// put back the compositors on the main viewport
CompositorManager &compositorManager = CompositorManager::getSingleton();
if(compositorManager.hasCompositorChain(mLeftViewport))
{
CompositorChain *oldChain = compositorManager.getCompositorChain(mLeftViewport);
for(unsigned int i = 0; i < oldChain->getNumCompositors(); i++)
{
CompositorInstance *compositorInstance = oldChain->getCompositor(i);
Compositor *compositor = compositorInstance->getCompositor();
compositorManager.addCompositor(mCompositorViewport, compositor->getName());
compositorManager.setCompositorEnabled(mCompositorViewport, compositor->getName(),compositorInstance->getEnabled());
}
oldChain->removeAllCompositors();
}
//mRightTarget->removeAllViewports();
//mLeftTarget->removeAllViewports();
mCompositorViewport->setOverlaysEnabled(mAreOverlaysEnabled);
*/
/*
mCompositorViewport->setOverlaysEnabled(mAreOverlaysEnabled);
*/
Root::getSingleton().getRenderSystem()->removeListener(&mDeviceLostListener);
mCompositorInstance = NULL;
mCompositorViewport = NULL;
}
void StereoManager::shutdown(void)
{
if(mStereoMode == SM_NONE)
return;
shutdownListeners();
if(mAvailableModes[mStereoMode].mUsesCompositor)
shutdownCompositor();
RenderTargetList::iterator it;
RenderTargetList::iterator end = mRenderTargetList.end();
for(it = mRenderTargetList.begin(); it != end; ++it)
{
it->first->setAutoUpdated(it->second);
}
mStereoMode = SM_NONE;
}
//-------------------------- misc --------------
void StereoManager::setVisibilityMask(uint32 leftMask, uint32 rightMask)
{
// if(mLeftViewport)
// {
// mLeftViewport->setVisibilityMask(leftMask);
// }
// if(mRightViewport)
// {
// mRightViewport->setVisibilityMask(rightMask);
// }
mRightMask = rightMask;
mLeftMask = leftMask;
}
void StereoManager::getVisibilityMask(uint32 &outLeftMask, uint32 &outRightMask) const
{
outRightMask = mRightMask;
outLeftMask = mLeftMask;
}
void StereoManager::addRenderTargetDependency(RenderTarget *renderTarget)
{
if(mRenderTargetList.find(renderTarget) != mRenderTargetList.end())
return;
mRenderTargetList[renderTarget] = renderTarget->isAutoUpdated();
renderTarget->setAutoUpdated(false);
}
void StereoManager::removeRenderTargetDependency(RenderTarget *renderTarget)
{
if(mRenderTargetList.find(renderTarget) == mRenderTargetList.end())
return;
renderTarget->setAutoUpdated(mRenderTargetList[renderTarget]);
mRenderTargetList.erase(renderTarget);
}
void StereoManager::updateAllDependentRenderTargets(bool isLeftEye)
{
uint32 mask;
if(isLeftEye)
{
mask = mLeftMask;
}
else
{
mask = mRightMask;
}
RenderTargetList::iterator itarg, itargend;
itargend = mRenderTargetList.end();
for( itarg = mRenderTargetList.begin(); itarg != itargend; ++itarg )
{
RenderTarget *rt = itarg->first;
int n = rt->getNumViewports();
std::vector<int> maskVector(n); // VS2005 gives a warning if I declare the vector as uint32 but not with int
for(int i = 0; i<n ; ++i)
{
maskVector[i] = rt->getViewport(i)->getVisibilityMask();
rt->getViewport(i)->setVisibilityMask(maskVector[i] & mask);
}
rt->update();
for(int i = 0; i<n ; ++i)
{
rt->getViewport(i)->setVisibilityMask(maskVector[i]);
}
}
}
//---------------------------- Stereo tuning ------------------------
void StereoManager::setFocalLength(Real l)
{
if(l == std::numeric_limits<Real>::infinity())
{
setFocalLengthInfinite(true);
}
else
{
setFocalLengthInfinite(false);
Real old = mFocalLength;
mFocalLength = l;
if( mCamera )
{
mCamera->setFocalLength(mFocalLength);
if(mIsFocalPlaneFixed)
updateCamera(mFocalLength - old);
else if(mDebugPlane)
updateDebugPlane();
}
}
}
Real StereoManager::getFocalLength(void) const
{
if(mFocalLengthInfinite)
return std::numeric_limits<Real>::infinity();
else
return mFocalLength;
}
void StereoManager::setFocalLengthInfinite(bool isInfinite)
{
mFocalLengthInfinite = isInfinite;
if(isInfinite)
mIsFocalPlaneFixed = false;
}
void StereoManager::useScreenWidth(Real w)
{
mScreenWidth = w;
mIsFocalPlaneFixed = true;
if( mCamera )
updateCamera(0);
}
void StereoManager::updateCamera(Real delta)
{
mCamera->moveRelative(-delta * Vector3::UNIT_Z);
Radian a = 2 * Math::ATan(mScreenWidth/(2 * mFocalLength * mCamera->getAspectRatio()));
mCamera->setFOVy(a);
}
void StereoManager::inverseStereo(bool inverse)
{
mIsInversed = inverse;
mLeftCameraListener->mIsLeftEye = !mIsInversed;
mRightCameraListener->mIsLeftEye = mIsInversed;
}
void StereoManager::setCustomProjectonMatrices(bool enable, const Matrix4 &leftMatrix, const Matrix4 &rightMatrix)
{
mIsCustomProjection = enable;
mLeftCustomProjection = leftMatrix;
mRightCustomProjection = rightMatrix;
}
void StereoManager::getCustomProjectonMatrices(bool &enabled, Matrix4 &leftMatrix, Matrix4 &rightMatrix) const
{
enabled = mIsCustomProjection;
leftMatrix = mLeftCustomProjection;
rightMatrix = mRightCustomProjection;
}
//------------------------------------ Debug focal plane ---------------------------------
void StereoManager::enableDebugPlane(bool enable)
{
if(mDebugPlane)
mDebugPlane->setVisible(enable);
}
void StereoManager::toggleDebugPlane(void)
{
if(mDebugPlane)
mDebugPlane->setVisible(!mDebugPlane->isVisible());
}
void StereoManager::createDebugPlane(SceneManager *sceneMgr, const String &leftMaterialName, const String &rightMaterialName)
{
if(mDebugPlane)
return;
mSceneMgr = sceneMgr;
Plane screenPlane;
screenPlane.normal = Vector3::UNIT_Z;
MeshManager::getSingleton().createPlane("Stereo/Plane",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
screenPlane,1,1,10,10);
mDebugPlane = sceneMgr->createEntity( "Stereo/DebugPlane", "Stereo/Plane" );
if(leftMaterialName == "")
{
mLeftMaterialName = "Stereo/Wireframe";
}
else
{
mLeftMaterialName = leftMaterialName;
}
if(rightMaterialName == "")
{
mRightMaterialName = "Stereo/Wireframe";
}
else
{
mRightMaterialName = rightMaterialName;
}
mDebugPlaneNode = static_cast<SceneNode*>(sceneMgr->getRootSceneNode()->createChild("Stereo/DebugPlaneNode"));
mDebugPlaneNode->attachObject(mDebugPlane);
enableDebugPlane(true);
updateDebugPlane();
}
void StereoManager::destroyDebugPlane(void)
{
if(mDebugPlane)
{
SceneNode *parent = static_cast<SceneNode*>(mDebugPlaneNode->getParent());
parent->removeAndDestroyChild("Stereo/DebugPlaneNode");
mDebugPlaneNode = NULL;
mSceneMgr->destroyEntity("Stereo/DebugPlane");
mDebugPlane = NULL;
MeshManager::getSingleton().remove("Stereo/Plane");
}
}
void StereoManager::updateDebugPlane(void)
{
if(mDebugPlaneNode && mCamera)
{
Real actualFocalLength = mFocalLengthInfinite ? mCamera->getFarClipDistance() * 0.99f : mFocalLength;
Vector3 pos = mCamera->getDerivedPosition();
pos += mCamera->getDerivedDirection() * actualFocalLength;
mDebugPlaneNode->setPosition(pos);
mDebugPlaneNode->setOrientation(mCamera->getDerivedOrientation());
Vector3 scale;
Real height = actualFocalLength * Math::Tan(mCamera->getFOVy()/2)*2;
scale.z = 1;
scale.y = height;
scale.x = height * mCamera->getAspectRatio();
mDebugPlaneNode->setScale(scale);
}
}
void StereoManager::chooseDebugPlaneMaterial(bool isLeftEye)
{
if(mDebugPlane)
{
if(isLeftEye)
mDebugPlane->setMaterialName(mLeftMaterialName);
else
mDebugPlane->setMaterialName(mRightMaterialName);
}
}
//-------------------------------------- config ------------------------------------
void StereoManager::saveConfig(const String &filename) const
{
std::ofstream of(filename.c_str());
if (!of)
OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create settings file.",
"StereoManager::saveConfig");
of << "[Stereoscopy]" << std::endl;
of << "# Available Modes: ";
const StereoModeList::const_iterator end = mAvailableModes.end();
for(StereoModeList::const_iterator it = mAvailableModes.begin(); it != end; ++it)
{
of << it->second.mName << " ";
}
of << std::endl;
StereoModeList::const_iterator it = mAvailableModes.find(mStereoMode);
if(it != mAvailableModes.end())
of << "Stereo mode = " << it->second.mName << std::endl;
else
of << "Stereo mode = " << "NONE # wrong enum value, defaults to NONE" << std::endl;
of << "Eyes spacing = " << mEyesSpacing << std::endl;
of << "# Set to inf for parallel frustrum stereo." << std::endl;
if(mFocalLengthInfinite)
of << "Focal length = " << "inf" << std::endl;
else
of << "Focal length = " << mFocalLength << std::endl;
of << "Inverse stereo = " << (mIsInversed ? "true" : "false") << std::endl;
of << std::endl << "# For advanced use. See StereoManager.h for details." << std::endl;
of << "Fixed screen = " << (mIsFocalPlaneFixed ? "true" : "false") << std::endl;
of << "Screen width = " << mScreenWidth << std::endl;
of.close();
}
StereoManager::StereoMode StereoManager::loadConfig(const String &filename)
{
ConfigFile cf;
cf.load(filename.c_str());
StereoMode mode;
const String &modeName = cf.getSetting("Stereo mode","Stereoscopy");
const StereoModeList::const_iterator end = mAvailableModes.end();
StereoModeList::iterator it;
for(it = mAvailableModes.begin(); it != end; ++it)
{
if(it->second.mName == modeName)
{
mode = it->first;
break;
}
}
if(it == mAvailableModes.end())
mode = SM_NONE;
fixFocalPlanePos(StringConverter::parseBool(cf.getSetting("Fixed screen","Stereoscopy")));
if(cf.getSetting("Focal length","Stereoscopy") == "inf")
mFocalLengthInfinite = true;
else
setFocalLength(StringConverter::parseReal(cf.getSetting("Focal length","Stereoscopy")));
setEyesSpacing(StringConverter::parseReal(cf.getSetting("Eyes spacing","Stereoscopy")));
setScreenWidth(StringConverter::parseReal(cf.getSetting("Screen width","Stereoscopy")));
inverseStereo(StringConverter::parseBool(cf.getSetting("Inverse stereo","Stereoscopy")));
return mode;
}
Code: Select all
/*
-----------------------------------------------------------------------------
This source is part of the Stereoscopy manager for OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
-----------------------------------------------------------------------------
* Copyright (c) 2008, Mathieu Le Ber, AXYZ-IMAGES
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the AXYZ-IMAGES nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Mathieu Le Ber ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Mathieu Le Ber BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
// Last update jan 19 2010
#ifndef _STEREOMANAGER_H_
#define _STEREOMANAGER_H_
#include "stdafx.h"
#include <map>
/** Stereo vision manager class.
This manager supports two stereo vision mode :
- An anaglyph mode for red/blue glasses
- Three interlaced modes for autostereoscopic screens
- A dual output mode to use with a polarized screen and two projectors or mounted head display
Note :
Ogre does not support natively the output in fullscreen on two screens. If you want to use the
dual output mode with two fullscreen displays, you may want to apply this patch to OGRE :
http://sourceforge.net/tracker/index.php?func=detail&aid=2555758&group_id=2997&atid=302997
However, this manager is completely indepedent from this patch, the dual output mode only needs two viewports,
for example two non-fullscreen windows or a windows with two viewports inside.
*/
namespace Ogre
{
class StereoManager
{
public:
enum StereoMode
{
SM_NONE,
/// Anaglyph red/cyan
SM_ANAGLYPH_RC,
/// Anaglyph yellow/blue
SM_ANAGLYPH_YB,
/// Dual output off-axis mode : suitable for two projectors with polarized filters or head mounted display
SM_DUALOUTPUT,
/// Verticaly interlaced mode
SM_INTERLACED_V,
/// Horizontaly interlaced mode
SM_INTERLACED_H,
/// Interlaced mode with a checkerboard pattern
SM_INTERLACED_CB,
/// max value of the enum
SM_LIMIT
//SM_SHUTTERGLASSES
};
struct StereoModeDescription
{
StereoModeDescription() {}
StereoModeDescription(const String &name) :
mName(name), mUsesCompositor(false), mMaterialName("") {}
StereoModeDescription(const String &name, const String &materialName) :
mName(name), mUsesCompositor(true), mMaterialName(materialName) {}
StereoModeDescription &operator=(const StereoModeDescription &desc)
{
mName = desc.mName;
mMaterialName = desc.mMaterialName;
mUsesCompositor = desc.mUsesCompositor;
return *this;
}
String mName;
String mMaterialName;
bool mUsesCompositor;
};
typedef std::map<StereoMode, StereoModeDescription> StereoModeList;
protected:
class StereoCameraListener : public RenderTargetListener
{
public:
StereoCameraListener(void);
Vector3 mOldPos;
Vector2 mOldOffset;
uint32 mOldVisibilityMask;
StereoManager *mStereoMgr;
Camera *mCamera;
Viewport *mViewport;
bool mIsLeftEye;
void init(StereoManager *stereoMgr, Viewport *viewport, bool isLeftCamera);
// virtual void preRenderTargetUpdate (const RenderTargetEvent& evt);
// virtual void postRenderTargetUpdate (const RenderTargetEvent& evt);
virtual void preViewportUpdate (const RenderTargetViewportEvent &evt);
virtual void postViewportUpdate (const RenderTargetViewportEvent &evt);
};
friend class StereoCameraListener;
class DeviceLostListener : public RenderSystem::Listener
{
StereoManager *mStereoMgr;
public:
void init(StereoManager *stereoMgr);
virtual void eventOccurred (const String &eventName, const NameValuePairList *parameters);
};
friend class DeviceLostListener;
Camera *mCamera;
StereoCameraListener* mLeftCameraListener;
StereoCameraListener* mRightCameraListener;
DeviceLostListener mDeviceLostListener;
Viewport *mLeftViewport, *mRightViewport;
uint32 mLeftMask, mRightMask;
CompositorInstance *mCompositorInstance;
/* config */
StereoModeList mAvailableModes;
StereoMode mStereoMode;
Real mEyesSpacing;
Real mFocalLength;
bool mFocalLengthInfinite;
bool mIsFocalPlaneFixed;
Real mScreenWidth;
bool mIsInversed;
bool mIsCustomProjection;
Matrix4 mLeftCustomProjection, mRightCustomProjection;
//String mConfigFileName;
/* members for anaglyph only */
bool mAreOverlaysEnabled;
Viewport *mCompositorViewport;
/* dependencies */
typedef std::map<RenderTarget *, bool> RenderTargetList;
//typedef std::list<RenderTarget *> RenderTargetList;
RenderTargetList mRenderTargetList;
/* debug plane */
SceneManager *mSceneMgr;
Entity *mDebugPlane;
SceneNode *mDebugPlaneNode;
String mLeftMaterialName, mRightMaterialName;
void initCompositor(Viewport *viewport, const String &materialName, Viewport *&out_left, Viewport *&out_right);
void shutdownCompositor(void);
void initListeners(Viewport* leftViewport, Viewport* rightViewport);
void shutdownListeners(void);
void updateCamera(Real delta);
void init(Viewport* leftViewport, Viewport* rightViewport);
void updateAllDependentRenderTargets(bool isLeftEye);
void chooseDebugPlaneMaterial(bool isLeftEye);
public:
//--------------init--------------
StereoManager(void);
~StereoManager(void);
/** The manager should be initialized with two viewports if you want dual output stereo (SM_DUALOUTPUT).
If you want red/blue anaglyph stereo (SM_ANAGLYPH) you only need one viewport, just set the rightViewport to NULL.
The left eye and the right eye will be composited on the leftViewport.
The camera will be detected from the viewports.
You can also use a configuration file that will store the stereo mode, the focal length, the eye spacing and
the screen width. */
void init(Viewport* leftViewport, Viewport* rightViewport, const String &fileName);
void init(Viewport* leftViewport, Viewport* rightViewport, StereoMode mode);
/** Shutdown and re-init the stereo manager to change stereo mode */
void shutdown(void);
//--------------dependencies--------------
/** RenderTargets added with this method will no longer be auto-updated but will be updated
one time before the right viewport is updated and one time before the left viewport is updated.
It is useful if you have a render texture whose content depends on the camera position,
for example a render texture for water reflection */
void addRenderTargetDependency(RenderTarget *renderTarget);
void removeRenderTargetDependency(RenderTarget *renderTarget);
//--------------debug plane--------------
/** Create a representation of the focal plane in the scene. If no material name is provided,
a default wireframe material is used.
The position of the debug plane will no longer be consistent with the focal length when it is set to infinite.
The focal plane will still use the last finite focal length. */
void createDebugPlane(SceneManager *sceneMgr, const String &leftMaterialName = "", const String &rightMaterialName = "");
void destroyDebugPlane(void);
void enableDebugPlane(bool enable);
void toggleDebugPlane(void);
void updateDebugPlane(void);
//--------------accessors--------------
inline StereoMode getStereoMode(void) const {return mStereoMode;}
inline Camera *getCamera(void) const {return mCamera;}
inline void setCamera(Camera *cam) {mCamera = cam;}
inline Real getEyesSpacing(void) const {return mEyesSpacing;}
inline void setEyesSpacing(Real l) {mEyesSpacing = l;}
/** Sets the focal length of the camera, i.e. the distance at which a point will be rendered at the same position
on the screen for each eye. Will disable the infinite focal length */
void setFocalLength(Real l);
/** Returns the focal length.
Will return std::numeric_limits<Real>::infinity() if you used setFocalLengthInfinite(true) */
Real getFocalLength(void) const;
/** Sets the focal length to infinite. Usefull if you use Head Mounted Displays because you need parallel frustums.
The position of the debug plane will no longer be consistent with the focal length when it is set to infinite.
The focal plane will still use the last finite focal length. */
void setFocalLengthInfinite(bool isInfinite = true);
inline bool isFocalLengthInfinite(void) const { return mFocalLengthInfinite; }
/** The focal plane represents the screen in the world space. As the screen
is not and infinite plane but a rectangle, what I call the focal plane is in fact
a rectangle.
When the position of the plane is fixed, its position and size doesn't change if
you change the focal length. Instead the camera is moved to reflect the focal length.
The FOV angle of the camera is also adjusted in order to keep the focal rectangle
covering the whole field view.
If you set the screen width in the manager you can achieve a 1:1 scale effect if the
observer's distance to the screen is equal to the focal distance.*/
inline void fixFocalPlanePos(bool fix) {mIsFocalPlaneFixed = fix;}
inline void setScreenWidth(Real w) {mScreenWidth = w;}
void useScreenWidth(Real w);
/** Use a custom projections matrix for each eye */
void setCustomProjectonMatrices(bool enable, const Matrix4 &leftMatrix, const Matrix4 &rightMatrix);
void getCustomProjectonMatrices(bool &enabled, Matrix4 &leftMatrix, Matrix4 &rightMatrix) const;
/** Inverse the left eye and the right eye viewports */
void inverseStereo(bool inverse);
bool isStereoInversed(void) const {return mIsInversed;}
/** Only objects matching the following flags will be rendered.
This method sets the visibility mask for the right and the left viewports and
the according mask for each dependent render target.
It is usefull if you want to display some objects only for the right eye and
some objects only for the left eye .*/
void setVisibilityMask(uint32 leftMask, uint32 rightMask);
void getVisibilityMask(uint32 &outLeftMask, uint32 &outRightMask) const;
/** retrieve the left and right viewports.
They will be the same as the ones you passed to the init method in the DUAL_OUTPUT mode.
They will be different in case of the modes using the compositor. */
Viewport *getLeftViewport(void) const { return mLeftViewport; }
Viewport *getRightViewport(void) const { return mRightViewport; }
//--------------config--------------
/** You can save and load the stereo configuration (mode, eyes spacing, focal length and screen width)
to a file. Then this file can be used to initialize the manager. */
void saveConfig(const String &filename) const;
StereoMode loadConfig(const String &filename);
};
}
#endif