查看: 4329|回复: 20

单视图多相机投影矩阵不一致

[复制链接]

该用户从未签到

发表于 2011-7-22 21:31:34 | 显示全部楼层 |阅读模式
打算采用采用单视图多相机模拟两个屏幕通道,一个是正视,另一个是向下45度,得到的效果明显有问题。代码如下:

  1.   osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
  2.   osg::GraphicsContext::ScreenIdentifier si;
  3.   si.readDISPLAY();
  4.   unsigned int width, height;
  5.   wsi->getScreenResolution(si, width, height);
  6.   osgViewer::View* view = new osgViewer::View;
  7.   //投影矩阵
  8.   osg::Matrixd projectOffset;
  9.   //视图矩阵
  10.   osg::Matrixd viewOffset;
  11.   //正面视口
  12.   view->addSlave(createCamera(0,0,width,height/2),projectOffset,viewOffset);
  13.   //侧面视口
  14.   viewOffset=osg::Matrixd::rotate(osg::Quat(osg::DegreesToRadians(45.0),osg::Vec3(1.0,0.0,0.0)));
  15.   view->addSlave(createCamera(0,height/2,width,height),projectOffset,viewOffset);

  16.   view->setSceneData(mRoot.get());

  17.   cViewer->addView(view);
复制代码

frustum.jpg
白色视锥体

得到的两个通道效果如下,应该是在两个屏幕上,这里为了调试放在一个屏幕上,大家注意红色标注的地方,结果正确吗?
Scene.jpg
上下两个通道

该用户从未签到

发表于 2011-7-23 10:19:55 | 显示全部楼层
应该是createCamera代码,对相机位置设置的问题。 可能平移、旋转的次序有问题。

该用户从未签到

 楼主| 发表于 2011-7-23 16:18:37 | 显示全部楼层
创建相机那个函数没有对相机位置进行设置,对相机位置的设置在一楼的帖子里了。
  1. //创建指定尺寸相机
  2. osg::Camera* OSGCore::createCamera(int x,int y,int w,int h)
  3. {
  4.         osg::ref_ptr<osg::GraphicsContext::Traits> traits=new osg::GraphicsContext::Traits();
  5.         traits->windowDecoration=false;
  6.         traits->x=x;
  7.         traits->y=y;
  8.         traits->width=w;
  9.         traits->height=h;
  10.         traits->doubleBuffer=true;

  11.         osg::DisplaySettings* ds=osg::DisplaySettings::instance();
  12.         traits->alpha=ds->getMinimumNumAlphaBits();
  13.         traits->stencil=ds->getMinimumNumStencilBits();
  14.         traits->sampleBuffers=ds->getMultiSamples();
  15.         traits->samples=ds->getNumMultiSamples();

  16.         osg::ref_ptr<osg::GraphicsContext> gc=osg::GraphicsContext::createGraphicsContext(traits.get());
  17.         osg::ref_ptr<osg::Camera> camera=new osg::Camera();
  18.         camera->setGraphicsContext(gc.get());
  19.         camera->setViewport(new osg::Viewport(0,0,w,h));

  20.         return camera.release();
  21. }

复制代码
另外,在创建相机时对其投影矩阵的设置,为什么程序运行过程中会不断改变,我的理解应该是视图矩阵在变。如果投影矩阵不断改变肯定会导致结果不对。

该用户从未签到

发表于 2011-7-23 18:01:35 | 显示全部楼层
你这个要是能对齐那才见鬼呢,建议补补基本的计算机图形学概念。
你这两个相机的投影面根本就不是一个平面怎会对齐?


没有坚实基础就使用这些成人玩具,到头来一场空。
osg这种东西简单几句就出效果,致使很多新手信心无限膨胀,从而忽略了基本概念的学习。
你既然发现了投影矩阵在变,为什么不看看投影矩阵是怎么计算的,这些最基本的东西计算机图形学的教材里面都有,为什么不看?

该用户从未签到

发表于 2011-7-23 18:07:42 | 显示全部楼层
你要面临的问题比你想象的要复杂的多。你这种做法是肯定不会成功的。

该用户从未签到

发表于 2011-7-23 18:13:27 | 显示全部楼层
OpenGL里普通的投影方式要求视轴与投影面垂直,而面对你的问题,视轴是不能和投影面垂直的,所以需要你自己计算投影矩阵,这个不是一个简单的问题。OSG好像是直接支持的,不过不是你这种做法,osg替用户做了很多,同时需要用户理解最起码的概念。

该用户从未签到

 楼主| 发表于 2011-7-23 22:10:05 | 显示全部楼层
你这个要是能对齐那才见鬼呢,建议补补基本的计算机图形学概念。
你这两个相机的投影面根本就不是一个平面 ...
sky11811 发表于 2011-7-23 18:01


首先,谢谢您对本帖的关心。
关于投影矩阵的计算我看过,正交不用讲,透视有两种计算方式:一是根据视锥体的6个顶点确定;二是根据fovy,aspectRatio,near,far来确定。不过哪种方式原理都是构造一个棱台,世界坐标经过MV变换,如果在这个棱台中则显示,否则裁减掉。那斜视锥体也是同一个道理。计算机图形学确实学的不够扎实,非常不好意思。
两个相机不在一个平面,同一条线经过投影变化就不是一条直线吗?我觉得这个问题没有论证和实验过,而这正是我发这个帖子要和大家讨论的。
OSG中投影矩阵不断的变化的原因我正在看源码分析,只是希望如果有人做过或者知道可以提示下,省的走弯路。
至于您说OSG是一个成人玩具,不知道是贬低我呢,还是抬高自己。

该用户从未签到

发表于 2011-7-23 23:48:10 | 显示全部楼层
本帖最后由 sky11811 于 2011-7-24 00:14 编辑

我需要再仔细看看你的代码。

该用户从未签到

发表于 2011-7-23 23:55:00 | 显示全部楼层
这种低层问题最好还是用OpenGL来做实验吧,这样有助于深入的理解问题的本质。

该用户从未签到

发表于 2011-7-24 00:13:32 | 显示全部楼层
仔细看了下你的代码,你的意图我基本明白了。
现在我直观的给你讲为什么拼不上,原因在于你用的是透视投影,物体的远近会影响最终它在屏幕的像素位置。
你的正视相机的bottom面没有和你的斜向下45度相机的top面重合,这导致拼接点离两个相机的距离不同,所以拼不上。
我看你在场景里画了一些竖线,你要是在正中间画一条,那么这一条就可以在你现在的情况下拼上。
不知道你明白没有。

该用户从未签到

发表于 2011-7-24 00:20:14 | 显示全部楼层
所谓正中间画一条竖线是指,这条竖线和你的两个相机的视轴相交。

该用户从未签到

 楼主| 发表于 2011-7-24 14:52:21 | 显示全部楼层
基本明白了,昨晚回去我也思考了很久,位于两个投影面中心的直线可以重合。
near投影面的大小不同,因此偏离中心的直线则不会重合,多谢您的提示。

该用户从未签到

发表于 2011-7-25 10:03:45 | 显示全部楼层
near投影面的大小不同,因此偏离中心的直线则不会重合
湖面之舟 发表于 2011-7-24 14:52



    我想你还是没有正确理解,如果两个相机投影矩阵相同,所谓的near投影面大小不同是不成立的。 楼上那位讲解的原因是,你画的黑线在两个屏幕接触边界处的点并不是线上的同一点,所以不可能重合

该用户从未签到

发表于 2011-7-26 20:57:52 | 显示全部楼层
楼上也是行家,楼主基本功实在是不敢恭维,这么久还是不明白,“near投影面的大小不同,因此偏离中心的直线则不会重合”,这样的说辞让人。。。。。。

该用户从未签到

 楼主| 发表于 2011-7-27 17:53:32 | 显示全部楼层
我想你还是没有正确理解,如果两个相机投影矩阵相同,所谓的near投影面大小不同是不成立的。 楼上 ...
indif 发表于 2011-7-25 10:03

投影矩阵相同,那么left,right,near,far都相同。我帖子里面好像没有讲投影矩阵相同,近裁减面不同。
我的意思是给不同的相机设置相同的投影矩阵参数,结果运行过程中打印出来的实际参数不一样。代码比如:
  1. osg::Matrixd viewOffset;
  2. viewOffset=osg::Matrix::translate(osg::Vec3(0.0,0.0,-42));

  3. osgViewer::View* view = new osgViewer::View;

  4. osg::Camera* camera=createCamera(x,y,w,h);
  5. //设置观察矩阵方向
  6. osg::Matrix mv=view->getCamera()->getViewMatrix();
  7. camera->setViewMatrix(mv*viewOffset);
  8. //设置投影矩阵
  9. camera->setProjectionMatrixAsFrustum(left,right,bottom,top,zNear,zFar);

  10. view->setCamera(camera);
复制代码

其中
left=-0.7
right=0.7
bottom=-0.685
top=0.08795
near=0.83623
far=10000

而实际上通过如下代码打印出的视锥体参数:
  1. double fovy,aspectRatio,zNear,zFar;

  2. std::cout<<"viewMater:"<<std::endl;
  3. cViewer->getView(0)->getCamera()->getProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFar);
  4. std::cout<<"fovy:"<<fovy<<";aspectRatio:"<<aspectRatio<<";zNear:"<<zNear<<";zFar:"<<zFar<<std::endl;
复制代码

打印结果是fovy=45.32,aspectRatio=1.81,zNear=0.121,zFar=246.84。
可能我对OSG中master相机和slave相机之间的关系理解的不是特别清楚。

对不同的相机设置相同的near,实际二者不同,如有可能,您能解释下为什么?

该用户从未签到

 楼主| 发表于 2011-7-27 18:11:24 | 显示全部楼层
楼上也是行家,楼主基本功实在是不敢恭维,这么久还是不明白,“near投影面的大小不同,因此偏离中心的直线 ...
sky11811 发表于 2011-7-26 20:57


可能是我帖子一开始就没有表达清楚我的意思。
其实本意是想说明经过相同的投影变换,为什么同一物体的几何拓朴关系变了,而不是说上下通道的两个点是否对齐。那探究这个问题的过程中,有发觉对于OSG的相机及投影变换掌握的不够透彻,才由此一问。
下面用一幅图来说明我的意思:
project.jpg
如果两个投影矩阵不同(如帖子中讨论的大小),但都是对称型视锥体,那么位于对称中心的直线任何情况下仍然为直线,不知道您同意否?
反之,偏离中心的直线则会上下通道不对其。
另外,您说这种情况很复杂,没我想的那么简单,其实我倒觉得没您想的那么复杂。用非对称的视锥体应该可以满足我的要求。

您能否指教下OSG中用当view中没用手工设置相机前,用setCamera(camera);和addsalve(camera,projOffset,viewOffset);两种方法添加的相机有什么不一样?
当然看您是否有耐心和时间,多谢

该用户从未签到

发表于 2011-7-27 19:21:47 | 显示全部楼层
这种东西例子里就带的有,两个窗口通过偏移投影菊阵.

该用户从未签到

发表于 2011-7-27 20:41:00 | 显示全部楼层
对于这样的底层问题,最好还是用OpenGL去试验,这样会少些干扰。
不是说OSG不好,而是OSG太好,致使你很多对OSG的理解偏差,导致对基本图形学概念的理解偏差。

该用户从未签到

发表于 2011-7-28 16:16:04 | 显示全部楼层
osg内部会在响应窗口缩放事件的时候按比例对投影矩阵进行修改

该用户从未签到

发表于 2013-9-9 16:05:48 | 显示全部楼层
楼主,您这个问题最后解决没?你的是模拟上下两个通道,我目前是想模拟左中右三个通道,因为使用透视投影设置fov角度比较大(比如90度)的时候,通过投影仪接到幕布上显示场景,发现由于透视投影造成的场景的拉伸形变相当明显。所以,考虑左右两个通道的显示使用slave相机,计算一下正确的偏移矩阵,显示没有问题,但是变形依旧。从而又考虑左右通道的slave相机的投影矩阵不变,继承主相机的投影矩阵,计算一下观察矩阵的偏移矩阵,目前没有完全解决,就是在两个通道的交界处,会由于观察矩阵的不同,当相机转动时,在那个交界处会出现明显的棱角,而不是平滑的过度的情况。

该用户从未签到

发表于 2013-9-9 16:38:37 | 显示全部楼层
sky11811 发表于 2011-7-23 18:07
你要面临的问题比你想象的要复杂的多。你这种做法是肯定不会成功的。

       **大哥,不好意思又翻陈年老帖,想借楼请教您图形学的问题,上课的时候没听讲,所以图形学基础比较差。
    我目前遇到一个这样的问题,就是:设置透视投影的fov为60度,或者90度,按照透视投影的原理,在视觉上,显示器上显示出来的场景的两边应该是存在一种“拉伸形变”的感觉的。这个应该没有疑问。当场景使用一台显示器或者一个投影仪显示的时候,这种现象应该还不是很明显。但是,当我使用Matrox TripleHead2Go 环幕仪进行分屏,然后外接三个投影仪,投影到三个屏幕的时候(左右两个屏幕与中间的屏幕成150度夹角),这种透视投影造成的视觉拉伸感特别明显,中间屏幕渲染的是视点方向的场景,这个是很正常的,两边的屏幕渲染的是视点左右方的场景,会明显的感觉树木或者房子沿着视点方向拉伸严重,这应该也是正常的。ps:我的程序中只用了一个主相机。fov角度设置为60度,宽高比为屏幕分辨率的宽高比。znear为1,zfar为500;
     后来,我想使用多相机进行渲染,在程序中模拟三个相机,中间一个主相机,左右两边使用slave相机,然后计算左右两个从相机的投影矩阵的偏移矩阵,计算绝对正确,观察矩阵继承主相机的。出来的结果仍然是两边的场景存在一定的视觉上的拉伸。应该也是正常情况。
     那么,我就想到另外一种情况,就是跟楼主的想法一样,投影矩阵继承主相机的投影矩阵,计算观察矩阵的偏移矩阵,以便三个相机构成完整的场景渲染。但是,我个人认为,即便计算正确,在左右两个屏幕与中间屏幕的交界处,也必然存在由于观察矩阵的不同而导致的偏差。我目前得到的结果是图形投影没有问题,就是感觉这个交界处是一条棱边一样,转动相机,会明显感觉场景在这个位置“波动”(不好描述,就是感觉中间一条凸起的棱边。) 这个应该也是正常情况吧?
      所以,我有个问题请教,就是,我如何做或者如何计算,在使用比较大的fov角度以获得更宽视野的时候,能避免这种因为透视投影造成的视觉拉伸呢?或者,您有什么建议?还望指教!基础较差,难免有错误的言论,正在努力补基础ing。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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