第四章 颜色、像素和帧缓存
缓存以及用途
OpenGL包含以下三种缓存:
- 一个或者多个颜色缓存(color buffer)
- 深度缓存(depth buffer)
- 模板缓存(stencil buffer)
缓存的清除
设置缓存清除值
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void glClearDepth(GLclampd depth);
void glClearDepthf(GLclampf depth);
void glClearStencil(GLint s);
GLclamp*类型会被截断到0.0~1.0之间。默认的深度清除值是1.0,其他的都是0。
清除缓存
void glClear(GLbitfield mask);
mask可以使GL_COLOR_BUFFER_BIT, GL_DPETH_BUFFER_BIT或GL_STENCIL_BUFFER_BIT的组合。
缓存的掩码
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void glColorMaski(GLuint buffer, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void glDepthMask(GLboolean flag);
void glStencilMask(GLboolean mask);
void glStencilMaskSeparate(GLenum face, GLuint mask);
如果设置为GL_TRUE则可以写入,否则不能写入。
颜色的表达与OpenGL
最通常情况下,OpenGL内部会使用浮点数来标识一个颜色分量,并且这些值总是要限制在[0.1, 1.0]之间称为归一化数值。颜色被写入到帧缓存之后,会被映射到帧缓存所支持的数据范围之内,例如红绿蓝分量都有8位,那么最后颜色分量的区间范围是[0, 255]。
多重采样
使用glGetIntegerv()函数来检查GL_SAMPLE_BUFFERS来判断是否请求成功,如果为1则可以使用多重采样光栅化的方法。
使用glGetIntegerv()函数来获取GL_SAMPLES,返回每个像素有多少样本用于实现多重采样
获取采样点在像素内的位置
void glGetMultisamplefv(GLenum pname, GLuint index, GLfloat* val);
设置pname为GL_SAMPLE_POSITION获取第index个采样点在像素内的便宜位置。在片元着色器内使用gl_SamplePosition获取相同的信息。可以使用gl_SampleID来判断所处的样本。
如果只开启多重采样,那么每个像素的颜色值会分配给所有采样点,也就是所有颜色都是相同的,但经过光栅化之后会有不同的深度与模板值。如果片元着色器中使用了gl_Sample*变量或者用sample关键字限定了输入变量,那么片元着色器会在一个像素上执行多次,每个样本位置都会有不同的信息。
如果不通过以上方法修改片元着色器,也可以通过glEnable()启动GL_SAMPLE_SHADING强制OpenGL使用采样着色的方式。
控制样本数量
void glMinSampleShading(GLfloat value);
设置每个像素种独立着色的样本值数量,value表示一个比例,取值范围是[0,1],1表示所有样本都会使用唯一一组采样数据。
片元的测试与操作
剪切测试
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
设置剪切矩形的位置与大小。首先需要glEnable()设置GL_SCISSOR_TEST来开启测试,如果开启那么所有的渲染包括窗口的清除都会被限制在剪切盒区域内。
多重采样的片元操作
默认情况下,多重采样在计算覆盖率时不会考虑alpha的影响,如果要考虑alpha那么需要使用glEnable开启:
GL_SAMPLE_ALPHA_TO_CONVERAGE 使用片元的alpha值来计算采样覆盖率
GL_SAMPLE_ALPHA_TO_ONE 将片元alpha值设为最大的alpha值,然后使用该值来进行覆盖率的计算
GL_SAMPLE_COVERAGE 将使用glSampleCoverage()中设置的值,预覆盖率计算的结果进行与操作。
void glSampleCoverage(GLfloat value, GLboolean invert);
设置多重采样覆盖率的参数,如果开启GL_SAMPLE_ALPHA_TO_CONVERAGE或GL_SAMPLE_COVERAGE,那么value是一个临时的采样覆盖率值。invert用来设置这个临时覆盖值是否需要进行位反转,然后进行与操作。
GL_SAMPLE_MASK 设置一个掩码值来计算覆盖率。
void glSampleMaski(GLuint index, GLbitfield mask);
设置一个32位的mask,掩码本身的索引位置通过index来设置,而新的掩码值通过mask来设置。当采样结果准备写入帧缓存时,只有当前掩码值中对应位的数据才会被更新,其他的被丢弃。
也可以通过片元着色器中写入gl_SampleMask来设置。
模板测试
要开启深度测试需要调用glEnable()并传入GL_STENCIL_TEST
void glStencilFunc(GLenum func, GLint ref, GLuint mask);
void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
void glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
深度测试
要开启深度测试需要调用glEnable()并传入GL_DEPTH_TEST,每次重绘场景时都要清除深度缓存数据。
设置深度测试比较函数
void glDepthFunc(GLenum func);
可以使用的枚举类型包括:GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER或GL_NOTEQUAL。默认使用GL_LESS。
多边形偏移
启用多边形偏移的方法有三种:GL_FILL、GL_LINE和GL_POINT,对应的可以使用glEnable传入GL_POLYGON_OFFSET_FILL、GL_POLYGON_OFFSET_LINE和GL_POLYGON_OFFSET_POINT。
设置当前多边形光栅化方式
void glPolygonOffset(GLfloat factor, GLfloat units);
开启之后,每个片元的深度值都会被修改,在执行深度测试之前添加一个偏移量:
o f f s e t = m ∗ f a c t o r + r ∗ u n i t s offset = m * factor + r * units offset=m∗factor+r∗units
其中m是多边形的最大深度斜率(光栅化计算过程中得到),r是两个不同深度值之间的、可识别的最小差值,是一个与平台相关的常量。两个参数都可以是负数。
深度斜率表示如图:
计算公式:
m = ( ∂ z ∂ x ) 2 + ( ∂ z ∂ y ) 2 或 者 m = m a x ( ∂ z ∂ x , ∂ z ∂ y ) m = \sqrt{(\frac{\partial z}{\partial x})^2+(\frac{\partial z}{\partial y})^2} \\ \\ 或者 m = max(\frac{\partial z}{\partial x}, \frac{\partial z}{\partial y}) m=(∂x∂z)2+(∂y∂z)2或者m=max(∂x∂z,∂y∂z)
混溶
要开启混溶需要调用glEnable()并传入GL_BLEND
混溶参数
( S r , S g , S b , S a ) (S_r, S_g, S_b, S_a) (Sr,Sg,Sb,Sa)表示源混合参数, ( D r , D g , D b , D a ) (D_r, D_g, D_b, D_a) (Dr,Dg,Db,Da)表示目标混合参数, ( R s , G s , B s , A s ) (R_s, G_s, B_s, A_s) (Rs,Gs,Bs,As)和 ( R d , G d , B d , A d ) (R_d, G_d, B_d, A_d) (Rd,Gd,Bd,Ad)表示源和目标像素的颜色值。最终颜色值为:
( S r R s + D r R d , S g G s + D g G d , S b B s + D b B d , S a A s + D a A d ) (S_rR_s+D_rR_d, S_gG_s+D_gG_d, S_bB_s+D_bB_d, S_aA_s+D_aA_d) (SrRs+DrRd,SgGs+DgGd,SbBs+DbBd,SaAs+DaAd)
其中源混合参数对应片元着色器的输出颜色,目标混合参数对应帧缓存中已有的颜色
设置混溶参数
void glBlendFunc(GLenum srcfactor, GLenum destfactor);
void glBlendFunci(GLuint buffer, GLenum srcfactor, GLenum destfactor);
对于无符号和有符号的归一化帧缓存格式,混溶参数将分别限制在[0, 1]或者[-1, 1]的区间。如果采用浮点数那么不存在上下限。
void glBlendFuncSeparate(GLenum srcRGB, GLenum destRGB, GLenum srcAlpha, GLenum destAlpha);
void glBlendFuncSeparatei(GLuint buffer, GLenum srcRGB, GLenum destRGB, GLenum srcAlpha, GLenum destAlpha);
可以使用的参数:
如果使用GL_CONSTANT_COLOR那么需要使用:
void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
来设置对应常量的颜色值。
如果设置GL_ONE作为源参数,GL_ZERO作为目标参数,那么与禁止混溶效果是一样的。
逐缓存混溶设置可以使用glEnablei()和glDisablei()来开启跟关闭。
混溶方程
void glBlendEquation(GLenum mode);
void glBlendEquationi(GLuint buffer, GLenum mode);
设置帧缓存和源数据之间混合的方法。mode可以使用:
混溶模式参数 | 数学操作 |
---|---|
GL_FUN_ADD(默认值) | C s S + C d D C_sS+C_dD CsS+CdD |
GL_FUN_SUBTRACT | C s S − C d D C_sS-C_dD CsS−CdD |
GL_FUN_REVERSE_SUBTRACT | C d D − C s S C_dD-C_sS CdD−CsS |
GL_MIN | m i n ( C s S , C d D ) min(C_sS,C_dD) min(CsS,CdD) |
GL_MAX | m a x ( C s S , C d D ) max(C_sS,C_dD) max(CsS,CdD) |
其中 C s C_s Cs和 C d C_d Cd分别表示源和目标的颜色, S S S和 D D D表示源融混参数和目标融混参数。
void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
void glBlendEquationSeparatei(GLuint buffer, GLenum modeRGB, GLenum modeAlpha);
逻辑操作
要开启逻辑操作罗需要调用glEnable()并传入GL_COLOR_LOGIC_OP。
void glLogicOp(GLenum opcode);
对于源(s)跟目标(d)之间进行逻辑操作,默认为GL_COPY
遮挡查询
遮挡查询是在深度测试之后完成的。
遮挡查询的步骤:
- 为每个需要的遮挡查询对象生成一个ID
- 调用glBeginQuery()开始遮挡查询
- 渲染几何体以完成测试
- 调用glEndQuery()完成遮挡查询
- 获取通过深度测试的样本数
为了提高效率,需要禁止所有渲染模式。
生成查询对象
void glGenQueries(GLsizei n, GLuint * ids);
GLboolean glIsQuery(GLuint id);
启用遮挡查询
void glBeginQuery(GLenum target, GLuint id);
target必须是GL_SAMPLES_PASSED、GL_ANY_SAMPLES_PASSED或者GL_ANY_SAMPLES_PASSED_CONSERVATIVE。
结束遮挡查询
void glEndQuery(GLenum target);
查询方法:
glBeginQuery(GL_SAMPLES_PASSED, Query);
glDrawArrays(GL_TRIANGLES, 0, 3);
glEndQuery(GL_SAMPLES_PASSED);
判断结果
void glGetQueryObjectiv(GLenum id, GLenum pname, GLint* params);
void glGetQueryObjectuiv(GLenum id, GLenum pname, GLuint* params);
id是查询物体名称,如果pname是GL_QUERY_RESULT那么通过深度测试的片元的数量将被写入params中,如果返回0那么全部被挡住了。
查询结果可能会有一些延迟,可以首先通过查询GL_QUERY_RESULT_AVAIABLE,如果id已经可以查询那么params中会被写入GL_TRUE,否则GL_FALSE
释放查询对象
void glDeleteQueries(GLsizei n, const GLuint* ids);
条件渲染
如果遮挡查询的过程中,需要将查询结果返回应用程序,此时图形硬件设备会停止工作,为了避免这个问题,硬件可以使用条件渲染来使用遮挡查询。
void glBeginConditionalRender(GLuint id, GLenum mode);
void glEndConditionalRender(void);
其中id为查询对象id,mode为如何使用遮挡查询结果可以是:
mode | 意义 |
---|---|
GL_QUERY_WAIT | GPU等待查询结果然后判断是否继续渲染 |
GL_QUERY_NO_WAIT | GPU不等待查询结果。如果没有返回,那么它将选择条件渲染区域内的一部分场景进行渲染 |
GL_QUERY_BY_REGION_WAIT | GPU判断片元的结果是否对条件渲染有所贡献,并等待这些结果渲染完成。同时等待遮挡查询结果返回 |
GL_QUERY_BY_REGION_NO_WAIT | GPU将会抛弃帧缓存中所有对遮挡查询没有贡献的区域,并且即使结果还没有返回,它也会开始渲染其它区域的内容 |
如果在条件渲染队列已经开始执行时再次调用glBeginConditionalRender或者在条件渲染没有启动的时候调用glEndConditionalRender或者id对应的遮挡查询对象没有被设置为GL_SAMPLES_PASSED以外的模式,或者id对应的遮挡查询对象正在查询中,都会产生GL_INVALID_OPERATION。
glBeginConditionalRender(Query, GL_QUERY_WAIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, NumVertices);
glEndConditionalRender();
如果大部分的渲染操作并不会受到场景遮挡查询的结果影响的话,那么从整体上来说使用NO_WAIT形式要快一些。
逐图元的反走样
覆盖值的设定
void glHint(GLenum target, GLenum hint);
target的取值:
参数 | 描述 |
---|---|
GL_LINE_SMOOTH_HINT | 线的反走样质量 |
GL_POLYGON_SMOOTH_HINT | 多边形反走样质量 |
GL_TEXTURE_COMPRESSION_HINT | 纹理图像压缩的质量和性能 |
GL_FRAGMENT_SHADER_DERIVATIVE_HINT | 片元处理内置函数的导数精度,包括dFdx,fwidth |
hint的取值:
参数 | 描述 |
---|---|
GL_FASTEST | 效率最高 |
GL_NICEST | 质量最高 |
GL_DONT_CARE | 没有偏好 |
该函数是与平台相关的,有的实现里可能会完全忽略。
线段的反走样
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
多边形的反走样
和线段反走样类似,多边形反走样使用的是GL_POLYGON_SMOOTH。为了保证混融方式的恰当,可以设置混融参数为GL_SRC_ALPHA_SATURATE, GL_ONE。
帧缓存对象
程序创建的帧缓存对象只能用于离屏渲染,不能用于显示器的显示。而且窗口系统缓存在窗口创建时就有缓存对象:颜色深度和模板,而程序创建的帧缓存对象需要创建额外的真缓存对象,并与之关联。
创建帧缓存对象
void glGenFrameBuffers(GLsizei n, GLuint * ids);
绑定帧缓存对象
void glBindFrameBuffer(GLenum target, GLuint framebuffer);
如果target为GL_DRAW_FRAMEBUFFER,那么framebuffer设置的是绘制时的目标帧缓存,如果target设置为GL_READ_FRAMEBUFFER,那么framebuffer就是去读操作的源数据,如果target分为GL_FRAMEBUFFER,那么framebuffer所设置的帧缓存是可读可写的。如果framebuffer为0,那么绑定到窗口系统帧缓存
释放帧缓存对象
void glDeleteFramebuffers(GLsizei n, const GLuint * ids);
判断是否是帧缓存对象
GLboolean glIsFramebuffer(GLuint framebuffer);
设置帧缓存对象参数
void glFramebufferParameteri(GLenum target, GLenum pname, GLint param);
target必须是DRAW_FRAMEBUFFER READ_FRAMEBUFFER或FRAMEBUFFER。FRAMEBUFFER与DRAW_FRAMEBUFFER是等价的(书上没有加GL_前缀,感觉是写错了)。
pname必须是GL_FRAMEBUFFER_DEFAULT_WIDTH, GL_FRAMEBUFFER_DEFAULT_HEIGHT, GL_FRAMEBUFFER_DEFAULT_LAYERS, GL_FRAMEBUFFER_DEFAULT_SAMPLES或者GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS之一。
第一次调用会分配这个对象的存储空间并将其初始化。
渲染缓存
渲染缓存(renderbuffer)是OpenGL所管理的一处高效的内存区域,它可以储存格式化的图像数据。渲染缓存需要关联到一个帧缓存对象才有意义,需要保证图像缓存的格式必须与OpenGL所要求的格式一致。
创建渲染缓存
void glGenRenderBuffers(GLsizei n, GLuint * ids);
释放渲染缓存
void glDeleteRenderbuffers(GLsizei n, const GLuint * ids);
判断是否是渲染缓存
void glIsRenderbuffer(GLuint renderbuffer);
绑定渲染缓存
void glBindRenderbuffer(GLenum target, GLuint renderbuffer);
target必须是GL_RENDERBUFFER。
创建渲染缓存的存储空间
void glRenderbufferStorage(GLenum target, GLenum interalformat, GLsizei width, GLsizei height);
void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
为当前绑定的渲染缓存分配图像数据空间。对于一个颜色信息,internalformat可以使用的值为:
如果作为深度缓存使用,那么internalformat可以使用的值为:GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32或者是GL_DEPTH_COMPONENT32F。
如果作为模板缓存使用,那么internalformat可以使用的值为:GL_STENCIL_INDEX, GL_STENCIL_INDEX1, GL_STENCIL_INDEX4, GL_STENCIL8或者GL_STENCIL_INDEX16。
对于压缩的深度模板格式,只能为GL_DEPTH_STENCIL。
width和height是渲染缓存像素大小。
samples设置逐像素多重采样的样本个数。
帧缓存附件
开始渲染时,渲染结果可以保存到以下地方:
- 如果使用多重渲染目标,则创建图像到颜色缓存,甚至多个颜色缓存。
- 将遮挡信息保存到深度缓存。
- 将逐像素的渲染掩码保存到模板缓存。
这些缓存类型都表示一种缓存附件,就是将对应的图像缓存直接附加到帧缓存之上。可用的帧缓存附件(framebuffer attachment)点:
附件名称 | 描述 |
---|---|
GL_COLOR_ATTACHMENTi | 第i个颜色缓存。i的范围[0, GL_MAX_COLOR_ATTACHMENTS) |
GL_DEPTH_ATTACHMENT | 深度缓存 |
GL_STENCIL_ATTACHMENT | 模板缓存 |
GL_DEPTH_STENCIL_ATTACHEMNT | 用于保存压缩后的深度-模板缓存 |
可以将这些附件关联到两种不同类型的渲染表面:渲染缓存和纹理图像的某个层级
渲染缓存关联到帧缓存对象
void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
target必须是GL_DRAW_FRAMEBUFFER GL_READ_FRAMEBUFFER或GL_FRAMEBUFFER。
attachment必须是上表列出的可用的帧缓存附件之一。
renderbuffertarget必须是GL_RENDERBUFFER。
帧缓存的完整性
GLenum glCheckFramebufferStatus(GLenum target);
返回信息:
清除独立缓存
void glClearBuffer{fi ui}v(GLenum buffer, GLint drawbuffer, const TYPE* value);
清除drawbuffer对应缓存中的数据,清除值为value,buffer必须是GL_COLOR, GL_DPETH或者GL_STENCIL之一。
void glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
buffer必须是GL_DEPTH_STENCIL。
帧缓存的无效化
void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments);
void glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
设置绑定的帧缓存对象的一部分或者整体将不再保留。
target必须是GL_DRAW_FRAMEBUFFER GL_READ_FRAMEBUFFER或GL_FRAMEBUFFER。
attachments必须是上表列出的可用的帧缓存附件。
numAttachments表示attachments中的附件数量。
多重渲染缓存的同步写入
帧缓存对象的多渲染缓存特性,也就是一个片元着色器中同时写入多个缓存的能力,也称为MRT(Multiple-Render Target)。
如果需要设置out变量与帧缓存附件之间的关系,只需要将layout限定符将变量直接设置到正确的位置即可。
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 norm;
OpenGL中指定片元着色器输出值与帧缓存附件之间的联系:
void glBindFragDataLocatoin(GLuint program, GLuint colorNumber, const GLchar* name);
void glBindFragDataLocationIndexed(GLuint program, GLuint colorNumber, GLuint index, const GLchar* name);
使用colorNumber的值来对应片元着色器的变量name,从而与着色器程序program的输出位置进行关联。对于颜色索引的情形,index 可以用来同时设置输出索引值和位置。
链接结束后,如果它们可用的话,则可以获取片元着色器的输出位置和变量了:
GLint glGetFragDataLocation(GLuint program, const GLchar* name);
GLint glGetFragDataIndex(GLuint program, const GLchar* name);
获取片元着色器变量name的位置或者索引。
着色器中的location设置优先级要高。
选择颜色缓存来进行读写操作
绘制或者读取操作的结果通常与以下几种颜色缓存的内容关联:
- 默认帧缓存中的前、后、左前、左后、右前、右后缓存
- 或者用户自定义帧缓存对象中的前缓存,或者是任意渲染缓存附件
设置写入缓存
void glDrawBuffer(GLenum mode)
设置可以写入或者清除操作的颜色缓存,同时禁止前一次glDrawBuffer()或者glDrawBuffers()所设置的缓存。
mode可以是GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_LEFT, GL_FRONT_RIGHT, GL_BACK_LEFT, GL_BACK_RIGHT, GL_NONE, GL_FRONT_AND_BACK, GL_COLOR_ATTACHMENTi。
如果当前绑定了一个帧缓存对象,且不是默认帧缓存对象,那么只能用GL_NONE或者GL_COLOR_ATTACHMENTi,否则产生GL_INVALID_ENUM错误。
默认情况下,mode为GL_BACK。
void glDrawBuffers(GLsizei n, const GLenum * buffers);
buffers只能接受GL_FRONT_LEFT, GL_FRONT_RIGHT, GL_BACK_LEFT, GL_BACK_RIGHT, GL_NONE几种类型(书上这么写的,我记得好像也可以使用GL_COLOR_ATTACHMENTi)。
如果要将双重缓冲窗口作为一个单缓冲窗口来使用,可以使用glDrawBuffer(GL_FRONT_AND_BACK)。
void glReadBuffer(GLenum mode);
设置用作像素读取的缓存,读取像素的函数包括glReadPixels(), glCopyTexImage*(), glCopyTexSubImage*()等。
mode与glDrawBuffer可以使用的类型相同。
开启关闭附件启用的功能
void glEnable(GLenum capability, GLuint index);
void glDisable(GLenum capability, GLuint index);
GLboolean glIsEnablei(GLenum capability, GLuint index);
双源混溶
当使用混溶参数GL_SRC1_COLOR, GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_COLOR, GL_ONE_MINUS_SRC1_ALPHA时,混合方程会使用第二个源的数据进行混合。
如果设置源参数为GL_SRC1_COLOR,目标参数为GL_ONE_MINUS_SRC1_COLOR那么混溶函数的本质就是片元着色器中建立一个逐通道的alpha计算机制。
如果设置源参数为GL_ONE,目标参数为GL_ONE_MINUS_SRC1_COLOR这样第一个颜色输入会直接加到帧缓存内容上,第二个颜色的输出可以用来减弱帧缓存数据:
R G B d s t = R G B s r c 0 + R G B s r c 1 ∗ R G B d s t RGB_{dst} = RGB_{src0}+RGB_{src1}*RGB_{dst} RGBdst=RGBsrc0+RGBsrc1∗RGBdst
这个称为乘加运算,例如如果使用有色高光来渲染半透明物体,那么可以将物体颜色写入second_output,高光写入first_output。
像素的读取和拷贝
void glReadPixels(GLint x, GLint y, GLsizei width, GLsiezi height, GLenum format, glEnum type, void * pixels);
从刻度取得帧缓存中读取像素数据,保存到pixels当中。
format表示读取像素数据元素的类型:
type用于指定每个元素的数据类型:
返回值的截断
void glClampColor(GLenum target, GLenum clamp);
控制浮点数和定点数缓存的颜色截断方式,如果target设置为GL_CLAMP_READ_COLOR则开启截断,如果clamp为GL_TRUE,那么颜色将被阶段到[0,1],否则不会被截断。
如果使用定点数与浮点数混合的方式,如果clamp设置为GL_FIXED_ONLY时,直接断定点数数据,而浮点数仍保留原始形式。
拷贝像素矩形
如果需要在一块缓存不同区域之间或者是不同帧缓存之间进行拷贝,需要使用glBlitFramebuffer。
void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield buffers, GLenum filter);
将矩形像素从刻度帧缓存的一出去与拷贝到可会知帧缓存的另一处区域中。
buffers可以通过位或的方式设置GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。
filter用于当两个区域大小不同是,进行插值的方法,可以使用GL_NEAREST和GL_LINEAR。
如果有多个颜色绘制缓存,那么每个缓存都会进行一次数据拷贝。
如果srcX1 < srcX0或者desX1 < destX0 那么会进行一次水平翻转。
如果源数据和目标数据类型不同,那么大多情况会进行数据的转换。但如果可读缓存是浮点数某个写入缓存不是或者可读缓存是有(无)符号整数,某个写入缓存不是,则会产生GL_INVALID_OPERTATION错误。
如果源缓存是多重采样,目标缓存不是那么所有样本会被总到单一的像素值并存入目标缓存,反之元数据将被拷贝多次已匹配所有的样本值。如果都是多重采样,那么如果采样数相同则直接拷贝,不同会产生GL_INVALID_OPERATION错误。