【问题标题】:Writing to the OpenGL Stencil Buffer写入 OpenGL 模板缓冲区
【发布时间】:2018-06-23 02:22:28
【问题描述】:

我一直在阅读 OpenGL 中的模板缓冲区。基本概念是有道理的;只有在与模板缓冲区中的值进行按位与运算后满足特定条件时才会绘制片段。但我不明白的一件事是你实际上是如何写入模板缓冲区的。有没有我在这里缺少的功能?

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

【问题讨论】:

  • 写入模板缓冲区由写入 RGB 和/或深度的相同函数完成。这就是我向一位朋友解释的方式:模板测试测试在某种程度上类似于深度测试。您可以完全禁用它。您只能编写(无需测试)。您可以启用测试(并覆盖以防万一)。
  • @Scheff 如何写入模板缓冲区而不在颜色缓冲区中绘制任何内容?
  • @Scheff 没关系,我想我明白了
  • 我不确定您是否只能写入模板缓冲区。我刚刚查看了我们使用模板进行垂直/水平交错立体渲染的代码。 (模板缓冲区最初是用线/无线模式编写的,以将渲染限制为适当的偶数或奇数行/列。)我相信它也只会渲染 RGB,但您不会看到它。它被以下通过模板测试的渲染覆盖(在调用最终的glSwap() 之前)。

标签: c++ opengl glfw stencil-buffer


【解决方案1】:

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

模板缓冲区理论上是一个类似于后台缓冲区和深度缓冲区的缓冲区。同时写入其中三个(启用时)。您可以通过特定调用启用/禁用对它们的写入:

  • glColorMask(red, green, blue, 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 很重要,因为否则,模板缓冲区中的当前值(在示例中已清除)将针对上次使用的内容进行测试,并且您的遮罩几何图形甚至可能根本没有绘制出来。

所以没有特殊的函数可以写入模板缓冲区。我什至不确定它是否可以像您可以将数据直接写入后台缓冲区和深度缓冲区视频内存一样写入,但这不是它应该这样做的方式(因为它非常慢)。模板缓冲区与深度缓冲区共享内存,因此可以通过更改写入函数的参数来实现。不过,我不会指望它适用于所有视频驱动程序。

祝所有需要此信息的人好运!

【讨论】:

  • 哇,我问这个问题已经一年半了!我最终能够理解它,但我很感激你仍然为遇到它的其他人写了一个答案:)
  • 感谢您接受它:-)。我从经验中知道,你不是唯一一个为此苦苦挣扎的人,这就是我分享答案的原因。
  • 您提到您可以像使用普通缓冲区一样写入模板缓冲区,但我没有看到如何绑定模板缓冲区以便 glBufferData 写入它。 glBindBuffer 想要一个由 glGenBuffers 创建的“名称”(我不知道他们到底为什么称数字为名称),这似乎不适用于模板缓冲区。
  • 不,它不像@TrevorGiddings那样工作,您必须将模板缓冲区视为当前选择的渲染目标(可以简单地是后台缓冲区)的扩展,无论发生什么目标,如果像我在帖子中显示的那样启用,将在模板缓冲区上发生。如果您需要在不实际更改该渲染目标的情况下执行此操作,则禁用颜色写入(如上面的帖子中所示)。您不能将模板缓冲区设置为渲染目标,这是不可能的。您应该将其视为连接到渲染目标的碳涂层纸。
  • @scippie 如果你只能通过渲染来写入它,那么我不明白“与任何其他缓冲区没有什么不同”,我不明白“你当然可以真正将像素数据发送到图形内存”——除非您计算发送稍后将在渲染全屏四边形时使用的纹理。
【解决方案2】:

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

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

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

DJ

【讨论】:

    【解决方案3】:

    我描述了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);
    

    【讨论】:

    • 标题:写入 OpenGL 模板缓冲区,答案:写入 OpenGL 深度缓冲区。我学会了如何写入深度缓冲区,但这不是我在点击此类标题上的问题时所期望的,我仍然没有解决我的问题。
    • 这是相当古老的,但是关于模板/深度的最佳讨论之一。很遗憾 。根据最后一个“答案”,它仍然缺少模板和深度缓冲区之间的关系——它们不一样!根据许多doc - stencil ii 深度的特殊情况,测试必须首先通过dept - 如果启用,则它将通过stencil;
    猜你喜欢
    • 2012-07-11
    • 1970-01-01
    • 2011-04-16
    • 2014-01-17
    • 2011-03-09
    • 2020-04-10
    • 2014-12-18
    • 1970-01-01
    相关资源
    最近更新 更多