设置一个不对称锥台不对称

2023-09-08 00:44:57 作者:轻舞飞扬

我有一个程序,其中我跟踪用户的位置,并设置截锥体(设置相机在用户的位置)来改变场景的视角,每个用户的立场。直至现在,我把所有四个角落的显示屏在同一z和我能根据用户的角度来设置不对称的视锥和改变场景。

目前的code看起来像下面这样:

  UserCam ::开始(){
    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 ::结束(){
loadGlobalMatrices();
}

UserCam :: setupCam(){
    这 - > _topLeftScreen = _wcTopLeftScreen  -  _wcUserHead; // wcTopLeftScreen,wcBottomRightScreen和wcUserHead都在同一参考框架
    这 - > _bottomRightScreen = _wcBottomRightScreen  -  _wcUserHead;

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

不过,我希望能够用一个显示其保持倾斜,向用户和/或不具有其所有顶点的同时做同样的以Z

其中上述可想而知作为一种倾斜窗口,顶点将有来自用户的位置定义的视锥。怎么是这样一个截锥可能的,其中显示不具备所有顶点在同一以Z

修改 有三架飞机中,我考虑的设置。中间的一个得到正确的不对称锥台,因为所有的顶点都在相同的Z,而左,右平面具有两个顶点各自在不同Z.是相同的顶点如下:

 基准面:TL:(-426.66,0,200),TR:(0,0,0),BL:(-426.66,320.79,200),BR:(0 ,320.79,0)
平面2: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)
 

解决方案 ug中如何画锥台

在此设置的想法是将其转变为一个情况下,各个角落都有相同的z坐标。通常这样做,以期矩阵,你会得到:

  overall_transform =(投影)*(查看*世界)
 

或OpenGL的措辞

  overall_transform =预测*模型观察
 

如果你不想乱动原来的模型视图矩阵,你应该引入另一种矩阵之间:

  overall_transform =(投影*适应)*(查看*世界)
 

其中,适应是屏幕的边角映射到一个平面旋转矩阵恒定的z坐标。

为了找到预测你必须将屏幕与适应正确的参数。

修改

我们先从一个任意场景摄像机的位置,方向和屏幕是已知的。我们认为,该模型矩阵是已经在那里为每个对象

然后我们需要为视角 V 的对准摄像头的由来。这个矩阵可以很容易地计算出 gluLookAt 。整体矩阵是那么 T = V * M

直到这个步骤的矩阵是相同的所有三个屏幕。因此,这部分应该是在模型视图矩阵。我们现在增加进入投影矩阵,因为它每屏不同。

我们需要申请一个旋转研究的对齐屏幕垂直于z轴。摄像机的位置必须不会在这个步骤改变,因为它重新presents投影中心。整体改造,现在 T = R * V * M

为了计算的角度,我们可以使用如 ATAN2

  DX = right.x  -  left.x
DZ = right.z  -  left.z
角= ATAN2(DZ,DX)
 

这可能需要稍微适应这种计算您的实际需要。

现在是时候运用的实际透视变换,它可以与 glFrustum 来完成。

我们需要找到画面的局部边缘。你可以改变的屏幕坐标的变换(研究* V )。

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

现在所有三个坐标应具有相同的z坐标。我们可以使用这些如下:

  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(...);
//任何进一步的模型转换

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

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;
}

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.

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?

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)

解决方案

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)

or in the OpenGL wording

overall_transform = projection * 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)

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

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

Edit

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:

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.

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.

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.

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

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

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)

So overall T = glFrustum * R * V * M:

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

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