使用模板缓冲区概述对象会给出错误的结果

Posted

技术标签:

【中文标题】使用模板缓冲区概述对象会给出错误的结果【英文标题】:Outlining an object using a stencil buffer give wrong result 【发布时间】:2019-10-31 10:08:50 【问题描述】:

我正在尝试使用模板缓冲区在模型后面绘制轮廓边框。

我正在使用 2 次渲染通道,首先渲染模型并使用 GL_ALWAYS1 写入模板缓冲区,然后渲染使用 GL_NOTEQUAL 的模型的略微放大版本,参考值为1 所以基本上只传递原始立方体之外的片段,从而突出显示。

我得到了奇怪的结果,轮廓没有完全渲染,当我移动相机足够多时,它完全消失,好像放大立方体的模板测试根本没有通过。 以下是渲染循环的要点(shader3 只是为边框输出颜色):

while (!glfwWindowShouldClose(window))

    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClearStencil(0);
    renderer.Clear();    
    ...
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.1f, 100.0f);
    UniformMat4f projectionUniform("u_Projection");
    projectionUniform.SetValues(projection);

    glm::mat4 view = camera.GetView();
    UniformMat4f viewUniform("u_View");
    viewUniform.SetValues(view);

    modelUniform.SetValues(glm::translate(glm::mat4(1.0f), glm::vec3(5.0f, 0.0f, 0.0f)));

    shader1.SetUniform(projectionUniform);
    shader1.SetUniform(viewUniform);
    shader1.SetUniform(modelUniform);

    glStencilFunc(GL_ALWAYS, 1, 0xFF);
    glStencilMask(0xFF);

    renderer.Draw(model, shader1);

    modelUniform.SetValues(glm::scale(glm::translate(glm::mat4(1.0f), glm::vec3(5.0f, 0.0f, 0.0f)), glm::vec3(1.1f, 1.1f, 1.1f)));
    shader3.SetUniform(projectionUniform);
    shader3.SetUniform(viewUniform);
    shader3.SetUniform(modelUniform);

    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    glStencilMask(0x00);
    glDisable(GL_DEPTH_TEST);
    renderer.Draw(model, shader3);
    glEnable(GL_DEPTH_TEST);

我首先使用 crysis 的 nanosuit 模型进行了尝试,它的工作原理正如我所描述的那样,没有显示所有部件并最终在移动相机时消失。我决定尝试一个简单的几何图形来测试这一点,并尝试勾勒出一个简单的立方体并得到相同的结果:

【问题讨论】:

renderer.Clear(); 是什么?它是否使用glClear() GL_STENCIL_BUFFER_BIT 是的,清除颜色、深度和模板缓冲区 learnopengl.com 中有一个很好的教程。您可以比较您的代码的细微之处。根据我使用 OpenGL 的经验,遗漏小细节通常会带来致命的后果...... ;-) 这实际上是我的资源,所以我不确定出了什么问题 【参考方案1】:

问题是在主循环结束时调用glStencilMask(0x00);。模板掩码的默认值为0xff(对于 8 位,请参阅glStencilMask)。 OpenGL 是一个状态引擎。保持状态,直到再次更改(甚至超出帧)。glClear 考虑颜色、深度和模板蒙版的状态。如果模板掩码是0x00,则模板缓冲区根本不会被清除。

设置模板掩码0xff,然后清除模板缓冲区以解决问题:

glStencilMask(0xFF);
renderer.Clear(); 

【讨论】:

但是glStencilMask(0xFF); 不只是用来掩盖我们正在写入模板缓冲区而不是清除的内容吗?为什么我设置glClearStencil(0);并调用glClear(...)时会不清楚? 否,glStencilMask 指定允许写入的位。如果为 0,则不允许写入模板缓冲区的任何位,并且根本无法更改模板缓冲区,因此 glClear(GL_STENCIL_BUFFER_BIT) 什么都不做。

以上是关于使用模板缓冲区概述对象会给出错误的结果的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenGL 中为索引缓冲区对象使用结构会导致段错误

如何使用模板缓冲区仅屏蔽位于另一个对象后面的对象像素?

WebGL简易教程:颜色

循环缓冲区在第 6 个元素之后没有给出正确的缓冲区大小

渲染管道像素阶段“模板测试”

问绘图缓冲区的模板缓冲区会增加性能成本(WebGL)吗?