17.4 OpenGL将片段和样本写入帧缓冲区:整个帧缓冲区操作

本文详细解释了OpenGL中的帧缓冲操作,涉及DrawBuffer和DrawBuffers函数,颜色、深度和模板缓冲区的控制,以及清除、多重采样缓冲和帧缓冲区内容的无效化。这些功能对渲染性能和效果有着重要影响。
摘要由CSDN通过智能技术生成

整个帧缓冲区操作 Whole Framebuffer Operations

本节描述控制或影响整个帧缓冲区的操作。

选择缓冲区写入 Selecting Buffers for Writing

控制将每个片段颜色值写入的颜色缓冲区
void glDrawBuffer( enum buf );
void glNamedFramebufferDrawBuffer( uint framebuffer, enum buf );
  • DrawBuffer 帧缓冲对象是绑定到 DRAW_FRAMEBUFFER 的帧缓冲对象。
  • NamedFramebufferDrawBuffer 帧缓冲对象可以是零或帧缓冲对象的名称。如果帧缓冲对象为零,则受影响的是默认绘制帧缓冲区。

如果受影响的是默认帧缓冲区,则 buf

  • NONE
  • FRONT_LEFT
  • FRONT_RIGHT
  • BACK_LEFT
  • BACK_RIGHT
  • FRONT
  • BACK
  • LEFT
  • RIGHT
  • FRONT_AND_BACK

如果受影响的是帧缓冲对象,则 buf

  • NONE:No buffer
  • COLOR_ATTACHMENTi:帧缓冲区上特定的附着点上的图像
指定帧缓冲对象(Framebuffer Object, FBO)的绘制缓冲区,从而确定渲染过程中片段颜色写入的位置
void glNamedFramebufferDrawBuffers( uint framebuffer, sizei n, const enum *bufs );
  • framebuffer: 指定帧缓冲对象的名称。如果值为0,则表示影响默认帧缓冲。
  • n: 表示数组 bufs 中缓冲区的数量。
  • bufs: 一个指向枚举值数组的指针,这些值分别对应于每个片段颜色将被写入的缓冲区。
    • 对于影响默认帧缓冲的情况,则为 { NONE、FRONT_LEFT、FRONT_RIGHT、BACK_LEFT、BACK_RIGHT } 或者特殊值 BACK。当使用 BACK 时,n 必须为1,并且颜色值在单缓冲环境下写入左缓冲,在双缓冲环境下写入后置左缓冲。
    • 如果影响的是帧缓冲对象,则为 { NONE、COLOR_ATTACHMENTi }。

在两种情况下,所定义的绘制缓冲区与相应的片段颜色一一对应。当超过 n 个片段颜色时,剩余的颜色对应的绘制缓冲区设置为 NONE

实现支持的最大绘制缓冲区数量取决于硬件和驱动程序,可以通过调用 GetIntegerv 函数查询 MAX_DRAW_BUFFERS 参数来获取支持的最大数量。

另外,除了 NONE 外,数组 bufs 指向的任何缓冲区不得重复出现。

如果片段着色器写入用户定义的输出变量,则 DrawBuffers 指定一组绘制缓冲区,这些变量定义的多种输出颜色中的每一种都会单独写入其中。 如果片段着色器未写入用户定义的输出变量,则着色器执行后的片段颜色值是未定义的,并且每个片段颜色可能不同。 如果写入了一些(但不是全部)用户定义的输出变量,则与未写入的变量对应的片段颜色的值同样未定义。

写入用户定义的输出变量的顺序未定义。 如果同一图像附加到帧缓冲区对象的多个附加点,并且将不同的值写入到绑定到这些附件的输出,则附加图像中的结果值是未定义的。 类似地,在任何其他每片段操作期间都会导致未定义的行为,其中多重附加图像可能会被多个输出写入,例如在混合期间。


DrawBufferDrawBuffers 函数是用来指示OpenGL在后续的像素颜色值写入操作中影响哪些缓冲区的。当这些函数作用于帧缓冲对象(Framebuffer Object, FBO)时,如果设置的绘制缓冲区选择了一个尚未附加图像的附件,那么相应的片段颜色将不会被写入。

指定 NONE 作为片段颜色的绘制缓冲区意味着阻止该片段颜色的写入。在单眼(monoscopic)渲染场景下,只包含左眼视图的缓冲区;而在双眼(stereoscopic)渲染场景下,则同时包含左右眼视图的缓冲区。同样地,在单缓冲(single buffered)上下文中,仅包括前缓冲(front buffer),而在双缓冲(double buffered)上下文中,则包含前后两个缓冲。

默认帧缓冲(default framebuffer)的初始状态是这样的:

  • 如果存在后缓冲(back buffer),则片段颜色0的绘制缓冲区设为 BACK
  • 若无后缓冲,则设为 FRONT
  • 如果当前上下文未关联任何默认帧缓冲,则设为 NONE

对于帧缓冲对象(FBO),初始状态下片段颜色0的绘制缓冲区设置为 COLOR_ATTACHMENT0。对于默认帧缓冲和帧缓冲对象而言,除片段颜色0以外的其他片段颜色的初始绘制缓冲区状态均为 NONE

可以通过调用 GetIntegerv 函数并设置参数 pnameDRAW_BUFFERi 来查询当前绑定为绘图目标的帧缓冲所选中的第i个片段颜色的绘制缓冲区。其中,DRAW_BUFFER 等价于 DRAW_BUFFER0,通常用于查询第一个颜色附件的绘制缓冲区设置。

缓冲区更新的精细控制 Fine Control of Buffer Updates

控制颜色缓冲区写入掩码
void glColorMask( boolean r, boolean g, boolean b, boolean a );
void glColorMaski( uint buf, boolean r, boolean g, boolean b, boolean a );
  • 参数 r、g、b 和 a 分别代表红色、绿色、蓝色和阿尔法通道是否允许写入。

要查询特定索引i的绘制缓冲区的颜色写入掩码(决定哪些颜色分量可以被写入),可以调用glGetBooleani_v函数,并设置targetGL_COLOR_WRITEMASK以及指定index i。若要查询默认绘制缓冲区(通常是索引0)的颜色写入掩码,则可通过glGetBooleanv函数,其中pname设为GL_COLOR_WRITEMASK

启用或禁用深度缓冲区对深度值的写入
void glDepthMask( boolean mask );
控制向模板缓冲区特定位的写入
void glStencilMask( uint mask );
void glStencilMaskSeparate( enum face, uint mask );
  • mask 的最低有效位(数量等于模板缓冲区的位数)组成一个整数掩码。掩码中的每一位对应模板缓冲区的一位。
  • face 可以是 GL_FRONTGL_BACKGL_FRONT_AND_BACK,表示所影响的是前面板、后面板还是同时影响两者。

在渲染过程中,由前向基本体生成的片段使用前面板的模板掩码,后向基本体生成的片段则使用后面板的模板掩码(详情参见17.3.3节)。

清除操作(Clear operation)在清除模板缓冲区时始终使用前面板的模板写入掩码。

当 SAMPLE_BUFFERS 的值为 1 时,ColorMask、DepthMask 和 StencilMask 或 StencilMaskSeparate 控制多重采样缓冲区中值的修改。 颜色遮罩对颜色缓冲区的修改没有影响。如果完全禁用颜色遮罩,则仍必须组合颜色样本值(如上所述),并将结果用于替换 DrawBuffer 启用的缓冲区的颜色值。

清除缓冲区 Clearing the Buffers

清空特定缓冲区
void glClear( bitfield buf );
  • COLOR_BUFFER_BIT : 清除值通过 glClearColor() 设置
  • DEPTH_BUFFER_BIT : 清除值通过 glClearDepth() 设置
  • STENCIL_BUFFER_BIT : 清除值通过 glClearStencil() 设置
void glClearColor( float r, float g, float b, float a );
void glClearDepth( double d );
void glClearDepthf( float d );
void glClearStencil( int s ); // `s`会被掩码处理。

初始化状态下,颜色缓冲区、深度缓冲区以及模板缓冲区各自的清除值如下:

  • RGBA颜色缓冲区的清除值为 (0.0, 0.0, 0.0, 0.0)。
  • 深度缓冲区的清除值为 1.0。
  • 模板缓冲区的清除索引为 0。
清除帧缓冲对象的不同部分,包括颜色缓冲、深度缓冲和模板缓冲
void glClearBuffer{if ui}v( enum buffer, int drawbuffer, const T *value );
void glClearNamedFramebuffer{if ui}v( uint framebuffer, enum buffer, int drawbuffer, const T *value );
  • 清除颜色缓冲:
    • 当指定 buffer 为 COLOR 时,通过 drawbuffer 参数来选择绘制缓冲区。清除值由 value 指向的四元素向量(R, G, B, A)决定。
    • glClearBufferfv(buffer, drawbuffer, value);
    • glClearBufferiv(buffer, drawbuffer, value);
    • glClearBufferuiv(buffer, drawbuffer, value);
  • 清除深度缓冲:
    • 当 buffer 设为 DEPTH,drawbuffer 必须是 0,表示对整个深度缓冲执行清除操作。
    • glClearBufferfv(GL_DEPTH, 0, value);
  • 清除模板缓冲:
    • 当 buffer 等于 STENCIL 时,drawbuffer 是 0,针对整个模板缓冲执行清除。
    • 对于 ClearBuffer* 函数,其作用于当前绑定的绘图帧缓冲;而对于 ClearNamedFramebuffer* 函数,可以明确指定帧缓冲对象的名字,甚至可以选择默认的绘图帧缓冲(通过传入0)。
    • glClearBufferiv(GL_STENCIL, 0, value);
同时清除帧缓冲对象的深度和模板缓冲区
void glClearBufferfi( enum buffer, int drawbuffer, float depth, int stencil );
void glClearNamedFramebufferfi( uint framebuffer, enum buffer, int drawbuffer, float depth, int stencil );
  • buffer: 必须设置为 GL_DEPTH_STENCIL,表示将同时清除深度和模板组件。
  • drawbuffer: 必须设为零,因为此处默认清空整个深度-模板缓冲。
  • depth: 深度缓冲区要清除到的值;此值若有必要会进行裁剪,类似于使用 glClearDepth 时的操作。
  • stencil: 模板缓冲区要清除到的值;应用与 glClearStencil 相同的掩码规则。
  • framebuffer:明确指定帧缓冲对象的名字,甚至可以选择默认的绘图帧缓冲(通过传入0)。

清除多重样本缓冲区 Clearing the Multisample Buffer

清除操作会根据指定的清除掩码对多重采样缓冲中的颜色、深度或模板样本进行相应的清除:

  1. 当设置了 COLOR_BUFFER_BIT 并且绘图缓冲模式不是 NONE 时,会清除多重采样的颜色样本。
  2. 若设置了 DEPTH_BUFFER_BITSTENCIL_BUFFER_BIT,则会分别清除深度和模板样本。

Clear*Buffer* 命令不仅适用于单个常规缓冲区的清除,也同样适用于与之关联的多重采样缓冲。

此外,遮罩(Masking)和裁剪区域(Scissoring)的规定同样适用于对多重采样缓冲的清除操作,这意味着只有符合这些限制条件的缓冲样本才会被实际清除。

使帧缓冲区内容无效 Invalidating Framebuffer Contents

void glInvalidateSubFramebuffer( enum target, sizei numAttachments, const enum *attachments, int x, int y, sizei width, sizei height );
void glInvalidateNamedFramebufferSubData( uint framebuffer, sizei numAttachments, const enum *attachments, int x, int y, sizei width, sizei height );
  • target: 指定要操作的目标帧缓冲;必须是DRAW_FRAMEBUFFER、READ_FRAMEBUFFER之一,或者直接使用FRAMEBUFFER,它等同于DRAW_FRAMEBUFFER。
  • framebuffer: 帧缓冲对象的ID。如果设置为零,则影响默认的绘制帧缓冲。
  • numAttachments: 表示attachments数组中附件数量的参数。
  • attachments: 包含了要无效化的附件类型,如GL_COLOR_ATTACHMENT0GL_DEPTH_ATTACHMENTGL_STENCIL_ATTACHMENT等。
  • x, y: 要失效矩形左下角的坐标。
  • width, height: 矩形的宽度和高度。
void glInvalidateFramebuffer( enum target, sizei numAttachments, const enum *attachments );

// 等价于 

glInvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, vw, vh);
void glInvalidateNamedFramebufferData( uint framebuffer, sizei numAttachments, const enum *attachments );

// 等价于 

glInvalidateNamedFramebufferSubData(framebuffer, numAttachments, attachments, 0, 0, vw, vh);

其中 vwvh 分别等于通过查询 MAX_VIEWPORT_DIMS 获得的最大视口宽度和高度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值