本帖最后由 sirc 于 2010-3-23 21:00 编辑
4 Per-Fragment 操作和framebuffer
framebuffer可分两类a windows系统提供的缺省framebuffer对象 b 应用创建的非显示framebuffer对象
bitplane:framebufer中每一像素的每一bit组成一个bitplane,每一bitplane包含一个像素的一个bit。这些bitplane可以组成color, depth, stencil buffers。
对于windows系统framebuffer,color buffer包含一个front buffer,一个back buffer,典型来说,front buffer对应正在显示器显示的画面,而back buffer当前不可见。 对于应用创建的非显示framebuffer,color buffer名为COLOR_ATTACHMENT0,depth buffer名为DEPTH_ATTACHMENT,stencil buffer名为STENCIL_ATTACHMENT。
所有的bitplane缺省状态是不确定的。
4.1 Per-fragment操作
figure 4.1 Per-fragment操作
4.1.1 Pixel Ownership Test
这个测试判断framebuffer中位置(xw,yw)是否是GL控制的,若不是windows系统决定这一fragment的命运。这个测试允许windows系统控制GL的行为,例如GL窗口遮挡等。
应用创建的framebuffer中的像素总是归OpenGL ES所控制,而非windows系统。
4.1.2 Scissor Test
这个测试判断framebuffer中位置(xw,yw)是否位于scissor矩形内部,矩形由四个参数设置如下:
void Scissor( int left, int bottom, sizeiwidth, sizei height );
//若left <= xw < left + width且bottom<= yw < bottom + height,scissor测试通过,否则fragment舍。 这个测试通过Enable/Disable常量SCISSOR_TEST来使能/禁用。若禁用,认为SCISSOR测试总是通过的。
4.1.3 多重采样Fragment操作 这一步,根据SAMPLE_ALPHA_TO_COVERAGE,SAMPLE_COVERAGE, SAMPLE_ COVERAGE_VALUE和SAMPLE_COVERAGE_INVERT的值修改fragment的alpha和coverage的值。当然这是在SAMPLE_BUFFERS不等于1的时候有作用。
若SAMPLE_ALPHA_TO_COVERAGE使能,根据采样点的alpha值生成一个临时的coverage值,这个值与原coverage值进行AND运算后,生成fragment新的coverage值。
若SAMPLE_ALPHA_TO_COVERAGE禁用,fragment的新coverage值等于原值。
alpha值对应coverage值算法。。。
若SAMPLE_COVERAGE使能,fragment的coverage值还与另一个临时coverage值进行AND运算。该临时coverage值是SAMPLE_COVERAGE_VALUE的函数,而非alpha值。若SAMPLE_COVERAGE_INVERT= TRUE,临时coverage值求非后与原值AND运算。
void SampleCoverage( clampf value,boolean invert ); //设置SAMPLE_COVERAGE_VALUE, SAMPLE_COVERAGE_INVERT的值
4.1.4 Stencil Test
这个测试,stencilbuffer位置(xw,yw)的值与一个参考值进行比较,根据比较结果判定是否舍弃fragment。这个测试通过Enable/Disable常量STENCIL_TEST来使能/禁用。若禁用,fragment总是未经修改直接通过的。
两类stencil相关状态,名为正面stencil state集和背面stencil state集。Stencil测试处理非多边形的光栅化输出(点,线,位图,图像矩阵)以及正面多边形光栅化输出时,使用正面stencil state集;处理背面多边形光栅化输出时,使用背面stencil state集。
Stencil Test控制函数如下:
void StencilFunc( enum func, int ref, uintmask ); //设置两类stencilstate集相同值;
void StencilFuncSeparate( enum face,enum func, int ref, uint mask ); //face = FRONT, BACK或FRONT_AND_BACK
void StencilOp( enum sfail, enum dpfail,enum dppass ); //设置两类stencilstate集相同值;
void StencilOpSeparate( enum face, enumsfail, enum dpfail, enum dppass ); //face = FRONT, BACK或FRONT_AND_BACK
StencilFunc和StencilFuncSeparate函数有三个参数用以控制stencil测试是否通过;ref是比较的参考值,stencilbuffer中相应的值和参考值在比较前先同mask进行位AND运算,比较结果根据func来判定stencil测试是否通过。Func值有NEVER, ALWAYS, LESS, LEQUAL,EQUAL, GEQUAL, GREATER或NOTEQUAL。 StencilOp和StencilOpSeparate函数有三个参数来影响测试结果的影响。Sfail规定了stencil测试失败后对stencil buffer中相应值有什么动作要做。相应动作有KEEP, ZERO,REPLACE, INCR, DECR, INVERT, INCR_WRAP 和DECR_WRAP。Dpfail, dppass分别规定了深度测试(depth test)失败或通过对stencil buffer的动作。
若stencil测试失败,fragment舍去。
初始时,stencil测试禁用,正面背面的参考值为0,比较函数为ALWAYS,MASK为全1,stencil动作为KEEP。 若不存在stencilbuffer,测试默认通过。
4.1.5 深度缓存测试(depth buffer test)
若深度缓存测试失败,fragment舍去。通过Enable/DisableDEPTH_TEST可以来使能/禁用这一测试。若禁用,不进行深度比较和深度缓存的更新,fragment直接送入后续处理,stencil值按照深度测试通过的方式进行修改。
void DepthFunc( enum func ); //比较函数可以设置为NEVER, ALWAYS, LESS, LEQUAL, EQUAL, GREATER, GEQUAL, NOTEQUAL,比较双方是输入fragment的zw值与深度缓存当前位置的深度值。 若深度缓存测试失败,舍去当前fragment,当前stencil的值根据4.1.4方式更新。否则以zw更新fragment对应位置深度缓存中的值,同时更新stencil buffer相应值。
若不存在深度缓存,测试默认通过。
4.1.6 Blending
此环节通过Blend公式混合输入fragment的RGBA值与framebuffer中相应位置的RGBA值。Blending基于输入fragment的alpha值和framebuffer中相应存储的alpha值。
通过Enable/DisableBLEND可以来使能/禁用这一环节,若禁用fragment直接送入下一环节。
void BlendEquation( enum mode ); //同时指定RGB, ALPHA的模式
void BlendEquationSeparate( enum modeRGB, enummodeAlpha ); //分别指定两模式模式有FUNC_ADD,FUNC_SUBTRACT或FUNC_REVERSESUBTRACT.
Framebuffer中的目标RGBA分量是定点数,blending操作是浮点的,blending前默认有定点转换浮点的操作,转换有0,1不变性。
Blend公式如下所示,
Mode = FUNC_ADD, R = Rs*Sr + Rd*Dr,G = Gs*Sg + Gd*Dg,B = Bs*Sb + Bd*Db,A = As*Sa + Ad*Da
Mode = FUNC_SUBSTRACT, R = Rs*Sr - Rd*Dr,G = Gs*Sg - Gd*Dg,B = Bs*Sb - Bd*Db,A = As*Sa - Ad*Da
Mode = FUNC_REVERSE_SUBSTRACT, R = Rd*Dr - Rs*Sr,G = Gd*Dg - Gs*Sg,B = Bd*Db - Bs*Sb,A = Ad*Da - As*Sa
其中Sr, Sg, Sb, Sa是源混合因子,由源混合函数决定,Dr, Dg, Db, Da是目标混合因子,由目标混合函数决定。 混合函数如下:
void BlendFuncSeparate( enum srcRGB,enum dstRGB, enum srcAlpha, enum dstAlpha ); //分别指定两模式
void BlendFunc( enum src, enum dst); //同时指定RGB, ALPHA的模式混合函数和相应的混合因子如下所示,F代表S(源因子)或者D(目标因子)。FUNC=ZERO, Fr=0,Fg=0,Fb=0, Fa=0
FUNC=ONE, Fr=1,Fg=1,Fb=1, Fa=1
FUNC=SRC_COLOR,
Fr=Rs,Fg=Gs,Fb=Bs, Fa=As
FUNC=ONE_MINUS_SRC_COLOR, Fr=1-Rs,Fg=1-Gs,Fb=1-Bs, Fa=1-As
FUNC=DST_COLOR,
Fr=Rd,Fg=Gd,Fb=Bd, Fa=Ad
FUNC=ONE_MINUS_DST_COLOR, Fr=1-Rd,Fg=1-Gd,Fb=1-Bd, Fa=1-Ad
FUNC=SRC_ALPHA, Fr=As,Fg=As,Fb=As, Fa=As
FUNC=ONE_MINUS_SRC_ALPHA, Fr=1-As,Fg=1-As,Fb=1-As, Fa=1-As
FUNC=DST_ALPHA, Fr=Ad,Fg=Ad,Fb=Ad, Fa=Ad
FUNC=ONE_MINUS_DST_ALPHA,
Fr=1-Ad,Fg=1-Ad,Fb=1-Ad, Fa=1-Ad
FUNC=CONSTANT_COLOR, Fr=Rc,Fg=Gc,Fb=Bc, Fa=Ac
FUNC=ONE_MINUS_CONSTANT_COLOR, Fr=1-Rc,Fg=1-Gc,Fb=1-Bc, Fa=1-Ac
FUNC=CONSTANT_ALPHA,
Fr=Ac,Fg=Ac,Fb=Ac, Fa=Ac
FUNC=ONE_MINUS_CONSTANT_ALPHA, Fr=1-Ac,Fg=1-Ac,Fb=1-Ac, Fa=1-Ac
FUNC=SRC_ALPHA_SATURATE(只对源因子有意义) Sr=f, Sg=f, Sb=f, Sa=1,(其中f = min(As,1-Ad))
void BlendColor( clampf red, clampfgreen, clampf blue, clampf alpha ); //设置constant color, Cc
blending状态
初始blend公式对RGB和Alpha模式都是FUNC_ADD,初始混合函数对于源因子是ONE,对于目标因子是ZERO,初始constant color是(0,0,0,0),初始时blending禁用。
若color buffer不存在alpha,Ad缺省1。
4.1.7 抖动(Dithering)
通过Enable/Disable DITHER可以来使能/禁用这一环节。缺省使能。
抖动处理可以随机化量化噪声,可以使得低位数显示设备显示高位数效果。
对于颜色分量c,是一个浮点数,存入framebuffer前需转换成定点数,若framebuffer数据认为是m位定点数(都在小数点左边,此处浮点数不再认为[0,1]内)。我们让抖动输出c1,满足max(0,ceil(c)-1) <= c1 <=ceil(c),也就是说c1可以取两个值。
具体抖动算法与实现相关,不过必须只与输入颜色分量值和fragment的x,y窗口坐标有关。这一点是为了避免一些no-good effect。抖动算法实现可以参考下文,以及OpenGL® ES 2.0 Programming Guide中dithering章节。 http://www.virtualdub.org/blog/pivot/entry.php?id=151
4.1.8 多重采样fragment处理的说明
若SAMPLE_BUFFERS=1,stencil test,depth test,blending和dithering操作作用在每个pixel sample上,而非fragment。若该sample coverage为1,进行stencil, depth, blending, dithering等处理,否则无处理。
优化处理:可以只在fragment最中间的sample上做stencil, depth等测试,若需要更新,所有Multisample buffer的stencil, depth都更新为这一fragment的值。
Multsample buffer处理完后,color sample buffer需要合并生成一个color值,写入选择的color buffer。具体实现可能会延后写入color buffer。合并的算法实现相关,推荐是对每一颜色分量进行简单的平均。
4.2 整个framebuffer操作
4.2.1选择写入的buffer
color值写入front/back buffer是single/back buffered context由决定的。
4.2.2 buffer更新的微观控制
void ColorMask( boolean r, booleang, boolean b,boolean a ); //若boolean为真,允许写入相应分量
void DepthMask( boolean mask ); //若mask非零,允许写入深度值zw
void StencilMask( uint mask );//mask是s比特位的整数mask,对应s比特位的stencil buffer。
void StencilMaskSeparate( enum face,uint mask ); //face可以是FRONT, BACK或FRONT_AND_BACK
ES是否不支持colorindex mode? 这里没有提供OpenGL的IndexMask函数,参考OpenGL中相应函数如下, http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node104.html
若SAMPLE_BUFFERS=1,上面四个函数控制multisample buffer更新。Color mask对color buffer的更新没有影响。即使color mask全部关闭,color sample仍然按照前面章节的说明更新color buffer。
4.2.3 清除缓存
void Clear( bitfield buf ); //COLOR_BUFFER_BIT,DEPTH_BUFFER_BIT, STENCIL_BUFFER_BIT,分别指清除color, depth, stencil缓存;
void ClearColor( clampf r, clampf g,clampf b, clampf a ); //设定color buffer的清除颜色值,浮点数[0,1]输入转成framebuffer的定点数(2.1.2);
void ClearDepthf( clampf d ); //设定depth buffer的清除深度值,浮点数[0,1]输入转成framebuffer的定点数(2.12.1);
voidClearStencil( int s ); //设定stencil buffer的清除值,整数; 若clear函数被调用,在per-fragment上只允许进行pixel ownership test, scissortest, dithering处理。4.2.2 中mask处理也生效。若clear对应buffer不存在,没有效果而已。初始的RGBA清楚值为(0,0,0,0),stencil清除值为0,深度清除值为1.0。
清除multisample buffer
设定COLOR_BUFFER_BIT,DEPTH_BUFFER_BIT, STENCIL_BUFFER_BIT为1,相应清除color,depth, stencil buffer。
4.3 读取像素们(Reading Pixels)
4.3.1 Reading Pixels
Figure 4.2 读取像素操作 上图说明了如何将像素从framebuffer读出然后存入client memory。
void ReadPixels( int x, int y, sizeiwidth, sizei height, enum format, enum type, void *data );
ReadPixels函数的这些参数定义了3.6.2中的像素矩形。(Format, type)只允许(RGBA, UNSIGNED_BYTE)或者从表3.4中选择实现的特定组合,不能是LUMINANCE或LUMINANCE_ALPHA。GetIntegerv读取IMPLEMENTATION_COLOR_READ_FORMAT 和IMPLEMENTATION_COLOR_READ_TYPE可以获知该特定组合。 像素的存储模式可以是PACK ALIGNMENT=1,2,4,8(缺省4)。
读取的像素值来源于正在作为写入对象的color buffer。若FRAMEBUFFER_BINDING=0,像素值来源于当前连接的framebuffer对象的COLOR_ATTACHMENT0。 ReadPixels返回在color buffer中所有(i,j)值,其中x<=i<x+width,y<=j<y+height。若不存在alpha buffer,相应分量返回1.0。
RGBA值转换
Framebuffer读出的定点值先[0,1]饱和处理f,而后根据下表转化成相应的GL类型值c。 若type = INT,GL type int, c = [(2^32 - 1)f - 1]/2; 若type = UNSIGNED_BYTE,GL type ubyte, c = (2^8 - 1)f; 若type = UNSIGNED_SHORT_5_6_5,GL type ushort, c = (2^N - 1)f; 若type = UNSIGNED_SHORT_4_4_4_4,GL type ushort, c = (2^N - 1)f; 若type = UNSIGNED_SHORT_5_5_5_1,GL type ushort, c = (2^N - 1)f;
像素读取出来后放置在clientmemory中,内存组织方式如同TexImage2D。见章节3.6.2。
4.3.2 像素绘制/读取状态
PixelStore设置的状态,影响着像素读取。
4.4 FrameBuffer对象 默认的,GL使用windows系统提供的framebuffer,存储,尺寸,位置和图像格式等由windos完全控制。本章节着重说明应用创建的framebuffer。 应用创建的framebuffer对象包装framebuffer方式正如同纹理对象包装纹理的方式。特别的,framebuffer对象包含了颜色、深度和图案逻辑缓存等需要的状态。对于每一个逻辑缓存,一个framebuffer关联的图像可以和framebuffer联接,以用来存储逻辑缓存的渲染输出。Framebuffer可关联的图像包含纹理图像以及渲染缓存图像。 允许渲染缓存图像与framebuffer联接,OpenGL ES支持离屏渲染。同时允许纹理图像与framebuffer联接,ES支持渲染生成纹理图像。
4.4.1连接和管理framebuffer对象 缺省的,目标FRAMEBUFFER连接的framebuffer值0,指向了windows系统的缺省framebuffer,第4章的操作对象是缺省framebuffer。若FRAMEBUFFER连接的framebuffer不为0,指向了应用创建的framebuffer,也就是第4章的操作对象。
void BindFramebuffer( enum target,uint framebuffer ); //target=FRAMEBUFFER,framebuffer为未使用无符号整数名称。 BindFramebuffer创建的framebuffer分别有一个color连接点,depth连接点,stencil连接点。 BindFramebuffer可用来连接一个已有的framebuffer对象。
当前连接的framebuffer对象:ES操作影响的图像来源地,查询获取的状态来源地;fragment操作的目的地,也是ReadPixels的来源地;
对于应用创建的framebuffer:
pixel ownership test通过,也就是说framebuffer对所有的像素点有领地所有权; color buffer没有所谓的前台缓存(front buffer),后台缓存(back buffer); 唯一的colorbuffer对应连接点COLOR_ATTACHMENT0; 唯一的depthbuffer对应连接点DEPTH_ATTACHMENT; 唯一的stencilbuffer对应连接点STENCIL_ATTACHMENT; 无多重采样buffer,SAMPLES = 0,SAMPLE_BUFFERS=0;(怎么理解?难道生成离屏图像或者纹理图像不需要多重采样?还是意味着生成过程中可以有,但是结束后多重采样缓存废弃了?)
void DeleteFramebuffers( sizei n, uint*framebuffers ); //删除framebuffer对象
void GenFramebuffers( sizei n, uint*framebuffers ); //返回n个未使用的framebuffer对象名
4.4.2 图像关联的framebuffer对象 对于应用framebuffer,framebuffer可关联的图像,可以从framebuffer进行关联,断开关联;而系统缺省framebuffer的图像关联不允许修改。 一幅图像可以同时和多个framebuffer关联,从而节省单一framebuffer的内存消耗(这可能在多重采样中很有用)。一个逻辑buffer不能和多幅图像关联?
4.4.3 渲染缓存对象(renderbuffer) 渲染缓存是一个包含单幅可渲染内部格式的数据存储对象。
void BindRenderbuffer( enum target,uint renderbuffer ); //target=RENDERBUFFER,创建渲染缓存图像 OpenGL ES影响当前连接的渲染缓存对象。 GetIntegerV可以获取当前的RENDERBUFFER_BINDING。
void DeleteRenderbuffers( sizei n, const uint*renderbuffers ); //删除渲染缓存对象
void GenRenderbuffers( sizei n, uint*renderbuffers ); //获取未使用渲染缓存对象名称
void RenderbufferStorage( enum target,enum internalformat, sizei width, sizei height ); //设置渲染缓存的数据存储,
target = RENDERBUFFERinternalformat:包括如下5种格式, DEPTH_COMPONENT16——depth-renderable,D(16) RGBA4——color-renderable,R(4),G(4),B(4),A(4) RGB5_A1——color-renderable,R(5),G(5),B(5),A(1) RGB565——color-renderable ,R(5),G(6),B(5) STENCIL_INDEX8——stencil-renderable,S(8)
Width,height:渲染缓存的像素尺寸,不能大于MAX_RENDERBUFFER_SIZE。
void FramebufferRenderbuffer( enumtarget, enum attachment, enum renderbuffertarget, uint renderbuffer ); //联接渲染缓存对象和framebuffer中的逻辑缓存,target=FRAMEBUFFER;
attachment:COLOR_ATTACHMENT0, DEPTH_ATTACHMENT或STENCIL_ATTACHMENT;
renderbuffertarget:RENDERBUFFER
renderbuffer:需要联接的渲染缓存对象名
若执行成功,
FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE =RENDERBUFFER, FRAMEBUFFER_ATTACHMENT_OBJECT_NAME =renderbuffer;
联接纹理图像和framebuffer
ES支持通过CopyTexImage2D和CopyTexSubImage2D拷贝渲染内容到纹理图像。ES也支持直接渲染到纹理图像。
void FramebufferTexture2D( enumtarget, enum attachment, enum textarget, uint texture, int level );
target:FRAMEBUFFER;
texture:已存在的纹理对象或cube map纹理对象;
textarget:TEXTURE_2D,TEXTURE_CUBE_MAP_POSITIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_X,TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_NEGATIVE_Y,TEXTURE_CUBE_MAP_POSITIVE_Z, TEXTURE_CUBE_MAP_NEGATIVE_Z
level:纹理图像的mipmap level,必须为0;
FramebufferTexture2D函数执行成功后,
FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE =TEXTURE, FRAMEBUFFER_ATTACHMENT_OBJECT_NAME =texture; FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL= level;
若texture是cubemap纹理,FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = textarget;已有的纹理对象状态不变;
4.4.4 已联接framebuffer的纹理对象的渲染 必须避免在纹理对象进行渲染时,将此纹理对象与framebuffer联接。小心死循环哦!
4.4.5 Framebuffer完整性
Framebuffer关联完整性
若联接点attachment的FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE不为NONE,需要满足如下条件才能认为是framebuffer关联完整: image是FRAMEBUFFER_ATTACHMENT_OBJECT_NAME对象的分量,并且类型为FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; image的width和height非零; 若attachment是COLOR_ATTACHMENT0,image必须要有一个color-renderable的内部格式; 若attachment是DEPTH_ATTACHMENT,image必须要有一个depth-renderable的内部格式; 若attachment是STENCIL_ATTACHMENT0,image必须要有一个stencil-renderable的内部格式;
framebuffer完整性 framebuffer是完整的,意味着是windows系统提供的framebuffer,或者满足如下所有条件: 所有framebuffer连接点是framebuffer关联完整的; 至少有一幅图像连接到framebuffer; 所有关联的图像有相同width和height; 所有关联的图像内部格式的组合不违反实现相关的约束;
enum CheckFramebufferStatus( enumtarget ); //检查framebuffer是否完整, target=FRAMEBUFFER
4.4.6 framebuffer状态有关的值 FRAMEBUFFER_BINDING
4.4.7 像素和关联图像元素的映射 R,G,B,A分量转化为关联图像的内部格式。ColorMask, DepthMask, StencilMask, StencilMaskSeperate依然有效。
4.4.8 Errors
|