OpenGL透视投影像素完美绘图

OpenGL Perspective Projection pixel perfect drawing

目标是绘制一个形状,比方说一个三角形,像素完美(顶点应以像素为单位指定)并能够在第 3 维中对其进行变换。

我用 正交投影矩阵 试过了,一切正常,但形状没有任何深度 - 如果我围绕 Y 轴看起来我只是围绕 X 轴缩放它。 (因为 正交 投影显然是这样的)。现在我想尝试使用 透视 投影。但是有了这个投影,坐标系就完全改变了,因此我不能用像素指定我的三角形顶点。此外,如果我的 window 的大小发生变化,形状的大小也会发生变化(因为坐标系发生了变化)。

有什么方法可以改变透视投影的坐标系,这样我就可以像使用正交投影一样指定我的顶点吗?或者有人知道如何实现第一句中描述的目标吗?

投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。它从眼睛space变换到剪辑space,剪辑space中的坐标通过除以剪辑坐标。 NDC 的范围是 (-1,-1,-1) 到 (1,1,1)。

在透视投影中,投影矩阵描述了从针孔相机看到的世界中的 3D 点到视口的 2D 点的映射。
相机平截头体(截棱锥)中的眼睛 space 坐标映射到立方体(归一化设备坐标)。

透视投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

其中:

aspect = w / h
tanFov = tan( fov_y * 0.5 );

prjMat[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect)
prjMat[1][1] = 2*n/(t-b) = 1.0 / tanFov


我假设视图矩阵是单位矩阵,因此视图 space 坐标等于世界坐标。
如果你想绘制一个多边形,其中顶点坐标被转换 1:1 为像素,那么你必须在与视口平行的平面上绘制多边形。这意味着所有点都必须以相同的深度绘制。
深度必须选择这种方式,即通过逆投影矩阵对归一化设备坐标中的点进行变换,得到以像素为单位的顶点坐标。请注意,通过逆投影矩阵变换给出的齐次坐标必须除以齐次坐标的 w 分量,才能得到笛卡尔坐标。
这意味着,平面的深度取决于投影的视角:

假设您设置了这样的透视投影:

float vp_w  = ....  // width of the viewport in pixel
float vp_h  = ....  // height of the viewport in pixel
float fov_y = ..... // field of view angle (y axis) of the view port in degrees < 180°

gluPerspective( fov_y, vp_w / vp_h, 1.0, vp_h*2.0f );

那么顶点坐标和像素的1:1关系的平面的depthZ,会这样计算:

float angRad = fov_y * PI / 180.0;
float depthZ = -vp_h / (2.0 * tan( angRad / 2.0 ));

注意,投影到视口的中心点是(0,0),所以平面的左下角点是(-vp_w/2,-vp_h/2,depthZ),右上角点为(vp_w/2, vp_h/2, depthZ)。确保透视投影的近平面小于 -depthZ,远平面大于 -depthZ

进一步了解: