zoukankan      html  css  js  c++  java
  • [原][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) 

    两个函数,就能改变左右眼立体视觉效果了。

  • 相关阅读:
    Golang 学习权威网站
    iOS多线程GCD的使用
    iOS 开发 nonatomic 和 atomic
    iOS证书配置与管理
    iOS pthread
    NSTimer 不工作 不调用方法
    iOS开发者学习Flutter
    Xcode如何打开Archives打包界面?
    iOS 12.1 跳转页面时 tabBar闪动
    支付宝
  • 原文地址:https://www.cnblogs.com/lyggqm/p/12530171.html
Copyright © 2011-2022 走看看