[原][osg]解析osg自带左右眼立体成像功能的使用方式
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)
两个函数,就能改变左右眼立体视觉效果了。