OpenGL 编程指南(第八版)学习笔记——4颜色 像素和帧缓存

OpenGL 编程指南(第八版)学习笔记——4颜色 像素和帧缓存

缓存及其用途

  • 所有图形程序的共同目标,在屏幕上绘制图像(或者绘制到屏幕的一处缓存中)。
  • 帧缓存(通常就是屏幕)是由矩形的像素数组组成的,每个像素都可以在图像对应的点上显示一块方形的颜色值。
  • 颜色缓存只是记录像素信息的多个缓存中的一个。实际上,一个像素可能会关联多个颜色缓存,也就是渲染缓存(renderbuffer)。
  • OpenGL系统中通常包含以下几种类型的缓存:
    • 一个或多个可用的颜色缓存(color buffer)
    • 深度缓存(depth buffer)
    • 模板缓存(stencil buffer)
  • 默认帧缓存总是会包含一个双重缓存(double-buffered)机制的颜色缓存。
颜色缓存
  • 双缓存机制:直接在窗口中显示的前置缓存(front-buffer),以及用来渲染新图像的后备缓存(back-buffer)。当执行交换缓存操作,如 glutSwapBuffers()

    注:只有默认帧缓存的主颜色缓存可以使用双重缓存的特性。

    GL还可以支持立体显示,即每个颜色缓存都会划分出左颜色缓存,右颜色缓存。

深度缓存
  • 深度缓存为每个像素保存一个深度值,它可以用来判断3位空间中物体的可见性。
  • 这里的深度! 是物体与观察者眼睛的距离,因此深度值较大的像素会被深度值较小的像素覆盖。
  • 深度缓存的特性也可以通过 “深度测试”(z-buffer)来改变。
模板缓存
  • 模板缓存用来限制屏幕特定区域的绘制。
  • 相当于一个ROI。或者说是一个带有孔洞花纹的硬纸板。

缓存的清除

  • 通常在渲染完一帧后,最常见的操作就是清除缓存。
  • 设置不同缓存的清除值
void glClearColor(GLclampf red,GLclamf green,GLclampf bule,GLclampf alpha);
void glClearDepth(GLclampd depth);
void glClearDepthf(GLclampf depth);
void glClearStencil(GLint s);
// GLclampf和GLclampd类型就是截断后的GLfloat和GLdouble,需要截断到0.0-1.0区间。
  • 在设置清除值之后,可以使用 glClear来执行清除操作
void glClear(GLbitfild mask);
// 清除特定的缓存。mask的值是以下几种枚举量之间按位或操作的结果。

缓存的掩码

  • 在GL向颜色、深度或者模板缓存中写入数据之前,可以对数据执行一次掩码操作。
// 设置用于写入不同缓存的掩码
// 先略过。

颜色与OpenGL

  • 片元着色器负责设置每个片元的颜色。
  • 有多种方式来完成这个操作。
    • 片元着色器可以不借助任何”外部”数据。比如:设置完成某个常量颜色值
    • 每个输入的顶点都会提供一个附加的颜色数据。
    • 颜色的补充 —— 不是具体的颜色值 —— 可以通过片元着色器中计算来生成颜色值。
    • 外部数据,例如数字图像等,也可以在片元着色器中引用,用于查找颜色值。这些数据保存在 纹理贴图 当中,并且需要用到纹理映射技术(texture mapping)。

颜色表达与OpenGL

  • OpenGL是如何使用颜色值的:
    • GL内部使用一个浮点数来组成一个像素的颜色。
    • 归一化数值 (normalized value)

顶点颜色

  • 颜色数据也必须保存到 顶点缓存对象VBO

光栅化

  • 光栅化的主要职责就是判断空间的哪个部分被几何体(点,线,三角形)覆盖。
  • 光栅化相当于一个片元生命的开始。

多重采样

  • 多重采样是一种对几何图元的边缘进行平滑的技术。通常叫做 反走样。
  • 多重采样的工作方式就是对每个像素的几何图元进行多次采样。此时,每个像素点不会只保存单个颜色值,而是记录多个样本值。

帧缓存对象

  • 通过帧缓存对象(frame buffer object),我们可以创建自己的帧缓存,并且将他们绑定到渲染缓存(render buffer),将数据拷贝的消耗最小化,同时对性能进行优化。
  • 帧缓存对象对下面几种技术非常有意义:
    • 离屏渲染技术;
    • 纹理贴图的更新;
    • 缓存乒乓技术(这是GPGPU当中用到的一种数据传输的方式);
  • 窗口系统的缓存 vs 自己创建的帧缓存
  • 分配一个程序创建的帧缓存对象:
void glGenFramebuffers(GLsizei n,GLuint* ids);
// 分配n个未使用的帧缓存对象的名称,并且存储在ids中。
  • 绑定帧缓存对象:
void glBindFramebuffer(GLenum target,GLuint framebuffer);
// 设置一个可读或者可写的帧缓存。
// target为 GL_DRAW_FRAMEBUFFER 绘制时的目标帧缓存。
// target为 GL_READ_FRAMEBUFFER 读取操作的数据源
// target为 GL_FRAMEBUFFER 可读读写
// 若 framebuffer为0! 表示将目标绑定到默认的窗口系统帧缓存,或者设置为一个glGenFramebuffers()所生产的帧缓存对象。
  • 释放程序分配的帧缓存
void glDeleteFramebuffers(GLsizei n,const GLuint *ids);
  • 判断是否是程序分配的帧缓存对象:
GLboolean glIsFramebuffer(GLuint framebuffer);
  • 设置帧缓存对象的参数。前提是帧缓存对象还没有进行关联,否则这些参数需要通过帧缓存附件来设置。
void glFramebufferParameteri(GLenum target,GLenum panme,GLint param);
  • 帧缓存对象创建之后,还有很多工作要完成。还需要指定一处空间用作绘制操作或者读取操作,这处空间称作 帧缓存附件(framebuffer attachment)

渲染缓存

  • 渲染缓存(renderbuffer)是OpenGL所管理的一处高效的内存区域,它可以存储格式化的图像数据。渲染缓存中的数据只有关联到一个帧缓存对象之后才有意义。
  • 创建新的渲染缓存时可以调用 glGenRenderBuffers() 函数。
void glGenRenderbuffers(GLsizei n,GLuint* ids);
  • 帧缓存对象经过绑定之后才可以修改自己的状态。
void glBindRenderbuffer(GLenum target,GLuint renderbuffer);
创建渲染缓存的存储空间
  • glBindRenderbuffer 第一次调用后,只是创建了一个所有状态均为默认值的渲染缓存,这时候它还没有分配存储空间来存储图像信息。
  • 分配存储空间并且设置图像格式。 glRenderbufferStorage或者 glRenderbufferStorageMultisample
void glRenderbufferStorage(GLenum target,GLenum internalformat,GLsizei width,GLsizei height); 
void glRenderbufferStorageMultisample(GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height);
  • 示例:创建一个256x256的RGBA颜色渲染缓存

    glGenRenderbuffers(1,&color);
    glBindRenderbuffer(GL_RENDERBUFFER,color);
    glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA,256,256);
    

帧缓存附件

  • 当开始渲染时,可以将渲染的结果保存到以下几个地方:
    • 如果使用多重渲染目标(multiple render target),则创建图像到颜色缓存,设置是多个颜色缓存
    • 将遮挡信息保存到深度缓存
    • 将逐像素的渲染掩码保存到模板缓存
  • 这些缓存类型都表示了一种帧缓存的附件。
附件名称描述
GL_COLOR_ATTACHMENTi第i个颜色缓存。i从0开始
GL_DEPTH_ATTACHMENT深度缓存
GL_STENCIL_ATTACHMENT模板缓存
GL_DEPTH_STENCIL_ATTACHMENT特殊的附件类型。用于保存压缩后的深度-模板缓存
  • 将渲染缓存关联到帧缓存对象的情形:
  • 使用glFramebufferRenderbuffer
void glFramebufferRenderbuffer(GLenum target,GLenum attachment,GLenum renderbuffertarget,GLuint renderbuffer);
// 将渲染缓存renderbuffer关联到当前绑定的帧缓存对象的附件attachment上。
  • 帧缓存的完整性:
    • 调用 glCheckFramebufferStatus() 函数来检查

选择颜色缓存来进行读写操作

  • glDrawBuffer() 或者 glDrawBuffers() 来选择要写入的缓存
  • glReadBuffer() 来选择读取用的缓存,并作为 glReadPixels()、glCopyTexImage*()和glCopyTexSubImage*()等函数的数据源

像素数据的读取与拷贝

  • 当渲染工作结束之后,我们可以需要获取渲染后的图像作他用。这种情形下可以使用 glReadPixels() 函数读取帧缓存中的像素。
  • 然后将像素返回到应用程序中。可以分配一处内存空间来保存返回的像素。

拷贝像素矩阵

  • 如果需要在一块缓存的不同区域进行拷贝,或者在不同的帧缓存之间进行拷贝。
  • 可以使用 glBItFramebuffer 函数。
void glBlitFramebuffer(GLint srcX0,GLint srcY0,GLint srcX1,GLint stcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield buffers,GLenum filter);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值