【问题标题】:Open GL Translucid SpritesOpengl 半透明精灵
【发布时间】:2017-03-24 17:39:09
【问题描述】:

所以,我的目标是绘制具有半透明像素的精灵。

首先,我使用仅渲染不透明像素的着色器渲染精灵。然后,我禁用深度缓冲区写入并使用仅渲染半透明(或透明精灵)的着色器渲染相同的精灵,如下所述:

https://gamedev.stackexchange.com/questions/51202/how-do-you-display-non-cutout-transparent-2d-textures-with-a-depth-buffer-open

这是我用作测试的动画精灵表:

https://i.stack.imgur.com/MMs2W.png

这是我的渲染器更新功能:

updateRenderData();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDepthMask(GL_TRUE);
glUseProgram(_programID);
render();

glDepthMask(GL_FALSE);
glUseProgram(_translucencyPogramID);
render();


_window->SwapBuffers();

这是我的渲染函数(以防你想知道我如何渲染精灵):

GLint baseInstance = 0;
GLsizei spriteCount;

for (int i = 0; i < _spriteManager->GetSpriteBatchVector()->size(); i++)
{
    _SpriteBatch* spriteBatch = _spriteManager->GetSpriteBatchVector()->at(i);
    setTexture(spriteBatch->GetTexture());
    spriteCount = (GLsizei)spriteBatch->GetSpriteVector()->size();
    glDrawElementsInstancedBaseInstance(_quad.renderMode, _quad.indexCount, _quad.indexDataType, 0, spriteCount, baseInstance);
    baseInstance += spriteCount;
}

但是当我执行这段代码时,它只渲染半透明像素: https://i.stack.imgur.com/f4AY6.png

事实上,如果我删除第二个 render() 调用(仅调用,我仍然更改着色器并将深度蒙版设置为 false),则没有任何渲染(黑屏),如下所示:

updateRenderData();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDepthMask(GL_TRUE);
glUseProgram(_programID);
render();

glDepthMask(GL_FALSE);
glUseProgram(_translucencyPogramID);


_window->SwapBuffers();

但如果我在第一次渲染后不更改着色器也不将 glDepthMask 设置为 false,它会正确渲染我的精灵的不透明像素。

编辑: 这是我用于第二遍的片段着色器:

out layout(location = 0) vec4 outColor;

in vec2 texCoord;

uniform sampler2D tex;

void main()
{
    vec4 texel = texture(tex, texCoord);
    if(texel.a == 1)
    {
        discard;
    }
    outColor = texel;
}

第一遍是一样的,但如果 alpha

所以,我的问题是:这是什么原因造成的?

编辑 2:

为了澄清,这个渲染正确(没有半透明像素):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDepthMask(GL_TRUE);
glUseProgram(_programID);
render();

这根本不渲染:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDepthMask(GL_TRUE);
glUseProgram(_programID);
render();

glDepthMask(GL_FALSE);//Just added this line

而且这也根本不渲染:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDepthMask(GL_TRUE);
glUseProgram(_programID);
render();

glUseProgram(_translucencyPogramID);//Just added this line

【问题讨论】:

  • 你的着色器是什么样子的?
  • 以上代码都不会导致您按原样显示。了解您为什么有 2 个着色器会有所帮助?
  • "首先,我使用仅渲染不透明像素的着色器渲染精灵。然后,我禁用深度缓冲区写入并使用仅渲染半透明(或透明精灵)的着色器渲染相同的精灵”。也许这不是最好的方法,但我想尝试一下。
  • 而且是的,这只是更复杂的渲染系统的一小部分,但它太复杂了,不能放在这里。问题是为什么在渲染后使用 glDepthMask(GL_FALSE) 和 glUseProgram(_translucencyPogramID) 会影响渲染。
  • 所以你想画完全不透明的鸟,然后在上面画半透明的红色背景?

标签: c++ opengl 2d rendering sprite


【解决方案1】:

假设_programID 用于绘制鸟的不透明部分,_translucencyPogramID 用于绘制半透明部分。

您提供的代码中没有任何内容显示可能是什么原因。然而,这可能是以下原因:

  1. 您在使用_programID 时实际上并没有调用render()
  2. _programID你之后glClear(GL_COLOR_BUFFER_BIT)
  3. 您正在使用GL_ONE_MINUS_SRC_ALPHA 作为glBlendFunc()sfactor

假设您的_programID 的片段着色器包括:

if (texel.a < 1.0)
    discard;

您的_translucencyPogramID 的片段着色器包括:

if (texel.a == 1.0)
    discard;

然后授予你的绘制循环是这样的(伪代码):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDepthMask(GL_TRUE)
glUseProgram(_programID)
for each sprite
    glDrawArrays(....)

glDepthMask(GL_FALSE)
glUseProgram(_translucencyPogramID)
for each sprite
    glDrawArrays(....)

glDepthMask(GL_TRUE)

然后在使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 时,应该会得到想要的结果。

编辑

然后,当您添加glDepthMask(GL_FALSE) 时它会中断,是因为您之后没有再次启用它。您可以通过以下方式检查:

GLboolean enabled;
glGetBooleanv(GL_DEPTH_WRITEMASK, &enabled);
assert(enabled == GL_TRUE);

在你之前glClear(GL_DEPTH_BUFFER_BIT)

它中断的原因是因为如果写入深度缓冲区被禁用,那么glClear(GL_DEPTH_BUFFER_BIT) 将不会做任何事情,因此保持深度缓冲区不变。

正如您在下面看到的,在第二张照片上,它有点涂抹了所有鸟的框架的轮廓。这是因为深度缓冲区永远不会被清除,而这只鸟是最前面的鸟。如果在调用 glClear(GL_DEPTH_BUFFER_BIT) 时启用了写入深度缓冲区,那么它会正确生成第一张图片。

左:在 glClear 上启用深度写入。右:在 glClear 上禁用深度写入。

请注意,这种关系对于glClear(...) 和任何gl*Mask(GL_FALSE) 都是正确的。

【讨论】:

  • 感谢您花时间回答。您对 _programID 和 _translucidProgramID 的假设是正确的。但问题仍然存在。我在使用 _programID 时调用了 render(),在它之后我没有调用 glClear,我使用的是 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA),所以这些不是问题的原因。
  • 谢谢,这解决了部分问题。但是问题仍然存在,因为如果我在第一次渲染后更改着色器(仅添加行 glUseProgram(_translucencyProgramID);)它仍然不会渲染任何内容。我再次编辑了问题(对编辑量感到抱歉)。
  • 添加该行不应使其不再呈现。所以目前除了我在回答中已经写的内容之外,我无法添加任何内容。请随意编辑更多问题,以便我们深入了解。
  • 好的,我已经缩小了着色器问题的范围,从代码的另一部分(编译着色器的代码)看来它是一个错误,所以我将其标记为正确答案.谢谢!
  • 好的,不客气!如果您还没有考虑启用debug output(它在页面下方有点远)。这是一个非常好的实用程序,可以发现任何发生的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多