经过投影矩阵变换的顶点,再经过透视除法变换规范的NDC空间,这里的XY顶点都变换都近裁剪面了。
3D中东西要经过最后一步才能变成真正的屏幕坐标系中。这步叫ViewPort Transformation
ViewPort Transformation
我们先看下屏幕的坐标系什么样子
这个是windows下情况,屏幕X轴 正方向朝右 Y轴正方向朝下。原点在屏幕的左上角
Viewport 矩阵我们分两步求得
The viewport transformation will be represented by a 4x4 matrix. It encapsulates 2 stages
- a scaling to the shape of the viewport
- a transformation to the position of the viewport
第一步,放大的屏幕ViewPort大小,就是屏幕大小。
第二部,移动点到ViewPort,这步是因为 3D空间原点在中心。 以windows为例屏幕原点在左上角。
第一步
x在[-1,1]之间, 变换到屏幕[0~width] width屏幕宽分辨率
X轴在CVV中方向一样,只是放大了 width/2
y在[-1,1]之间, 变换到屏幕[0~height] height屏幕高分辨率
同样放大了 height/2 ,但是屏幕的Y轴方向和NDC中间相反,那么取反 -height/2
Z轴,我们在屏幕中先不关心,因为实际的值我们是写入Zbuff中,跟屏幕显示无关。
那么我们就构造缩放矩阵
第二步
消除屏幕坐标和NDC坐标系原点误差。
构造矩阵
x,y表示屏幕左下角的起点。一般我们是设置为0,0
那么想过矩阵相乘得到我们最终的ViewPort矩阵
Z轴部分我们不是很关心。也可以自己推到,屏幕空间Z的范围[Zmin Zmax]
ViewPort Transformation 是在管线中完成的,我们只要设置ViewPort大小,其他不用心。
但是有个地方要设计到。那么就是空间的拾取
我们把屏幕上一个点,变换3D空间中一个点。再和Camera的点,构成一条射线查询碰撞。
变换过程:
通过上面的矩阵 我们得到公式:
一般来说我们的X,y都是 0 0的,变换公式
这样我们有了屏幕的坐标就可以求出的NDC中xy坐标,但是一般我们能用都是世界坐标系或者摄像机坐标系的坐标。
这样我们变换回摄像机坐标系。我们可以承受 投影矩阵的逆矩阵,但是有简单的方法
投影矩阵
这里投影的X轴的基向量是2N/(right-left),那么投影矩阵对于X只是做了2N/(right-left)的缩放,那么逆操作成上他缩放值倒数(right-left)/2N
那么最终的矩阵公式
那么在摄像机坐标系在,可以得到一个点
因为摄像机坐标系中,摄像机点是原点。那么上面就是我们要的查询射线向量了。
如果要在世界坐标系中,只有把向量乘上相机矩阵的逆矩阵,摄像机的逆矩阵也特殊,看View矩阵那章。
参考:http://glasnost.itcarlow.ie/~powerk/GeneralGraphicsNotes/projection/viewport_transformation.html