写入OpenGL模板缓冲区

时间:2018-01-14 02:54:40

标签: c++ opengl glfw stencil-buffer

我一直在阅读OpenGL中的模板缓冲区。基本概念是有道理的;如果片段在与模板缓冲区中的值进行按位AND运算后满足某个条件,则仅绘制片段。但有一点我不明白你是如何写入模板缓冲区的。我有什么功能吗?

P.S。当我说写时,我的意思是指定模板缓冲区中的特定值。

3 个答案:

答案 0 :(得分:1)

没有人回答这个问题,这是一个有效的问题,所以一年多以后,这是您的问题的答案。

模板缓冲区理论上是一个缓冲区,例如后缓冲区和深度缓冲区。将它们中的三个同时写入(启用时)。您可以通过特定的呼叫来启用/禁用对它们的写入:

  • glColorMask(红色,绿色,蓝色,alpha)-用于后缓冲区
  • glDepthMask(t / f)-用于深度缓冲区
  • glStencilMask(value)-用于模具缓冲区

对于深度和模板缓冲区,您可以使用以下方法专门启用/禁用:

  • glEnable / glDisable(GL_DEPTH_TEST)
  • glEnable / glDisable(GL_STENCIL_TEST)

除非某些操作功能阻止,否则渲染到屏幕上的任何三角形都会写入所有启用的缓冲区。对于模板缓冲区,可以使用多种功能进行设置。请在OpenGL参考页上查找功能,但这是一个简单的示例,它遮盖了屏幕的一部分,然后仅在屏幕上被遮盖的部分进行渲染,只是为了让您入门。

glClearColor(0, 0, 0, 1);
glClearStencil(0);
glStencilMask(0xFF);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Do not draw any pixels on the back buffer
glEnable(GL_STENCIL_TEST); // Enables testing AND writing functionalities
glStencilFunc(GL_ALWAYS, 1, 0xFF); // Do not test the current value in the stencil buffer, always accept any value on there for drawing
glStencilMask(0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); // Make every test succeed

// ... here you render the part of the scene you want masked, this may be a simple triangle or square, or for example a monitor on a computer in your spaceship ...

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Make sure you will no longer (over)write stencil values, even if any test succeeds
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Make sure we draw on the backbuffer again.

glStencilFunc(GL_EQUAL, 1, 0xFF); // Now we will only draw pixels where the corresponding stencil buffer value equals 1

// ... here you render your image on the computer screen (or whatever) that should be limited by the previous geometry ...

glDisable(GL_STENCIL_TEST);

请注意,我故意省略了任何深度代码,以确保您看到它与模板无关。如果渲染3D几何,则可能需要启用它。如果深度测试失败,您甚至不需要写模板值。

请注意,在渲染蒙版几何时,将模板功能设置为GL_ALWAYS是很重要的,因为否则,将针对模板缓冲区中的当前值(在示例中已清除)进行测试,以对照上一次使用的值和您的蒙版几何图形甚至根本无法绘制。

因此,没有特殊功能可写入模板缓冲区,与其他缓冲区没有什么不同。当然,您确实可以将像素数据发送到图形内存,但这并不是应该使用的方式(而且速度非常慢)。

任何需要此信息的人,祝你好运!

答案 1 :(得分:0)

您可以读取、写入和复制值(字节、浮点数、双字...)到帧和深度缓冲区,但不能到模板缓冲区。

所有三个缓冲区都位于 GPU 内存中,问题是模板缓冲区使用了 24 位深度缓冲区中剩余的 8 位!

这就是为什么你必须渲染一些东西来设置或覆盖 8 位模板缓冲区中的值(实际上是深度缓冲区中的一个区域)

DJ

答案 2 :(得分:-1)

我描述了how to render to a stencil buffer here using libGDX。无论OpenGL版本或平台如何,在OpenGL中应用掩码的过程都是相同的。

掩码在OpenGL中的工作原理

在OpenGL中创建蒙版的方法有很多,请注意在我之前的答案中创建蒙版的代码实际上使用了深度缓冲区。我可以以类似的方式使用模板缓冲区来实现相同的结果。

使用深度缓冲区,您可以通过以下方式应用蒙版:

初始化并配置深度测试

首先清除深度缓冲区并禁用渲染到颜色缓冲区:

glClearDepthf(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glColorMask(false, false, false, false);

接下来,指定缓冲区的条件,这告诉OpenGL如何渲染到深度缓冲区以创建掩码。你可以通过调用glDepthFunc来做到这一点(掩盖的区域应该是绘制形状的场景区域还是其他东西?for the different kinds of input to the depth function, see the Depth test section of this site

glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
// Your code to render the mask goes here

制作面具

启用缓冲区后,可以渲染要用于蒙版的形状的多边形。因为我们禁止写入颜色缓冲区,所以渲染的图像在屏幕上不可见,它会被渲染到深度缓冲区。深度缓冲区具有与颜色缓冲区相同的宽度和高度尺寸,但由0和1值组成。每个像素都应用深度测试,如果通过,则将值1放置在该位置的缓冲区中,否则相应位置的值为0.

启用颜色缓冲区,设置深度功能并渲染到场景

现在,您将OpenGL配置为渲染到颜色缓冲区并应用深度掩码,如下所示:

glColorMask(true, true, true, true);
glDepthMask(true);
glDepthFunc(GL_EQUAL);
// Your code to render the scene goes here

由于您启用了深度缓冲区,因此视口中的每个像素都将具有相应的0或1值。现在,另一个深度函数应用于每个像素的相应值,如果结果为真,则将像素渲染到屏幕。这里深度函数的选择决定了如何应用蒙版。

停用深度测试

要允许再次正常渲染场景,请禁用深度缓冲区,如下所示:

glDisable(GL_DEPTH_TEST);