使用 glFrustum 创建拼接场景

Posted

技术标签:

【中文标题】使用 glFrustum 创建拼接场景【英文标题】:Creating a stitched scene using glFrustum 【发布时间】:2013-06-14 18:28:01 【问题描述】:

我有一个程序可以根据用户的位置在屏幕上渲染场景。随着用户改变位置,平截头体发生变化以提供离轴投影。我想利用该技术在三个不同的显示器上工作,将更大的场景拼接在一起,如下所示:

想象一下跨三个显示器渲染的大型真实世界场景。三个显示器应该显示场景,因为它会根据用户的位置在每个显示器上改变视角。我可以使用一个显示器来根据用户的位置渲染场景,但无法想到在三个屏幕上工作的方法。

我创建的类离轴投影基本上做了以下事情:

customCam::project()
pushMatrices();
glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
        glFrustum(leftNear.x, rightNear.x, bottomNear.y, topNear.y, _near, _far);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(uPos.x, uPos.y, 0, uPos.x, uPos.y, -1, 0, 1, 0); //neglect z scaling for now. In the main program, it's there
    glTranslatef(0, 0, uPos.z);

如何缝合三个平截头体,使场景看起来像在现实世界中一样连续?目前,该类的用户绘制场景如下:

cstCam.project();
    //draw something here
popMatriceS(); //which were pushed before glFrustum projection

编辑: 就我而言,要为用户定义三个平截头体(考虑到同一参照系中所有显示器的用户和屏幕角),我执行了以下操作:

custCam1.project();
//draw scene here. eg: two walls at the far left and right screen
drawWalls();
popMatrices();
custCam2.project();
drawWalls();
popMatrices();
custCam3.project();
drawWalls();
popMatrices();

void drawWalls()
//Left most corner screen wall
glBegin(GL_QUADS);
glVertex3f(-1.5*PHWIDTH, HEIGHT/2, 0); //where PHWIDTH, HEIGHT is the physical width/height of each screen
glVertex3f(-1.5*PHWIDTH, HEIGHT/2, -50);
glVertex3f(-1.5*PHWIDTH, -HEIGHT/2, -50);
glVertex3f(-1.5*PHWIDTH, -HEIGHT/2, 0);
glEnd();

//Right most corner screen wall
glBegin(GL_QUADS);
glVertex3f(1.5*PHWIDTH, HEIGHT/2, 0); //where PHWIDTH, HEIGHT is the physical width/height of each screen
glVertex3f(1.5*PHWIDTH, HEIGHT/2, -50);
glVertex3f(1.5*PHWIDTH, -HEIGHT/2, -50);
glVertex3f(1.5*PHWIDTH, -HEIGHT/2, 0);
glEnd();

【问题讨论】:

【参考方案1】:

这并不像看起来那么难。考虑下图(在 znear 层从上方看的三个屏幕)

我假设每个屏幕在 znear 距离处沿 x 方向跨越 2 个单位。您可能需要根据场景缩放此值。

三个屏​​幕的 y 坐标范围没有变化,因为它们处于相同的垂直位置。

因此,您需要三个不同的屏幕投影矩阵。确定偏移量非常简单。您只需要相机点的差异:

left screen   => [-3 - camera.x, -1 - camera.x]
center screen => [-1 - camera.x, 1 - camera.x]
right screen  => [1 - camera.x, 3 - camera.x]

当然,您需要如图所示在屏幕空间中的摄像头位置。

视图矩阵可以是任意的,但对于所有三个屏幕应该是相同的。这次,将场景空间中的相机位置传递给gluLookAt

【讨论】:

我编辑了我的帖子,添加了一些关于我能够实现的目标的更多细节。我基本上能够找到屏幕所有角落与用户位置的偏移量,然后使用我的cstCam::project 函数为这三个屏幕定义了三个不同的投影矩阵。使用我在上面编辑中发布的代码,我尝试在我的屏幕上模拟相同的内容(三个不同的视口)并得到以下结果:1)用户在三个屏幕的中心i.imgur.com/u9O65G8.png,2)用户向右移动: i.imgur.com/6bxY0R3.png 在您将看到的第二个屏幕截图中,当用户向右移动时,第一个摄像头的墙开始显示在第二个屏幕中,并且它不会形成连续场景。但是,我不确定这是否与我在上面所做的三个场景中的视图矩阵相同?此外,如果是这种情况,我无法辨别为什么所有三个都应该只有一个模型视图矩阵。很高兴能从你这边读到同样的解释。 应该只有一个(模型)视图矩阵,因为只有一个视点,所以三种情况下眼点都是相同的。每个显示器的查看方向也是相同的(垂直于显示平面,因此您只需为每个屏幕定义一个不对称的平截头体即可。您的屏幕截图表明您做得不对... @derhass:对于单个显示,不对称截头锥体和投影看起来是正确的。我使用的代码是pastebin.com/kLs6yGQA这里beginend是使用相机的方法,我使用相机进行投影为camera1.begin();//drawingcamera1.end。由于它适用于单个显示器,因此本质上可以将相同的代码用于三个显示器,因为我在编辑中为其编写了代码。我假设因为它适用于单个显示,所以当我使用三个但不确定它是平截头体还是 MV 矩阵时发生了一些错误? @user1240679:好吧,只显示您正在使用的真实代码,尤其是各种参数的值。仅从这些代码 sn-ps 很难猜出发生了什么。

以上是关于使用 glFrustum 创建拼接场景的主要内容,如果未能解决你的问题,请参考以下文章

BIRT 中如何根据参数动态拼接 SQL

oracle 字符串拼接慢不慢

CV实战 | 使用OpenCV进行图像全景拼接

.NET性能优化-使用ValueStringBuilder拼接字符串

字符串拼接的五种方式

场景应用:说说你对字符串拼接的理解