设置不对称视锥 [英] Setting up an asymmetric frustum

查看:31
本文介绍了设置不对称视锥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序,我在其中跟踪用户的位置并设置平截头体(将相机设置在用户的位置)以根据用户的位置改变场景的视角.直到现在,我的显示屏的四个角都在同一 z 处,我能够设置不对称的视锥体并根据用户的视角改变场景.

I have a program in which I am tracking user's position and setting the frustum (setting the camera at user's position) to change the perspective of the scene as per the user's position. Until right now, I had all four corners of the display screen at the same z and I was able to set the asymmetric frustum and change the scene according to the user's perspective.

当前代码如下所示:

The current code looks something like the following:

UserCam::begin(){
    saveGlobalMatrices();  
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
        glFrustum(_topLeftNear.x, _bottomRightNear.x, _bottomRightNear.y, _topLeftNear.y, _camZNear, _camZFar);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    gluLookAt(_wcUserHead.x, _wcUserHead.y, _topLeftScreen.z, _wcUserHead.x, _wcUserHead.y, _topLeftScreen.z-1, 0, 1, 0);
}

UserCam::end(){
loadGlobalMatrices();
}

UserCam::setupCam(){
    this->_topLeftScreen = _wcTopLeftScreen - _wcUserHead; //wcTopLeftScreen, wcBottomRightScreen and wcUserHead are in the same frame of reference
    this->_bottomRightScreen = _wcBottomRightScreen - _wcUserHead;

    this->_topLeftNear = (_topLeftScreen/ _topLeftScreen.z) * _camZNear;
    this->_bottomRightNear = (_bottomRightScreen/_bottomRightScreen.z )) * _camZNear;
}

但是,我希望能够对保持向用户倾斜和/或所有顶点不在同一 Z 的显示器执行相同操作.

However, I want to be able to do the same with a display which is kept tilted to the user and/or does not have all its vertices at the same Z.

上面可以想象成一种倾斜的窗口,其顶点将具有根据用户位置定义的截锥体.在显示器没有所有顶点都在同一 Z 的情况下,这种截锥体怎么可能?

The above can be imagined as a sort of tilted window, the vertices of which would have the frustum defined from the user's position. How is such a frustum possible where the display does not have all the vertices at the same Z?

编辑
我正在考虑的设置中有三个平面.中间的一个给出了正确的非对称视锥体,因为所有的顶点都在同一个 Z 轴上,而左右平面有两个顶点,每个顶点都在不同的 Z 轴上.它们的顶点如下:

EDIT
There are three planes in the setup that I am considering. The middle one give the correct asymmetric frustum since all the vertices are at the same Z, whereas the left and right planes have two vertices each at different Z. The vertices of the same are as follows:

Plane1: TL : (-426.66, 0, 200), TR: (0, 0, 0), BL : (-426.66, 320.79, 200), BR : (0, 320.79, 0)
Plane2: TL : (0, 0, 0), TR: (426.66, 0, 0), BL : (0, 320.79, 0), BR: (426.66, 320.79, 0)
Plane3: TL:  (426.66, 0, 0), TR: (853.32, 0, 200), BL : (426.66, 320.79, 0), BR : (853.32, 320.79, 200)

推荐答案

此设置的想法是将其转换为所有角具有相同 z 坐标的情况.通常这是用一个视图矩阵完成的,你会得到:

The idea in this setup is to transform it to a case where all corners have the same z-coordinate. Usually this is done with a view matrix and you get:

overall_transform = (projection) * (view * world)

或在 OpenGL 的措辞中

or in the OpenGL wording

overall_transform = projection * modelview

如果你不想篡改原来的modelview矩阵,你应该在中间引入另一个矩阵:

If you don't want to tamper with the original modelview matrix, you should introduce another matrix in between:

overall_transform = (projection * adaption) * (view * world)

其中 adaption 是一个旋转矩阵,它将屏幕的角映射到具有恒定 z 坐标的平面.

where adaption is a rotation matrix that maps the screen's corners to a plane with constant z-coordinate.

为了为projection找到正确的参数,你必须用adaption转换屏幕.

In order to find the correct parameters for projection you have to transform the screen with adaption.

我们从一个任意场景开始,其中相机的位置、方向和屏幕都是已知的.我们认为每个对象的模型矩阵已经存在:

We start with an arbitrary scene where the camera's position, direction and the screen is known. We consider that the model matrices are already there for each object:

然后我们需要将相机与原点对齐的视图转换 V.这个矩阵可以很容易地用 gluLookAt 计算出来.整个矩阵则为 T = V * M:

We then need the view transformation V that aligns the camera with the origin. This matrix can easily calculated with gluLookAt. The overall matrix is then T = V * M:

直到这一步,所有三个屏幕的矩阵都相同.所以这部分应该在模型视图矩阵中.我们现在添加的内容进入投影矩阵,因为它因屏幕而异.

Up to this step the matrices are the same for all three screens. So this part should be in the modelview matrix. What we add now goes into the projection matrix because it differs per screen.

我们需要应用旋转 R 使屏幕垂直于 z 轴对齐.相机的位置在这一步一定不能改变,因为它代表了投影中心.整体转换现在是T = R * V * M.

We need to apply a rotation R that aligns the screen perpendicular to the z-axis. The position of the camera must not change at this step because it represents the projection center. The overall transformation is now T = R * V * M.

为了计算角度,我们可以使用例如atan2:

In order to calculate the angle, we can use e.g. atan2:

dx = right.x - left.x
dz = right.z - left.z
angle = atan2(dz, dx)

可能需要根据您的实际需要稍微调整此计算.

It might be necessary to adapt this calculation slightly to your actual needs.

现在是应用实际透视变换的时候了,这可以用 glFrustum 来完成.

Now is the time to apply the actual perspective transform, which can be done with glFrustum.

我们需要找到屏幕的局部边缘.您可以使用当前变换 (R * V) 来变换屏幕坐标.

We need to find the local edges of the screen. You could transform the screen coordinates with the current transform (R * V).

TL' = R * V * TL
BL' = R * V * BL
BR' = R * V * BR

现在所有三个坐标都应该具有相同的 z 坐标.我们可以这样使用它们:

Now all three coordinates should have the same z-coordinate. We can use these as follows:

common_z = TL'.z = BL'.z = BR'.z
glFrustum(TL'.x / common_z * z_near,
          BR'.x / common_z * z_near,
          BL'.y / common_z * z_near,
          TL'.y / common_z * z_near,
          z_near, z_far)

所以总体T = glFrustum * R * V * M:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(...);
//any further model transforms

glMatrixMode(GL_PROJECTION);
glFrustum(...);
glRotate(...);    

这篇关于设置不对称视锥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆