Stereo vision manager [now as a plugin]

A place for users of OGRE to discuss ideas and experiences of utilitising OGRE in their games / demos / applications.
Post Reply
Ogra
Goblin
Posts: 268
Joined: Mon Feb 04, 2013 1:34 pm

Re: Stereo vision manager [now as a plugin]

Post by Ogra »

I know this thread is old but perhaps somebody could help.

I set

Code: Select all

mStereoManager.init(mWindow->getViewport(0), NULL, Ogre::StereoManager::SM_ANAGLYPH_RC);
to the end of my scene, but all I get is a black screen. What could be the reason for this?
Ogra
Goblin
Posts: 268
Joined: Mon Feb 04, 2013 1:34 pm

Re: Stereo vision manager [now as a plugin]

Post by Ogra »

I found out that is was my graphiccard which made this trouble.
Emerich
Halfling
Posts: 64
Joined: Wed Oct 24, 2012 10:59 am
x 12

Re: Stereo vision manager [now as a plugin]

Post by Emerich »

Hey all - sorry for necroing this thread but this question fits in here best.

I'm trying to use the Stereomanager in my android project (Ogre 1.9) . Since I don't have a phone that runs with 120hz, I decided to try the red cyan anaglyph stereo. I wrote the glsles shader and material and tested it on my own RTT - so that seems to work.
Now when I try using the Stereomanager and thus the Compositor, it simply doesn't work.
Considering the camera shift happens in the preViewportUpdate, I assume that has to be called - and that never happens.

Here's the part of my code:

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);
I would love some hints on what I'm doing wrong here.

Edit: I just tried it on the Windows Ogre to make sure it is not an issue with Android and I got the same issue.

Edit2: After changing all the listener references to pointers it works. God knows why. Code is below if anyone should run into that issue. Going to test it on Android next.

Edit3: Well even with a minimal example, the listeners never get called on android. I will create another topic in the mobile forum since this seems unrelated to this code.

StereoManager.cpp:

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;
}

Stereomanager.h

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
stevenrice
Gnoblar
Posts: 7
Joined: Sun Mar 17, 2013 4:01 pm

Re: Stereo vision manager [now as a plugin]

Post by stevenrice »

how to display in two screen? Because my result only display in single screen, when I used Dual output mode.

Would you please tell me how to solve this problem. Should I modify the syntax and parameters? or to adjust the environmental parameters.
Post Reply