osg::DisplaySettings::instance()->setStereo(true); osg::DisplaySettings::instance()->setStereoMode(osg::DisplaySettings::HORIZONTAL_SPLIT);
打開osg自帶的左右眼立體函數,可以直接將現有程序變成左右分屏的視圖。
但是默認的視錐關系比較誇張,我想要修改內部參數,因此,在這分析osg此功能的內置算法。
查看關鍵參數:
在DisplaySettings其默認設置函數中,osg給了幾個對應參數默認數值:
void DisplaySettings::setDefaults() { _stereo = false; _stereoMode = ANAGLYPHIC; _eyeSeparation = 0.05f; _screenWidth = 0.325f; _screenHeight = 0.26f; _screenDistance = 0.5f; 。。。。。。 }
也就是說默認 _stereo 立體參數是關閉的,后面的立體相關的數值也是用不到的,但是一旦打開,就用這個幾個默認數值。
后面就查看這幾個數值在哪里使用,明確功能的意義,再改變調試數值看看帶來的變化。
找了一圈發現是View里面的updateSlave函數使用的以上數值:
void View::StereoSlaveCallback::updateSlave(osg::View& view, osg::View::Slave& slave) { osg::Camera* camera = slave._camera.get(); osgViewer::View* viewer_view = dynamic_cast<osgViewer::View*>(&view); if (_ds.valid() && camera && viewer_view) { // inherit any settings applied to the master Camera. camera->inheritCullSettings(*(view.getCamera()), camera->getInheritanceMask()); if (_eyeScale<0.0) { camera->setCullMask(camera->getCullMaskLeft()); } else { camera->setCullMask(camera->getCullMaskRight()); } // set projection matrix if (_eyeScale<0.0) { camera->setProjectionMatrix(_ds->computeLeftEyeProjectionImplementation(view.getCamera()->getProjectionMatrix())); } else { camera->setProjectionMatrix(_ds->computeRightEyeProjectionImplementation(view.getCamera()->getProjectionMatrix())); } double sd = _ds->getScreenDistance(); double fusionDistance = sd; switch(viewer_view->getFusionDistanceMode()) { case(osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE): fusionDistance = viewer_view->getFusionDistanceValue(); break; case(osgUtil::SceneView::PROPORTIONAL_TO_SCREEN_DISTANCE): fusionDistance *= viewer_view->getFusionDistanceValue(); break; } double eyeScale = osg::absolute(_eyeScale) * (fusionDistance/sd); if (_eyeScale<0.0) { camera->setViewMatrix(_ds->computeLeftEyeViewImplementation(view.getCamera()->getViewMatrix(), eyeScale)); } else { camera->setViewMatrix(_ds->computeRightEyeViewImplementation(view.getCamera()->getViewMatrix(), eyeScale)); } } else { slave.updateSlaveImplementation(view); } }
主要調用是DisplaySettings里面的四個函數:
/** helper function for computing the left eye projection matrix.*/ virtual osg::Matrixd computeLeftEyeProjectionImplementation(const osg::Matrixd& projection) const; /** helper function for computing the left eye view matrix.*/ virtual osg::Matrixd computeLeftEyeViewImplementation(const osg::Matrixd& view, double eyeSeperationScale=1.0) const; /** helper function for computing the right eye view matrix.*/ virtual osg::Matrixd computeRightEyeProjectionImplementation(const osg::Matrixd& projection) const; /** helper function for computing the right eye view matrix.*/ virtual osg::Matrixd computeRightEyeViewImplementation(const osg::Matrixd& view, double eyeSeperationScale=1.0) const;
也就是通過改變左右眼點的 1.投影矩陣 2.視圖矩陣 來改變左右立體投影變化。
下面,我們仔細分析一個單眼:左眼的 投影輔助計算矩陣 和 視圖輔助計算矩陣
左眼投影矩陣輔助算法:
// Helper funciotns for computing projection and view matrices of left and right eyes // 輔助函數,用於計算左眼和右眼的投影和視圖矩陣 osg::Matrixd DisplaySettings::computeLeftEyeProjectionImplementation(const osg::Matrixd& projection) const { double iod = getEyeSeparation(); double sd = getScreenDistance(); double scale_x = 1.0;//左右分開 二選一 double scale_y = 1.0;//上下分開 二選一 if (getSplitStereoAutoAdjustAspectRatio()) { switch(getStereoMode()) { case(HORIZONTAL_SPLIT): scale_x = 2.0; break; case(VERTICAL_SPLIT): scale_y = 2.0; break; default: break; } } if (getDisplayType()==HEAD_MOUNTED_DISPLAY) { // head mounted display has the same projection matrix for left and right eyes. // 頭戴式顯示器的左右眼投影矩陣相同 return osg::Matrixd::scale(scale_x,scale_y,1.0) * projection; } else { // all other display types assume working like a projected power wall // need to shjear projection matrix to account for asymetric frustum due to eye offset. // 所有其他顯示類型都假定像投影電源牆一樣工作-需要晃動投影矩陣,以解決由於眼睛偏移而導致的不對稱視錐 return osg::Matrixd(1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, iod/(2.0*sd),0.0,1.0,0.0, 0.0,0.0,0.0,1.0) * osg::Matrixd::scale(scale_x,scale_y,1.0) * projection; } }
控制投影矩陣的主要是兩點:眼睛分離量 _eyeSeparation = 0.05f; 和 離屏距離:_screenDistance = 0.5f;
右眼視圖投影輔助算法:
osg::Matrixd DisplaySettings::computeLeftEyeViewImplementation(const osg::Matrixd& view, double eyeSeperationScale) const { double iod = getEyeSeparation(); double es = 0.5f*iod*eyeSeperationScale; return view * osg::Matrixd(1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, es,0.0,0.0,1.0); }
控制視圖矩陣的,主要是: 眼睛分離量 _eyeSeparation = 0.05f;
所以,我只需要改變:
void setEyeSeparation(float eyeSeparation)
void setScreenDistance(float distance)
兩個函數,就能改變左右眼立體視覺效果了。