OpenGL ES手册翻译---3.栅格化(二)

3.5 多边形

多边形由带状三角簇,扇形三角簇或者一些独立的三角形构成。像点和线段一样,多边形的栅格化由几个变量控制。

3.5.1 基本多边形的栅格化

栅格化多边形的第一步是要判定多边形是面朝前的还是朝后的。窗口坐标系中计算多边形的区域的符号(裁剪或者未裁剪)作为判定依据。一种计算这个区域的方法是
a = \frac{1}{2} \displaystyle\sum_{i=1}^{n-1} x_w^i y_w^{i\bigoplus1} - x_w^{i\bigoplus1} y_w^i \qquad(3.4)
x_w^iy_w^i是n个顶点的多边形(顶点数目为了计算方便是从0开始计数的)的第i个顶点在窗口坐标系中的x和y坐标,i\bigoplus1表示(i+1)模除n。对这个值的符号的解释通过下面函数控制:

void FrontFace(enum dir);

dir设置为CCW(在窗口坐标系中投影多边形的方向是逆时针的)表示在使用前应该取a的相反数。把dir设置为CW(对应着顺时针方向)使用上面计算的公式的a的符号即可。面朝前的判定仅仅需要一个状态位,初始化时设置为CCW

通过公式3.4计算的区域的符号是正的(包括最后一次调用FrontFace可能会翻转符号),那么这个多边形就是正面朝前的;反之是背面朝前的。使用这个判定还要结合CullFace函数的使能位和模式选择来决定特定的多边形能不能栅格化。CullFace模式通过下面的函数设置

void CullFace(enum mode)

mode是一个符号常量:是FRONT,BACK,FONT_AND_BACK中的一个。使用Enable或者Disable来开启或者关闭剔除使用的符号常量CULL_FACE。剔除是关闭的或者CullFace的模式是BACK,朝前的多边形就可以栅格化,同时,只有剔除功能是关闭的或者CullFace函数是FRONT模式,朝后的多边形才可以被栅格化。CullFace的初始值模式是BACK。初始化时,剔除功能是关闭的。

多边形的栅格化过程中,决定产生碎片的规则被称为点采样。通过多边形的顶点在窗口坐标中的x和y值,可以获取二维的投影矩阵的形式。在中心在多边形内部的碎片由栅格化过程产生。对在中心在多边形边缘的碎片会有一些特殊的处理。这种情况下我们要求,如果两个多边形在共同的边上(由相同的端点),碎片的中心也在这个边上,那么在栅格化过程可以确定多边形会产生碎片。

栅格化多边形会产生每块碎片相关联的数据,我们来说明这些数据在三角形的碎片中是如何产生的。给三角形定义一个重心坐标。重心坐标是三个数字,a,b,c组成的,每个数字范围为[0,1],而且有a+b+c=1。这些坐标确定一个在三角形内或者三角形边界上的唯一的点p,有公式
p = ap_a + bp_b + cp_c
p_a,p_b,p_c是三角形的顶点。a,b,c有以下公式算出:
a = \frac {A(pp_bp_c)} {p_ap_bp_c}
b = \frac {A(pp_ap_c)} {p_ap_bp_c}
c = \frac {A(pp_ap_b)} {p_ap_bp_c}
A(lmn)表示在窗口坐标系中顶点为l,m,n的三角形的面积。

p_a,p_b,p_c数据分别的表示为f_a,f_b,f_c。栅格化三角形产生一个碎片的f数据值可以通过下面公式算出:
f = \frac {af_a/w_a + bf_b/w_b + cf_c/w_c} {a/w_a + b/w_b + c/w_c} \qquad(3.5)
w_a,w_b,w_cp_a,p_b,p_c分别在w裁剪坐标中的值。a,b,c是产生数据的碎片的重心的坐标。a,b,c必须精确的和碎片的中心的坐标关联。另外一种说法就是碎片的相关数据必须是从碎片的中心采样而来的。

和线段栅格化一样,窗口z也就是深度值,必须使用线性插值来计算:
f = af_a+bf_b+cf_c

3.5.2 深度偏移

多边形的栅格化产生的所有碎片的深度值会有一个根据多边形计算的单一的偏移量。决定这个值的函数是

void PolygonOffset(float factor, float units)

factor是多边形的最大深度斜率的系数,units是依赖于实现的和深度缓冲的可用分辨率有关的常量。结果值求和生成多变形的偏移值。factorunits可用是正数或者负数。

三角形的最大深度变化率m可以通过下面公式计算:

m = \sqrt {(\frac{\partial z_w}{\partial x_w})^2 + (\frac { \partial z_w} {\partial y_w}) ^2} \qquad (3.6)

(x_w,y_w,z_w)是三角形的点,m的近似公式为:
m = max \{ |\frac {\partial z_w} {\partial x_w}|,| \frac {\partial z_w} {\partial y_w}| \} \qquad (3.7)
最小可解差r是依赖于实现的常数。它是窗口坐标z值中的最小差异,保证在整个多边形光栅化和深度缓冲区中保持不同。两个多边形有相同的顶点栅格化后产生的碎片对,但是z_w和r不同,将会在深度值上有所不同。

多边形的偏移值o有以下公式:

o = m*factor + r * units \qquad (3.8)

m作为深度值的函数,取值区间为[0,1],计算公式如上,o在相同的区间中,作用在深度值上。

POLYGON_OFFSET_FILL的布尔值决定了o是否会被应用在多边形的偏移上。使用EnableDisable函数来设置布尔状态值。如果POLYGON_OFFSET_FILL是打开的,o的值将会被添加到栅格化多边形产生的每个碎片的深度值上。

碎片的深度值,不论是偏移量被执行(偏好)之后牵拉,还是多边形的栅格化中使用的顶点值被牵拉,总是被限制在[0,1]的范围中。

3.5.3 多边形的多重采样栅格化

如果SAMPLE_BUFFERS是一,多边形的栅格化采用下面的算法。多边形栅格化为每个带有一个或多个采样点的帧缓冲产生一个碎片,这些采样点满足点在3.5.1节中描述的采样点标准,包括一些在多边形边界尚的需要特殊处理的采样点。如果多边形根据CullFace模式和方向被剔除,那么在栅格化期间就不会产生碎片。

满足采样标准的采样点对应的覆盖位为1,否则覆盖位为0。顶点着色器varying输出变量和深度值如同3.5.1节中描述的那样,通把对应采样位置代换到重心方程做线性插值计算,使用等式3.5或者忽略w通道使用其近似公式。一种实现方法是,使用像素上的任何位置,包括碎片的中心或者一个采样位置,给一个或者多个采样点通过重心公式分配相同的一组varing值。

3.5.4 多边形的栅格化状态

多边形栅格化的状态由多边形偏移公式的影响因子和偏好值组成。初始化的多边形的偏移量因子和偏好值都是0;初始化的多边形偏移量是关闭的。

3.6 矩形像素块

矩形像素块的颜色值使用TexImage2D和相关的函数(见3.7.1节)来指定。控制TexImage2D行为的一些参数和操作,通过ReadPixels函数共享(通常从帧缓冲中获取像素值);ReadPixels函数的讨论推迟到4.3节中讨论,因为要详细讨论帧缓存之后。尽管如此,这一届中我们需要注意到,TexImage2D从属的参数和状态,也存属于ReadPixels

这一节仅仅描述这些矩形是怎么在客户端内存中被定义的以及转移客户端内存中的像素矩形到GL或者相反的过程所涉及的步骤。

参数控制在客户端内存中的像素(用来读写的)的编码,这些参数用函数PixelStorei设置。

3.6.1 像素的存储模式

像素存储的模式会在TexImage2DReadPixels函数执行时影响他们的操作(和其他的函数一样,见3.7节)。像素存储模式使用函数:

void PixelStorei(enum pname, T param);

pname是一个符号化的常量,代表被设置的参数,param是设置给参数的值。表3.1总结了像素存储的参数,类型和初始值,以及值的范围。给参数设置一个超过给定范围的值导致INVALID_VALUE错误。

image
image

3.6.2 矩形像素块的传输

在客户端内存中编码的像素传输到GL的过程如图3.5。我们按照这个过程顺序按发生阶段介绍。

接受或者返回像素块的函数遵守下面的参数(这些函数指定的其他参数也一样):

format是一个符号化的常量,表示在内存中的值代表什么格式。
widthheight是宽和高,分别是要被画的像素块的宽高。
data是要被画的数据的指针。这些数据用GL数据类型的一种或者两种类型表示,数据类型由type指定。获取四种类型的名字和GL数据类型的对应关系在表3.2中给出。

image
  • 解包

数据从客户端内存中获取,客户端内存中以无符号的bytes类型或者无符号short类型(GL数据为ubyteushort)的序列存储。这些元素根据format,一个,两个,三个或者四个为一个集合,形成分组。表3.3总结了从内存中获取的分组的格式。

每个GL数据类型的值被客户端的GL绑定的指定的语言解释。

并不是所有的formattype的组合是有效的,GL接受的组合规定在表3.4中。附加的限制会在特定的函数中强制实行。

image

在内存中的分组被看作是按照矩形块排列。这个矩形块有一系列的行组成,第一行的第一组的第一个元素指向传递给TexImage2D的指针。在一行中,分组的数目是宽度;如果p表示第一行第一个元素在内存中的位置,那么第N行的第一个元素是:
p + Nk \qquad (3.9)

N是行数(从0开始计数),k定义为:
k = \begin{cases} nl &\ s \ge a, \\ a/s \lceil snl/a \rceil &\ s<a \end{cases} \qquad (3.10)

n是分组中元素的数目,l是一行中分组数,a是UNPACK_ALIGNMENT的值,s是元素用ubytes为单位的大小。如果每个元素的比特位数不是1,2,4或者8乘以GLubyte的比特位数,那么对所有的a就有k=nl。

UNSIGNED_SHORT_5_6_5,UNSIGNED_SHORT_4_4_4_4,UNSIGNED_SHORT_5_5_5_1是一些特殊的情况,每一组所有的通道都被打包成一个单一的无符号短类型。每个被打包的像素的通道数目通过类型来修正,必须和由format参数指定的每组的通道数目匹配,如表3.5。如果不匹配就会发生INVALID_OPERATION错误。这个限制也作用于所有使用typeformat参数定义接受或者返回的像素数据的类型和格式的函数。

image

每个被打包的像素类型的第一个第二个第三个和第四个通道的位字段如表3.6。每个字段都是无符号整形。如果基本GL类型的支持超过了最小精度(比如9位字节),则打包通道在像素中会右对齐。

image

通道打包使用第一通道在字段的高位的方式,连续的通道逐步占用低位。每个通道的高位被打包在字段的高位中。

在打包的像素中通道和区域的对齐如表3.7中的描述。

image

上面的关于行的长度和图像提取的讨论对打包的像素也是有效的,如果“分组”替换为“通道”,每个分组的通道数目可以理解成1。

  • 转换成浮点指针

每个分组中的元素,将对应的整数,无符号整数或者元素的无符号的字段类型,根据2.1.2节中描述的近似公式,转化成浮点值。

  • 转化为RGB

这一步仅仅用在如果formatLUMINANCE或者LUMINANCE_ALPHA时。如果formatLUMINANCE,每组元素,通过把原始的单一元素复制到每三个新元素为一组中,被转化成R,G,B三个一组的元素。如果formatLUMINANCE_ALPHA,那么每两个元素为一组,通过复制第一个原始元素到一组三个的新元素中以及复制第二个原始元素到第四个新元素中,被转换成R,G,B,A四个元素一组。

  • 最后扩张为RGBA

每个分组通过下面的方式转换为四个元素一组:如果分组没有包含A元素,那么A会被添加并设置为1.0。如果R,G,B中的任何元素在分组中缺失,那么每个缺失的元素将会被添加,并设置为0.0。

推荐阅读更多精彩内容