use*_*679 4 c++ opengl algorithm 3d
我有一个程序,我在其中跟踪用户的位置并设置视锥体(将相机设置在用户的位置)以根据用户的位置更改场景的视角.直到现在,我将显示屏的所有四个角都放在同一个z上,我能够根据用户的视角设置不对称平截头体并改变场景.
当前代码如下所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
但是,我希望能够对显示器做同样的事情,该显示器保持倾斜于用户和/或没有相同的所有顶点Z.
以上可以想象为一种倾斜窗口,其顶点将具有从用户位置定义的平截头体.如果显示器没有所有顶点,那么这种平截头体怎么可能Z呢?
编辑
我正在考虑的设置中有三个平面.中间的一个给出正确的不对称平截头体,因为所有顶点都在同一个Z,而左和右平面有两个顶点,每个顶点在不同的Z.它们的顶点如下:
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)
Run Code Online (Sandbox Code Playgroud)
此设置中的想法是将其转换为所有角具有相同z坐标的情况.通常这是通过视图矩阵完成的,你得到:
overall_transform = (projection) * (view * world)
Run Code Online (Sandbox Code Playgroud)
或者在OpenGL中的措辞
overall_transform = projection * modelview
Run Code Online (Sandbox Code Playgroud)
如果您不想篡改原始模型视图矩阵,则应在其间引入另一个矩阵:
overall_transform = (projection * adaption) * (view * world)
Run Code Online (Sandbox Code Playgroud)
adaption旋转矩阵在哪里,将屏幕的角映射到具有恒定z坐标的平面.
为了找到正确的参数,projection你必须转换屏幕adaption.
我们从一个任意场景开始,在这个场景中,摄像机的位置,方向和屏幕都是已知的.我们认为模型矩阵已经存在于每个对象中:

然后,我们需要V将相机与原点对齐的视图转换.这个矩阵很容易计算出来gluLookAt.那么总体矩阵是T = V * M:

到目前为止,所有三个屏幕的矩阵都是相同的.所以这部分应该在模型视图矩阵中.我们现在添加的是投影矩阵,因为它在每个屏幕上有所不同.
我们需要应用一个旋转R,使屏幕垂直于z轴对齐.在此步骤中摄像机的位置不得改变,因为它代表投影中心.整体转型现在T = R * V * M.
为了计算角度,我们可以使用例如atan2:
dx = right.x - left.x
dz = right.z - left.z
angle = atan2(dz, dx)
Run Code Online (Sandbox Code Playgroud)
可能有必要根据您的实际需要稍微调整此计算.

现在是时候应用实际的透视变换了,这可以用来完成glFrustum.
我们需要找到屏幕的本地边缘.您可以使用当前transform(R * V)转换屏幕坐标.
TL' = R * V * TL
BL' = R * V * BL
BR' = R * V * BR
Run Code Online (Sandbox Code Playgroud)
现在所有三个坐标应该具有相同的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)
Run Code Online (Sandbox Code Playgroud)
整体而言T = glFrustum * R * V * M:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(...);
//any further model transforms
glMatrixMode(GL_PROJECTION);
glFrustum(...);
glRotate(...);
Run Code Online (Sandbox Code Playgroud)