查看: 1651|回复: 17

多个投影仪显示同一个场景,两侧投影仪显示的场景有明显的横向拉伸变形!什么原因呢?

[复制链接]

该用户从未签到

发表于 2012-10-30 19:38:27 | 显示全部楼层 |阅读模式
问题如题:
    我们用分屏器接上三个投影仪,然后用来显示我们所渲染的场景(一个大场景),在程序中没有对三屏显示做任何操作!现在出现的问题是:两侧投影仪所显示出来的场景会存在明显的横向拉伸。有种放大了的感觉!不知道这个问题有没有谁遇到过类似的情况?
    我们在程序中只用了一个主相机来渲染,没有设置别的相机!我们设置主相机的一些参数是:viewer->getCamera()->setProjectionMatrixAsPerspective(50.0f, 1.25, 1, 500.0);如果将50.0f改成20的话,两边的投影仪没有了拉伸的效果了,但是会影响视野,视野范围太窄了,肯定不适合!不知道还有没有别的解决方案???
    不知道在程序中用多相机来对场景进行渲染会怎么样?多个相机能渲染同一个大的场景么?谢谢各位指教!

该用户从未签到

发表于 2012-10-31 07:43:08 | 显示全部楼层
是不是投影矩阵设置的问题,给出具体的效果。
多相机渲染 slavecamera就可以了  如果实在多个机器上 自己同步

该用户从未签到

 楼主| 发表于 2012-10-31 09:54:33 | 显示全部楼层
liuzhiyu123 发表于 2012-10-31 07:43
是不是投影矩阵设置的问题,给出具体的效果。
多相机渲染 slavecamera就可以了  如果实在多个机器上 自己同 ...

显示图: 1.jpg ,左边的房子是处于中间的投影仪显示出来的,看着是正常的。但是右边的房子是处于右边的投影仪显示出来的,感觉到明显的拉伸变形!

2.jpg ,将上图中左边的房子通过相机移到左边的投影仪进行显示时,也会感觉到明显的拉伸变形!包括树木也是,中间的投影仪显示出来的树木大小比较正常,一旦在两边的投影仪显示,树木明显放大了的感觉!

应该是投影矩阵的问题,因为在程序中没有考虑到用三个投影仪去显示,所以没有对投影矩阵进行什么计算。我们用三个投影仪显示的意思是:一台主机,通过分屏器接上三台投影仪,三台投影仪分别投影到对应的幕布上,现在是中间的投影仪显示的场景很正常,两边的投影仪显示的场景有明显的拉伸变形。程序中只有一个主相机渲染场景,没有设置任何的从属相机。

该用户从未签到

发表于 2012-11-5 09:38:40 | 显示全部楼层
OSG默认是会根据窗口尺寸自动改变投影矩阵的,您需要强制setProjectionResizePolicy为FIXED然后调整投影矩阵的aspectRatio来符合真正的总体屏幕尺寸

该用户从未签到

 楼主| 发表于 2012-11-5 13:29:38 | 显示全部楼层
array 发表于 2012-11-5 09:38
OSG默认是会根据窗口尺寸自动改变投影矩阵的,您需要强制setProjectionResizePolicy为FIXED然后调整投影矩阵 ...

嗯,谢谢array大哥,我先试试!非常感谢!osg真的是博大精深啊,这个函数以前不知道哇!

该用户从未签到

 楼主| 发表于 2012-11-5 17:28:32 | 显示全部楼层
array 发表于 2012-11-5 09:38
OSG默认是会根据窗口尺寸自动改变投影矩阵的,您需要强制setProjectionResizePolicy为FIXED然后调整投影矩阵 ...

          array大哥,我按照您的指点去设置了一下,现在是没有了拉伸形变,但是就存在另外的一个问题:相机的视野变窄了许多。以前感觉是站着看场景,现在就感觉是趴着看场景。现在就只能重新去写一个相机的算法,但重写相机算法后我们的程序很多地方都要修改,工作量太庞大!不改的话相机的视野确实太窄太低了!本来之前没想着用三个投影仪来显示场景的。
      我试过用三个相机来渲染场景,这样似乎不会存在这个问题了。但是,我们的程序中存在CEGUI界面,一旦用三个相机以后,因为需要设置图形上下文,结果界面就显示不出来了,不知道这个是什么原因!还望array大哥指教!
一些代码:
        //得到窗口的图形环境
        osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
        if (!wsi)
        {
                osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
        }
        unsigned int tileWidth, tileHeight;
        wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), tileWidth ,tileHeight);

        //初始化主相机图形环境
        osg::ref_ptr<osg::GraphicsContext::Traits> mastertrait = new osg::GraphicsContext::Traits();
        //osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData( GetSafeHwnd() );
        mastertrait->x = 0;
        mastertrait->y = 0;
        mastertrait->width = tileWidth;
        mastertrait->height = tileHeight;
        mastertrait->windowDecoration = false;
        mastertrait->doubleBuffer = false;
        mastertrait->useCursor = true;
        mastertrait->setInheritedWindowPixelFormat = true;
        osg:isplaySettings *ds = osg::DisplaySettings::instance();
        mastertrait->alpha = ds->getMinimumNumAlphaBits();
        mastertrait->stencil = ds->getMinimumNumStencilBits();
        mastertrait->sampleBuffers = ds->getMultiSamples();
        mastertrait->samples = ds->getNumMultiSamples();

        osg::ref_ptr<osg::GraphicsContext> mastergc = osg::GraphicsContext::createGraphicsContext(mastertrait.get());
        osg::ref_ptr<osg::Camera> masterCamera = viewer->getCamera();
        masterCamera->setGraphicsContext(mastergc.get());
        masterCamera->setViewport(new osg::Viewport(0,0,mastertrait->width,mastertrait->height));

        osg::ref_ptr<osgViewer::GraphicsWindowWin32> gcwin32=dynamic_cast<osgViewer::GraphicsWindowWin32*>(masterCamera->getGraphicsContext());
        //root->addEventCallback(new TestMinimizeHandler(gcwin32));


        //UI
        viewer->realize();
        masterCamera->getGraphicsContext()->makeCurrent();
        //root->addChild(CreateBackground());                                                        //创建背景图片
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        osg::ref_ptr<CEGUIDrawable> cd = new CEGUIDrawable(sceneMgr,KeySoundNode,viewer,ClickSoundNode,gcwin32/*,printer.get()*/);//界面节点
        geode->addDrawable(cd.get());
        cd->Init();//初始化事件处理函数pinfo
        root->addChild(geode.get());                                //初始化UI
        root->addEventCallback(new CEGUIUpdateCallback(geode,cd,sceneMgr,physicsMgr));
        geode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
        //root->getOrCreateStateSet()->setRenderBinDetails(10, "DepthSortedBin");


在这个里边我只用了一个主相机,但是重新设置它的图形上下文,结果界面就没有了!不设置图形上下文界面就不会有问题!

该用户从未签到

发表于 2012-11-6 00:22:38 | 显示全部楼层
buptronin 发表于 2012-10-31 09:54
显示图:,左边的房子是处于中间的投影仪显示出来的,看着是正常的。但是右边的房子是处于右边的投影仪显 ...

一个透视投影Camera在视角大了以后,投影到一个平面上就是这样的。要设置三个Camera,投影到不同的平面上才行。

该用户从未签到

 楼主| 发表于 2012-11-6 09:45:28 | 显示全部楼层
smash 发表于 2012-11-6 00:22
一个透视投影Camera在视角大了以后,投影到一个平面上就是这样的。要设置三个Camera,投影到不同的平面上 ...

嗯,是的!修改投影矩阵的一些参数确实可以解决变形问题,但是相机的视角好像较之前低了许多!我用过三个相机去渲染,但是用三个相机以后界面就加不上去了,因为三个相机的话必须各自设置各自的图形上下文,不知道是不是这个影响界面的显示!

该用户从未签到

发表于 2012-11-6 16:03:36 | 显示全部楼层
buptronin 发表于 2012-11-6 09:45
嗯,是的!修改投影矩阵的一些参数确实可以解决变形问题,但是相机的视角好像较之前低了许多!我用过三个 ...

那可能要设置3个HUDCamera,对应相同的场景,把投影矩阵设的连起来。

该用户从未签到

发表于 2012-11-9 10:07:29 | 显示全部楼层
视野窄可以通过改变投影矩阵来改善啊,说白了就是fov
至于cegui和您的context之间有什么问题,这个只能看您自己的具体结合方案了,要用起来肯定不会有问题

该用户从未签到

 楼主| 发表于 2012-11-18 15:57:17 | 显示全部楼层
smash 发表于 2012-11-6 00:22
一个透视投影Camera在视角大了以后,投影到一个平面上就是这样的。要设置三个Camera,投影到不同的平面上 ...

您好!有个问题想请教一下,我现在用三个相机去渲染一个完整的场景。三个相机投影到不同的平面上。我外边接了三个显示器。中间的显示器是主相机的显示窗口,两边的显示器是两个从相机的显示窗口。这样设置完了后程序执行出来,两侧的显示器显示的场景还是有很大的拉伸,跟之前只有一个相机的情况是一样的。不知道是不是那两个从相机得设置不同的投影矩阵?我的主相机的一些参数是这样设置的,
         viewer->getCamera()->setProjectionResizePolicy(osg::Camera:rojectionResizePolicy::FIXED);       
        viewer->getCamera()->getProjectionMatrixAsPerspective( fov,aspectRatio,nearPlane,farPlane);
        viewer->getCamera()->setProjectionMatrixAsPerspective(50.0f, aspectRatio, 1, 500.0);
是不是从相机也要设置相关的投影矩阵呢?设置从相机的投影矩阵的话,这个矩阵应该怎么设置?还请指点啊!

该用户从未签到

发表于 2012-11-18 22:24:12 | 显示全部楼层
投影矩阵显然是不一样的,主相机投影平面是你的主屏幕,如果两个从相机的视点跟主相机重合,投影平面也还是和主相机在同一个平面的话,就跟一个相机一样效果了,只能是视点做一个偏移,或者是投影平面偏转一定角度。

该用户从未签到

 楼主| 发表于 2012-11-19 08:45:18 | 显示全部楼层
smash 发表于 2012-11-18 22:24
投影矩阵显然是不一样的,主相机投影平面是你的主屏幕,如果两个从相机的视点跟主相机重合,投影平面也还是 ...

嗯,谢谢!两个从相机是设置了一定的偏移矩阵的!这样三个相机所渲染出来的场景就是一个完整的场景,没有重合的地方的!但是现在的问题是,两个从相机渲染的场景还是有拉伸现象,跟之前用一个相机的情况一样。后来我用setProjectionMatrixAsPerspective( fov,aspectRatio,nearPlane,farPlane);设置了一下相机的透视投影矩阵,感觉还是差不多一样的效果。不知道这三个相机除了从相机要设置正确的偏移矩阵以外,还得设置什么样的投影矩阵呢?有没有公式可以计算?

该用户从未签到

发表于 2012-11-19 14:15:16 | 显示全部楼层
buptronin 发表于 2012-11-19 08:45
嗯,谢谢!两个从相机是设置了一定的偏移矩阵的!这样三个相机所渲染出来的场景就是一个完整的场景,没有 ...

这种情况应该是调整一下ViewPort,把三个图像拼接起来。不用改ProjectionMatrix。

该用户从未签到

 楼主| 发表于 2012-11-22 15:14:47 | 显示全部楼层
smash 发表于 2012-11-19 14:15
这种情况应该是调整一下ViewPort,把三个图像拼接起来。不用改ProjectionMatrix。

还是不行啊!
代码如下:
//创建从相机,设置视口
osg::Camera* createCamera(int x, int y, int w, int h)
{
        osg::ref_ptr<osg::GraphicsContext::Traits> trait = new osg::GraphicsContext::Traits();
        trait->x = x;
        trait->y = y;
        trait->width = w;
        trait->height = h;
        trait->windowDecoration = false;
        trait->doubleBuffer = true;

        osg:isplaySettings *ds = osg::DisplaySettings::instance();
        trait->alpha = ds->getMinimumNumAlphaBits();
        trait->stencil = ds->getMinimumNumStencilBits();
        trait->sampleBuffers = ds->getMultiSamples();
        trait->samples = ds->getNumMultiSamples();

        osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(trait.get());
        osg::ref_ptr<osg::Camera> camera = new osg::Camera();
        camera->setGraphicsContext(gc.get());
        camera->setViewport(new osg::Viewport(0,0,w,h));
        //camera->setReferenceFrame(osg::Camera::ReferenceFrame::ABSOLUTE_RF_INHERIT_VIEWPOINT);

        double fov;
        double aspectRatio;
        double nearPlane;
        double farPlane;

        double newAspectRatio;
        camera->setProjectionResizePolicy(osg::Camera:rojectionResizePolicy::FIXED);
        //换取对称视景个参数并显示,每个屏幕都有对应的ratio,所以必须先get在set
        camera->getProjectionMatrixAsPerspective( fov,aspectRatio,nearPlane,farPlane);
        newAspectRatio = double(w)/double(h);
        //double aspectRatiochange = newAspectRatio/aspectRatio;
        //设置视景参数,将yz平面视野角度设为50°
        camera->setProjectionMatrixAsPerspective(60.0f, aspectRatio, 1, 500.0);

        return camera.release();
}

//主相机设置

        //得到窗口的图形环境
        osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
        if (!wsi)
        {
                osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
        }
        unsigned int tileWidth, tileHeight;
        wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), tileWidth ,tileHeight);



        //初始化主相机图形环境
        osg::ref_ptr<osg::GraphicsContext::Traits> mastertrait = new osg::GraphicsContext::Traits();
        mastertrait->x = tileWidth/3;
        mastertrait->y = 0;
        mastertrait->width = tileWidth/3;
        mastertrait->height = tileHeight;
        mastertrait->windowDecoration = false;
        mastertrait->doubleBuffer = true;
        mastertrait->useCursor = false;
        osg::DisplaySettings *ds = osg::DisplaySettings::instance();
        mastertrait->alpha = ds->getMinimumNumAlphaBits();
        mastertrait->stencil = ds->getMinimumNumStencilBits();
        mastertrait->sampleBuffers = ds->getMultiSamples();
        mastertrait->samples = ds->getNumMultiSamples();

        osg::ref_ptr<osg::GraphicsContext> mastergc = osg::GraphicsContext::createGraphicsContext(mastertrait.get());
        osg::ref_ptr<osg::Camera> masterCamera = new osg::Camera();
        masterCamera = viewer->getCamera();
        masterCamera->setGraphicsContext(mastergc.get());
        masterCamera->setViewport(new osg::Viewport(0,0,mastertrait->width,mastertrait->height));
               //添加从相机,设置从相机的投影矩阵的偏移矩阵,设置好各个从相机的视口
                viewer->addSlave(createCamera(0,0,tileWidth/3,tileHeight),osg::Matrixd::translate(2,0.0,0.0),osg::Matrixd());
        viewer->addSlave(createCamera(2*tileWidth/3,0,tileWidth/3,tileHeight),osg::Matrixd::translate(-2,0.0,0.0),osg::Matrixd());


              viewer->getCamera()->setProjectionResizePolicy(osg::Camera::ProjectionResizePolicy::FIXED);
       
        viewer->getCamera()->getProjectionMatrixAsPerspective( fovy,aspectRatio,nearPlane,farPlane);
        newAspectRatio = double(tileWidth)/double(tileHeight);
        double aspectRatiochange = newAspectRatio/aspectRatio;
       
        viewer->getCamera()->setProjectionMatrixAsPerspective(60.0f, aspectRatio, 1, 500.0);
        if(aspectRatiochange!=1.0)
        {
                viewer->getCamera()->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatiochange,1.0,1.0);
        }

需求是:
主机利用分屏器外接了三个投影仪,每个投影仪都有对应的屏幕。这样做主需要是想用三个投影仪显示一个大的场景。程序中使用的是透视投影,设置的fovy是60度,宽高比为屏幕的宽高比。可是,显示出来以后两侧的投影仪存在很大的变形,感觉被横向拉伸。后来看了array的osgcookbook里边的威力强的例子,想到用三个相机(一个主相机,两个从相机,主相机对应中间的屏幕,从相机对应的是两边的屏幕)来渲染同一个场景,然后三个相机设置不同的投影矩阵。设置的代码如上,但是显示出来的结果还是一样。中间的主相机对应的屏幕的场景没有拉伸,两边的从相机对应的场景渲染出来有很大的拉伸,不知道这个是不是正常的,有没有什么解决方案,我用三个相机来渲染为什么还是不行呢?感觉您之前接触过,还望多指教。两个从相机的视口还有偏移矩阵我都设置好了的,三个相机刚好组成了同一场景,没有什么重叠的地方,就是两侧的从相机渲染出来的场景有横向拉伸。另外还有一个问题,用从相机渲染一个大的场景,为什么会卡呢??

该用户从未签到

 楼主| 发表于 2012-11-22 17:36:10 | 显示全部楼层
恳请array大哥等高手出山指教啊!!!!

该用户从未签到

发表于 2012-11-27 10:39:53 | 显示全部楼层
您可以参考osgposter来做多视图的投影矩阵设置,这个程序的作用就是把场景做成NxM的超大海报输出。至于您目前设置的这个投影矩阵offset:
  1. viewer->addSlave(createCamera(0,0,tileWidth/3,tileHeight),osg::Matrixd::translate(2,0.0,0.0),osg::Matrixd());
复制代码
我只能说肯定是不对的,您把它带入到透视投影的公式里就知道了,结果并不是您想象的那样

该用户从未签到

 楼主| 发表于 2012-11-27 10:47:34 | 显示全部楼层
array 发表于 2012-11-27 10:39
您可以参考osgposter来做多视图的投影矩阵设置,这个程序的作用就是把场景做成NxM的超大海报输出。至于您目 ...

谢谢array大哥!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表