00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "Ogre.h"
00037 #include "StereoManager.h"
00038 #include <vector>
00039 #include <limits>
00040 using namespace Ogre;
00041
00042
00043
00044 void StereoManager::StereoCameraListener::init(StereoManager *stereoMgr, Viewport *viewport, bool isLeftEye)
00045 {
00046 mStereoMgr = stereoMgr;
00047 mCamera = NULL;
00048 mIsLeftEye = isLeftEye;
00049 mViewport = viewport;
00050 }
00051
00052
00053 void StereoManager::StereoCameraListener::preViewportUpdate (const RenderTargetViewportEvent& evt)
00054 {
00055 if(evt.source != mViewport)
00056 return;
00057 mCamera = mViewport->getCamera();
00058 assert(mCamera);
00059 mStereoMgr->setCamera(mCamera);
00060
00061 SceneManager *sceneMgr = mCamera->getSceneManager();
00062 mOldVisibilityMask = sceneMgr->getVisibilityMask();
00063
00064 if(mIsLeftEye)
00065 {
00066 sceneMgr->setVisibilityMask(mStereoMgr->mLeftMask & mOldVisibilityMask);
00067 }
00068 else
00069 {
00070 sceneMgr->setVisibilityMask(mStereoMgr->mRightMask & mOldVisibilityMask);
00071 }
00072
00073
00074 Real offset = (mIsLeftEye ? -0.5f : 0.5f) * mStereoMgr->getEyesSpacing();
00075
00076 if(!mStereoMgr->mIsCustomProjection)
00077 {
00078 mOldOffset = mCamera->getFrustumOffset();
00079 if(!mStereoMgr->isFocalLengthInfinite())
00080 mCamera->setFrustumOffset(mOldOffset - Vector2(offset,0));
00081 }
00082 else
00083 {
00084 if(mIsLeftEye)
00085 {
00086 mCamera->setCustomProjectionMatrix(true, mStereoMgr->mLeftCustomProjection);
00087 }
00088 else
00089 {
00090 mCamera->setCustomProjectionMatrix(true, mStereoMgr->mRightCustomProjection);
00091 }
00092 }
00093
00094
00095 mOldPos = mCamera->getPosition();
00096 Vector3 pos = mOldPos;
00097
00098 pos += offset * mCamera->getRight();
00099 mCamera->setPosition(pos);
00100
00101 mStereoMgr->updateAllDependentRenderTargets(mIsLeftEye);
00102 mStereoMgr->chooseDebugPlaneMaterial(mIsLeftEye);
00103 }
00104
00105 void StereoManager::StereoCameraListener::postViewportUpdate (const RenderTargetViewportEvent& evt)
00106 {
00107 if(evt.source != mViewport)
00108 return;
00109
00110 if(!mStereoMgr->mIsCustomProjection)
00111 mCamera->setFrustumOffset(mOldOffset);
00112 else
00113 mCamera->setCustomProjectionMatrix(false);
00114
00115 mCamera->setPosition(mOldPos);
00116
00117 mCamera->getSceneManager()->setVisibilityMask(mOldVisibilityMask);
00118 }
00119
00120
00121
00122 void StereoManager::DeviceLostListener::init(StereoManager *stereoMgr)
00123 {
00124 mStereoMgr = stereoMgr;
00125 }
00126
00127 void StereoManager::DeviceLostListener::eventOccurred (const String &eventName, const NameValuePairList *parameters)
00128 {
00129 if(eventName == "DeviceRestored")
00130 {
00131 if(mStereoMgr->mCompositorInstance)
00132 {
00133 Viewport *leftViewport, *rightViewport;
00134 mStereoMgr->shutdownListeners();
00135 leftViewport = mStereoMgr->mCompositorInstance->getRenderTarget("Stereo/Left")->getViewport(0);
00136 rightViewport = mStereoMgr->mCompositorInstance->getRenderTarget("Stereo/Right")->getViewport(0);
00137 mStereoMgr->initListeners(leftViewport, rightViewport);
00138 }
00139 }
00140 }
00141
00142
00143 StereoManager::StereoManager(void)
00144 {
00145 mStereoMode = SM_NONE;
00146 mDebugPlane = NULL;
00147 mDebugPlaneNode = NULL;
00148 mLeftViewport = NULL;
00149 mRightViewport = NULL;
00150 mCamera = NULL;
00151 mCompositorInstance = NULL;
00152 mIsFocalPlaneFixed = false;
00153 mScreenWidth = 1.0f;
00154 mEyesSpacing = 0.06f;
00155 mFocalLength = 10.0f;
00156 mFocalLengthInfinite = false;
00157 mIsInversed = false;
00158 mIsCustomProjection = false;
00159 mLeftCustomProjection = Matrix4::IDENTITY;
00160 mRightCustomProjection = Matrix4::IDENTITY;
00161 mRightMask = ~((uint32)0);
00162 mLeftMask = ~((uint32)0);
00163
00164 mAvailableModes[SM_ANAGLYPH_RC] = StereoModeDescription("ANAGLYPH_RED_CYAN", "Stereo/RedCyanAnaglyph");
00165 mAvailableModes[SM_ANAGLYPH_YB] = StereoModeDescription("ANAGLYPH_YELLOW_BLUE", "Stereo/YellowBlueAnaglyph");
00166 mAvailableModes[SM_INTERLACED_H] = StereoModeDescription("INTERLACED_HORIZONTAL", "Stereo/HorizontalInterlace");
00167 mAvailableModes[SM_INTERLACED_V] = StereoModeDescription("INTERLACED_VERTICAL", "Stereo/VerticalInterlace");
00168 mAvailableModes[SM_INTERLACED_CB] = StereoModeDescription("INTERLACED_CHECKBOARD", "Stereo/CheckboardInterlace");
00169
00170 mAvailableModes[SM_DUALOUTPUT] = StereoModeDescription("DUALOUTPUT");
00171 mAvailableModes[SM_NONE] = StereoModeDescription("NONE");
00172 }
00173
00174 StereoManager::~StereoManager(void)
00175 {
00176 shutdown();
00177 destroyDebugPlane();
00178 }
00179
00180 void StereoManager::init(Viewport* leftViewport, Viewport* rightViewport, StereoMode mode)
00181 {
00182 if(mStereoMode != SM_NONE)
00183 return;
00184 mStereoMode = mode;
00185 init(leftViewport, rightViewport);
00186 }
00187
00188 void StereoManager::init(Viewport* leftViewport, Viewport* rightViewport, const String &fileName)
00189 {
00190 if(mStereoMode != SM_NONE)
00191 return;
00192 mStereoMode = loadConfig(fileName);
00193 init(leftViewport, rightViewport);
00194 }
00195
00196 void StereoManager::init(Viewport* leftViewport, Viewport* rightViewport)
00197 {
00198 if(mStereoMode == SM_NONE)
00199 return;
00200 if(!leftViewport)
00201 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "At least left viewport must be provided",
00202 "StereoManager::init");
00203
00204 mCamera = leftViewport->getCamera();
00205 if(!mCamera && rightViewport && !rightViewport->getCamera())
00206 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Viewports must have cameras associated",
00207 "StereoManager::init");
00208
00209 if(rightViewport && mCamera != rightViewport->getCamera())
00210 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Left and right viewports must have the same camera associated",
00211 "StereoManager::init");
00212
00213
00214 if(mAvailableModes[mStereoMode].mUsesCompositor)
00215 {
00216 Viewport *newLeft, *newRight;
00217 initCompositor(leftViewport, mAvailableModes[mStereoMode].mMaterialName, newLeft, newRight);
00218 leftViewport = newLeft;
00219 rightViewport = newRight;
00220 }
00221
00222 initListeners(leftViewport, rightViewport);
00223
00224 RenderTargetList::iterator it;
00225 RenderTargetList::iterator end = mRenderTargetList.end();
00226 for(it = mRenderTargetList.begin(); it != end; ++it)
00227 {
00228 it->first->setAutoUpdated(false);
00229 }
00230
00231 bool infinite = mFocalLengthInfinite;
00232 setFocalLength(mFocalLength);
00233 setFocalLengthInfinite(infinite);
00234
00235 if(mIsFocalPlaneFixed)
00236 updateCamera(0);
00237 }
00238
00239 void StereoManager::initListeners(Viewport* leftViewport, Viewport* rightViewport)
00240 {
00241 if(leftViewport)
00242 {
00243 mLeftCameraListener.init(this, leftViewport, !mIsInversed);
00244 leftViewport->getTarget()->addListener(&mLeftCameraListener);
00245 mLeftViewport = leftViewport;
00246 }
00247
00248 if(rightViewport)
00249 {
00250 mRightCameraListener.init(this, rightViewport, mIsInversed);
00251 rightViewport->getTarget()->addListener(&mRightCameraListener);
00252 mRightViewport = rightViewport;
00253 }
00254 }
00255
00256 void StereoManager::shutdownListeners(void)
00257 {
00258 if(mLeftViewport)
00259 {
00260 mLeftViewport->getTarget()->removeListener(&mLeftCameraListener);
00261 mLeftViewport = NULL;
00262 }
00263 if(mRightViewport)
00264 {
00265 mRightViewport->getTarget()->removeListener(&mRightCameraListener);
00266 mRightViewport = NULL;
00267 }
00268 }
00269
00270 void StereoManager::initCompositor(Viewport *viewport, const String &materialName, Viewport *&out_left, Viewport *&out_right)
00271 {
00272 mCompositorViewport = viewport;
00273 mCompositorInstance = CompositorManager::getSingleton().addCompositor(viewport, "Stereo/BaseCompositor");
00274 if(!mCompositorInstance)
00275 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Cannot create compositor, missing StereoManager resources",
00276 "StereoManager::initCompositor");
00277 CompositorManager::getSingleton().setCompositorEnabled(viewport, "Stereo/BaseCompositor", true);
00278
00279 MaterialPtr mat = static_cast<MaterialPtr>(MaterialManager::getSingleton().getByName(materialName));
00280 if(mat.isNull())
00281 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, materialName + " not found, missing StereoManager resources",
00282 "StereoManager::initCompositor");
00283
00284 mCompositorInstance->getTechnique()->getOutputTargetPass()->getPass(0)->setMaterial(mat);
00285 out_left = mCompositorInstance->getRenderTarget("Stereo/Left")->getViewport(0);
00286 out_right = mCompositorInstance->getRenderTarget("Stereo/Right")->getViewport(0);
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 mDeviceLostListener.init(this);
00317 Root::getSingleton().getRenderSystem()->addListener(&mDeviceLostListener);
00318 }
00319
00320 void StereoManager::shutdownCompositor()
00321 {
00322 CompositorManager::getSingleton().setCompositorEnabled(mCompositorViewport, "Stereo/BaseCompositor", false);
00323 CompositorManager::getSingleton().removeCompositor(mCompositorViewport, "Stereo/BaseCompositor");
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 Root::getSingleton().getRenderSystem()->removeListener(&mDeviceLostListener);
00349 mCompositorInstance = NULL;
00350 mCompositorViewport = NULL;
00351 }
00352
00353 void StereoManager::shutdown(void)
00354 {
00355 if(mStereoMode == SM_NONE)
00356 return;
00357
00358 shutdownListeners();
00359 if(mAvailableModes[mStereoMode].mUsesCompositor)
00360 shutdownCompositor();
00361
00362 RenderTargetList::iterator it;
00363 RenderTargetList::iterator end = mRenderTargetList.end();
00364 for(it = mRenderTargetList.begin(); it != end; ++it)
00365 {
00366 it->first->setAutoUpdated(it->second);
00367 }
00368
00369 mStereoMode = SM_NONE;
00370 }
00371
00372
00373 void StereoManager::setVisibilityMask(uint32 leftMask, uint32 rightMask)
00374 {
00375
00376
00377
00378
00379
00380
00381
00382
00383 mRightMask = rightMask;
00384 mLeftMask = leftMask;
00385 }
00386
00387 void StereoManager::getVisibilityMask(uint32 &outLeftMask, uint32 &outRightMask) const
00388 {
00389 outRightMask = mRightMask;
00390 outLeftMask = mLeftMask;
00391 }
00392
00393 void StereoManager::addRenderTargetDependency(RenderTarget *renderTarget)
00394 {
00395 if(mRenderTargetList.find(renderTarget) != mRenderTargetList.end())
00396 return;
00397 mRenderTargetList[renderTarget] = renderTarget->isAutoUpdated();
00398 renderTarget->setAutoUpdated(false);
00399 }
00400
00401 void StereoManager::removeRenderTargetDependency(RenderTarget *renderTarget)
00402 {
00403 if(mRenderTargetList.find(renderTarget) == mRenderTargetList.end())
00404 return;
00405 renderTarget->setAutoUpdated(mRenderTargetList[renderTarget]);
00406 mRenderTargetList.erase(renderTarget);
00407 }
00408
00409 void StereoManager::updateAllDependentRenderTargets(bool isLeftEye)
00410 {
00411 uint32 mask;
00412 if(isLeftEye)
00413 {
00414 mask = mLeftMask;
00415 }
00416 else
00417 {
00418 mask = mRightMask;
00419 }
00420
00421 RenderTargetList::iterator itarg, itargend;
00422 itargend = mRenderTargetList.end();
00423 for( itarg = mRenderTargetList.begin(); itarg != itargend; ++itarg )
00424 {
00425 RenderTarget *rt = itarg->first;
00426
00427 int n = rt->getNumViewports();
00428 std::vector<int> maskVector(n);
00429
00430 for(int i = 0; i<n ; ++i)
00431 {
00432 maskVector[i] = rt->getViewport(i)->getVisibilityMask();
00433 rt->getViewport(i)->setVisibilityMask(maskVector[i] & mask);
00434 }
00435
00436 rt->update();
00437
00438 for(int i = 0; i<n ; ++i)
00439 {
00440 rt->getViewport(i)->setVisibilityMask(maskVector[i]);
00441 }
00442 }
00443 }
00444
00445
00446 void StereoManager::setFocalLength(Real l)
00447 {
00448 if(l == std::numeric_limits<Real>::infinity())
00449 {
00450 setFocalLengthInfinite(true);
00451 }
00452 else
00453 {
00454 setFocalLengthInfinite(false);
00455
00456 Real old = mFocalLength;
00457 mFocalLength = l;
00458 if( mCamera )
00459 {
00460 mCamera->setFocalLength(mFocalLength);
00461 if(mIsFocalPlaneFixed)
00462 updateCamera(mFocalLength - old);
00463 else if(mDebugPlane)
00464 updateDebugPlane();
00465 }
00466 }
00467 }
00468
00469 Real StereoManager::getFocalLength(void) const
00470 {
00471 if(mFocalLengthInfinite)
00472 return std::numeric_limits<Real>::infinity();
00473 else
00474 return mFocalLength;
00475 }
00476
00477 void StereoManager::setFocalLengthInfinite(bool isInfinite)
00478 {
00479 mFocalLengthInfinite = isInfinite;
00480 if(isInfinite)
00481 mIsFocalPlaneFixed = false;
00482 }
00483
00484 void StereoManager::useScreenWidth(Real w)
00485 {
00486 mScreenWidth = w;
00487 mIsFocalPlaneFixed = true;
00488 if( mCamera )
00489 updateCamera(0);
00490 }
00491
00492 void StereoManager::updateCamera(Real delta)
00493 {
00494 mCamera->moveRelative(-delta * Vector3::UNIT_Z);
00495 Radian a = 2 * Math::ATan(mScreenWidth/(2 * mFocalLength * mCamera->getAspectRatio()));
00496 mCamera->setFOVy(a);
00497 }
00498
00499 void StereoManager::inverseStereo(bool inverse)
00500 {
00501 mIsInversed = inverse;
00502 mLeftCameraListener.mIsLeftEye = !mIsInversed;
00503 mRightCameraListener.mIsLeftEye = mIsInversed;
00504 }
00505
00506 void StereoManager::setCustomProjectonMatrices(bool enable, const Matrix4 &leftMatrix, const Matrix4 &rightMatrix)
00507 {
00508 mIsCustomProjection = enable;
00509 mLeftCustomProjection = leftMatrix;
00510 mRightCustomProjection = rightMatrix;
00511 }
00512
00513 void StereoManager::getCustomProjectonMatrices(bool &enabled, Matrix4 &leftMatrix, Matrix4 &rightMatrix) const
00514 {
00515 enabled = mIsCustomProjection;
00516 leftMatrix = mLeftCustomProjection;
00517 rightMatrix = mRightCustomProjection;
00518 }
00519
00520
00521 void StereoManager::enableDebugPlane(bool enable)
00522 {
00523 if(mDebugPlane)
00524 mDebugPlane->setVisible(enable);
00525 }
00526
00527 void StereoManager::toggleDebugPlane(void)
00528 {
00529 if(mDebugPlane)
00530 mDebugPlane->setVisible(!mDebugPlane->isVisible());
00531 }
00532
00533 void StereoManager::createDebugPlane(SceneManager *sceneMgr, const String &leftMaterialName, const String &rightMaterialName)
00534 {
00535 if(mDebugPlane)
00536 return;
00537
00538 mSceneMgr = sceneMgr;
00539 Plane screenPlane;
00540 screenPlane.normal = Vector3::UNIT_Z;
00541 MeshManager::getSingleton().createPlane("Stereo/Plane",
00542 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
00543 screenPlane,1,1,10,10);
00544 mDebugPlane = sceneMgr->createEntity( "Stereo/DebugPlane", "Stereo/Plane" );
00545
00546 if(leftMaterialName == "")
00547 {
00548 mLeftMaterialName = "Stereo/Wireframe";
00549 }
00550 else
00551 {
00552 mLeftMaterialName = leftMaterialName;
00553 }
00554
00555 if(rightMaterialName == "")
00556 {
00557 mRightMaterialName = "Stereo/Wireframe";
00558 }
00559 else
00560 {
00561 mRightMaterialName = rightMaterialName;
00562 }
00563
00564
00565 mDebugPlaneNode = static_cast<SceneNode*>(sceneMgr->getRootSceneNode()->createChild("Stereo/DebugPlaneNode"));
00566 mDebugPlaneNode->attachObject(mDebugPlane);
00567
00568 enableDebugPlane(true);
00569 updateDebugPlane();
00570 }
00571
00572 void StereoManager::destroyDebugPlane(void)
00573 {
00574 if(mDebugPlane)
00575 {
00576 SceneNode *parent = static_cast<SceneNode*>(mDebugPlaneNode->getParent());
00577 parent->removeAndDestroyChild("Stereo/DebugPlaneNode");
00578 mDebugPlaneNode = NULL;
00579 mSceneMgr->destroyEntity("Stereo/DebugPlane");
00580 mDebugPlane = NULL;
00581 MeshManager::getSingleton().remove("Stereo/Plane");
00582 }
00583 }
00584
00585 void StereoManager::updateDebugPlane(void)
00586 {
00587 if(mDebugPlaneNode && mCamera)
00588 {
00589 Real actualFocalLength = mFocalLengthInfinite ? mCamera->getFarClipDistance() * 0.99f : mFocalLength;
00590
00591 Vector3 pos = mCamera->getDerivedPosition();
00592 pos += mCamera->getDerivedDirection() * actualFocalLength;
00593 mDebugPlaneNode->setPosition(pos);
00594 mDebugPlaneNode->setOrientation(mCamera->getDerivedOrientation());
00595 Vector3 scale;
00596 Real height = actualFocalLength * Math::Tan(mCamera->getFOVy()/2)*2;
00597 scale.z = 1;
00598 scale.y = height;
00599 scale.x = height * mCamera->getAspectRatio();
00600 mDebugPlaneNode->setScale(scale);
00601 }
00602 }
00603
00604 void StereoManager::chooseDebugPlaneMaterial(bool isLeftEye)
00605 {
00606 if(mDebugPlane)
00607 {
00608 if(isLeftEye)
00609 mDebugPlane->setMaterialName(mLeftMaterialName);
00610 else
00611 mDebugPlane->setMaterialName(mRightMaterialName);
00612 }
00613 }
00614
00615
00616
00617 void StereoManager::saveConfig(const String &filename) const
00618 {
00619 std::ofstream of(filename.c_str());
00620 if (!of)
00621 OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create settings file.",
00622 "StereoManager::saveConfig");
00623
00624 of << "[Stereoscopy]" << std::endl;
00625 of << "# Available Modes: ";
00626
00627 const StereoModeList::const_iterator end = mAvailableModes.end();
00628 for(StereoModeList::const_iterator it = mAvailableModes.begin(); it != end; ++it)
00629 {
00630 of << it->second.mName << " ";
00631 }
00632 of << std::endl;
00633
00634 StereoModeList::const_iterator it = mAvailableModes.find(mStereoMode);
00635 if(it != mAvailableModes.end())
00636 of << "Stereo mode = " << it->second.mName << std::endl;
00637 else
00638 of << "Stereo mode = " << "NONE # wrong enum value, defaults to NONE" << std::endl;
00639
00640 of << "Eyes spacing = " << mEyesSpacing << std::endl;
00641
00642 of << "# Set to inf for parallel frustrum stereo." << std::endl;
00643 if(mFocalLengthInfinite)
00644 of << "Focal length = " << "inf" << std::endl;
00645 else
00646 of << "Focal length = " << mFocalLength << std::endl;
00647
00648 of << "Inverse stereo = " << (mIsInversed ? "true" : "false") << std::endl;
00649
00650 of << std::endl << "# For advanced use. See StereoManager.h for details." << std::endl;
00651 of << "Fixed screen = " << (mIsFocalPlaneFixed ? "true" : "false") << std::endl;
00652 of << "Screen width = " << mScreenWidth << std::endl;
00653
00654 of.close();
00655 }
00656
00657 StereoManager::StereoMode StereoManager::loadConfig(const String &filename)
00658 {
00659 ConfigFile cf;
00660 cf.load(filename.c_str());
00661
00662 StereoMode mode;
00663
00664 const String &modeName = cf.getSetting("Stereo mode","Stereoscopy");
00665 const StereoModeList::const_iterator end = mAvailableModes.end();
00666 StereoModeList::iterator it;
00667 for(it = mAvailableModes.begin(); it != end; ++it)
00668 {
00669 if(it->second.mName == modeName)
00670 {
00671 mode = it->first;
00672 break;
00673 }
00674 }
00675 if(it == mAvailableModes.end())
00676 mode = SM_NONE;
00677
00678 fixFocalPlanePos(StringConverter::parseBool(cf.getSetting("Fixed screen","Stereoscopy")));
00679
00680 if(cf.getSetting("Focal length","Stereoscopy") == "inf")
00681 mFocalLengthInfinite = true;
00682 else
00683 setFocalLength(StringConverter::parseReal(cf.getSetting("Focal length","Stereoscopy")));
00684
00685 setEyesSpacing(StringConverter::parseReal(cf.getSetting("Eyes spacing","Stereoscopy")));
00686 setScreenWidth(StringConverter::parseReal(cf.getSetting("Screen width","Stereoscopy")));
00687 inverseStereo(StringConverter::parseBool(cf.getSetting("Inverse stereo","Stereoscopy")));
00688
00689 return mode;
00690 }
00691