写入 OpenGL 模板缓冲区
Writing to the OpenGL Stencil Buffer
我一直在阅读有关 OpenGL 中的模板缓冲区的信息。基本概念是有道理的;只有在与模板缓冲区中的值按位与运算后满足特定条件时,才会绘制片段。但是我不明白的一件事是你实际上是如何写入模板缓冲区的。是否有我在这里缺少的功能?
P.S。当我说写入时,我的意思是在模板缓冲区中指定具体值。
我描述了。无论 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);
没有人回答这个问题,这是一个有效的问题,所以一年多后,这里是你问题的答案。
stencil buffer理论上和back buffer、depth buffer一样是一个buffer。他们三个被同时写入(启用时)。您可以 enable/disable 通过特定的电话给他们写信:
- glColorMask(red, green, blue, alpha) - 用于后台缓冲区
- glDepthMask(t/f) - 用于深度缓冲区
- glStencilMask(value) - 用于模板缓冲区
对于深度和模板缓冲区,您可以具体 enable/disable 进一步:
- 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 很重要,否则会测试模板缓冲区中的当前值(在示例中已清除)与上次使用的内容相反,您的遮罩几何图形甚至可能根本无法绘制。
所以没有特殊的函数可以写入模板缓冲区。我什至不确定它是否可以像您可以将数据直接写入后台缓冲区和深度缓冲区视频内存一样写入,但这不是应该这样做的方式(因为它非常慢)。模板缓冲区与深度缓冲区共享内存,因此可以通过更改写入函数的参数来实现。不过,我不会指望它适用于所有视频驱动程序。
祝所有需要此信息的人好运!
您可以将值(字节、浮点数、双字...)读取、写入和复制到帧和深度缓冲区,但不能读取到模板缓冲区。
所有三个缓冲区都位于 GPU 内存中问题是模板缓冲区使用了 24 位深度缓冲区中剩余的 8 位!
这就是为什么您必须渲染一些东西来设置或覆盖 8 位模板缓冲区中的值(实际上是深度缓冲区中的一个区域)
DJ
我一直在阅读有关 OpenGL 中的模板缓冲区的信息。基本概念是有道理的;只有在与模板缓冲区中的值按位与运算后满足特定条件时,才会绘制片段。但是我不明白的一件事是你实际上是如何写入模板缓冲区的。是否有我在这里缺少的功能?
P.S。当我说写入时,我的意思是在模板缓冲区中指定具体值。
我描述了
遮罩在 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);
没有人回答这个问题,这是一个有效的问题,所以一年多后,这里是你问题的答案。
stencil buffer理论上和back buffer、depth buffer一样是一个buffer。他们三个被同时写入(启用时)。您可以 enable/disable 通过特定的电话给他们写信:
- glColorMask(red, green, blue, alpha) - 用于后台缓冲区
- glDepthMask(t/f) - 用于深度缓冲区
- glStencilMask(value) - 用于模板缓冲区
对于深度和模板缓冲区,您可以具体 enable/disable 进一步:
- 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 很重要,否则会测试模板缓冲区中的当前值(在示例中已清除)与上次使用的内容相反,您的遮罩几何图形甚至可能根本无法绘制。
所以没有特殊的函数可以写入模板缓冲区。我什至不确定它是否可以像您可以将数据直接写入后台缓冲区和深度缓冲区视频内存一样写入,但这不是应该这样做的方式(因为它非常慢)。模板缓冲区与深度缓冲区共享内存,因此可以通过更改写入函数的参数来实现。不过,我不会指望它适用于所有视频驱动程序。
祝所有需要此信息的人好运!
您可以将值(字节、浮点数、双字...)读取、写入和复制到帧和深度缓冲区,但不能读取到模板缓冲区。
所有三个缓冲区都位于 GPU 内存中问题是模板缓冲区使用了 24 位深度缓冲区中剩余的 8 位!
这就是为什么您必须渲染一些东西来设置或覆盖 8 位模板缓冲区中的值(实际上是深度缓冲区中的一个区域)
DJ