Open GL Translucid Sprites

时间:2017-03-24 17:39:10

标签: c++ opengl 2d rendering sprite

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

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

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&lt; 1。 顶点着色器是标准的。

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

编辑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

1 个答案:

答案 0 :(得分:0)

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

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

的结果
  1. 使用render()时,您实际上并没有致电_programID
  2. _programID你之后glClear(GL_COLOR_BUFFER_BIT)
  3. 您使用GL_ONE_MINUS_SRC_ALPHA作为glBlendFunc()&#39; s sfactor
  4. 因此,您的_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)时启用写入深度缓冲区,则它会正确生成第一张图片。

    correct wrong

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

    请注意,这种关系适用于glClear(...)和任何gl*Mask(GL_FALSE)