光栅化操作阶段,由顶点程序处理的顶点将进入硬件处理阶段。首先顶点组装为图元,如三角形。同时,各个图元还将被进一步处理,进而确定屏幕上的2D形式,并光栅化为片元集合。
光栅化过程包括如下子操作:剪裁操作、透视除法、背面剔除操作、视口转换以及扫描转换。光栅化操作不可编程。
3.1剪裁操作
剪裁算法通常在硬件中实现,用户无权干涉。分为3种:
三角形位于视锥体外部并被丢弃;
三角形位于视锥体内部,并被传递至下一步骤;
三角形与视锥体部分相交,须执行剪裁操作。
3.2透视除法
为了实现齐次(剪裁)空间至笛卡尔空间的转换,各个顶点需要除以自身的w坐标。该值等于-z且为正值,表示相对于相机空间xy平面的距离值。因此,经w除法操作后,较远处的对象通常较小,这就是所谓的透视投影或透视收缩效果。所以,w除法通常称为透视除法。
在经过透视除法操作后,剪裁空间内的顶点可通过标准化设备坐标加以表示(NDC)。X y坐标位于(-1,1)范围内,z坐标位于(0,1)(opengl为(-1,1))范围内,因为NDC坐标定义为标准化坐标。
3.3背面剔除操作
剔除操作是指消除相机对象不可见的场景内容。背面剔除操作能消除背向相机视点的相关多边形。背对相机的多边形称为背面,正对相机的多边形称为正面。
如何判断正面还是背面?
可以计算三角形法线n以及连接相机位置和当前三角形的法线c之间的点积。如果点积为正值,说明n c构成锐角,当前三角形为背面;点积为负值,说明三角形为正面;点积为0表示三角形为侧面。
但是这种方式要计算所有三角形的连接向量,会产生大量计算。投影转换使得全部连接向量平行于z轴。通用连接向量表示为“平行投影直线”。
在投影转换后,基于CW排列顺序的2D三角形表示背面,而基于CCW顶点排列顺序的2D三角形则为正面数据面。
对于2D三角形
P = (x2-x1)(y3-y1)-(y2-y1)(x3-x1)
如果P大于0,则三角形按照CCW方式排列;如果P小于0,则按照CW方式排列;如果等于0,则为侧面。背面 剔除子操作过程采用判别式来区分背面或正面数据。
不透明对象背面应该剔除掉。如果某一正面被其他正面数据面遮挡,则该正面数据面也不会对最终图像有所贡献。这一类不可见数据面也应该在输出合并阶段通过片元可见性算法进行处理,如Z缓冲算法。(详见第四章)。
光栅器所执行的剔除操作并非仅限于背面剔除操作,其他方案还包括z剔除算法。该方法需要读者理解z缓冲算法。
3.4 再访坐标系统
本节阐述背面剔除操作与RHS和LHS之间的关系。
3.4.13ds max至Opengl——翻转坐标轴
3ds max中垂直轴为Z轴,opengl垂直轴为Y轴,这会导致对象呈现翻转状态。3dmax提供yz轴翻转功能可以解决这个问题。
3.4.2Opengl至Direct3D——反射
将RHS模型植入LHS将生成反射效果。
将Z逆置即可。
3.4.3opengl至Direct3D——顶点重排列
如果Direct3D直接渲染,那么正面数据会被剔除,背面数据被渲染。原因就是RHS转换为LHS后,2D三角形的正面排列顺序为CCW,背面排列顺序为CW;而Direct3D 默认剔除的是D3DCULL_CCW,即默认剔除CCW排列的三角形,这样的话就把转换后的正面给剔除了。所以为了能够转换后的背面,D3DCULL_CCW改为D3DCULL_CW即可。
3.5 视口转换
视锥体宽高比和视口的宽高比应该相同,这样的话对象不会变形。
Opengl中,glViewport(MinX,MinY,w,h)用于定义视口的矩形区域,glDepthRange(MinZ,MaxZ)用于定义其z值范围。
剪裁空间采用LHS,屏幕空间采用RHS,两者y轴相反,所以剪裁空间至屏幕空间的转化需要翻转y轴。先将NDC下的物体坐标(2X2X1,即x(-1,1),y(-1,1),z(0,1)按视口大小缩放,然后把物体平移至屏幕中间。
视口矩阵通常为(W/2,0,0,MinX+W/2);
(0,-H/2,0,MinY + H/2);
(0,0,MaxZ-MinZ,MinZ);
(0,0,0,1);
3.6 扫描转换
扫描转换阶段定义了图元所覆盖的屏幕空间像素位置,冰茶只计算各顶点属性,进而定义各个像素位置处的片元属性。
一般采用线性插值方法。
两个规则:
左上规则:当边上的同一像素被两个三角形共享时,需要判断其到底属于哪个三角形,否则该像素将被扫描算法计算两次。Opengl和Direct3D采用左上规则:即如果像素位于三角形的上边或左边,则该像素隶属于此三角形。
透视修正:相机空间转换为剪裁空间后,共线顶点之间的距离比例会改变,剪裁空间转换为屏幕空间后,这个比例会维持,即屏幕空间的比例也会改变,如果直接采用“变形”屏幕空间距离比例,则会导致问题。所以要采用透视修正来解决这个问题。
3.7 应用:对象拾取操作
3D图形程序中,较为常见的操作时从屏幕的渲染场景中拾取或选取操作对象。比如点击茶壶对象来完成对该对象的拾取,屏幕空间图像可视为像素阵列,鼠标点击操作将返回2D像素坐标(Xs,Ys)。本节讨论如果通过(Xs,Ys)确定点击对象。
3.7.1 计算世界空间中的光线
现在屏幕空间中定义一个平行于Z轴的方向向量,然后通过视口矩阵和投影矩阵转化成相机空间中的光线向量。命名为CS_Direc。
然后将相机空间光线转换回世界空间。可以通过视见矩阵的逆操作来实现。对应可得到世界空间光线的方向向量,命名为WS_Direc。
假设相机空间的起始点为相机空间的原点,那么经转换到世界空间后,该起始点为EYE位置。命名为WS_Start
旋转矩阵的逆矩阵为其转置矩阵。原因是旋转矩阵为正交矩阵。R乘以R的转置 = I;
世界空间光线的计算代码:pick函数。
3.7.2 光线——对象相交测试
如何判断光线与多边形网格对象是否相交?从理论上讲,该过程需要将光线与对象中的各个三角形执行橡胶测试,代价过于高昂。一种快速但精确度稍差的近似方案是基于包围体(BV)的多边形网格相交测试,包围体将完整包含多边形网格,并于随后执行各项BV相交测试。光线——三角形相交,光线——球体相交。
较为常见的BV:轴对齐包围盒(AABB),包围球。
基于AABB的包围球和紧密型包围球。
对于光线——球体相交测试,通过计算二次方根结果来判定是否相交。
一般光线——三角形相交测试会使用光线——球体相交测试来做预处理