[原][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) 

兩個函數,就能改變左右眼立體視覺效果了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM