简体   繁体   English

Open GL Translucid Sprites

[英]Open GL Translucid Sprites

So, my goal is to draw sprites with translucid pixels. 所以,我的目标是用透明像素绘制精灵。

First, I render the sprites with a shader that only renders the opaque pixels. 首先,我使用仅渲染不透明像素的着色器渲染精灵。 Then, I disable depth buffer writing and render the same sprites with a shader that only renders the translucid (or transparent sprites), as explained here: 然后,我禁用深度缓冲区写入并使用仅渲染透明(或透明精灵)的着色器渲染相同的精灵,如下所述:

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

This is the animation sprite sheet I am using as test: 这是我用作测试的动画精灵表:

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

This is my renderer update function: 这是我的渲染器更新功能:

updateRenderData();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

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


_window->SwapBuffers();

And this is my render function (just in case you want to know how I render the sprites): 这是我的渲染函数(以防万一你想知道我如何渲染精灵):

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;
}

But when I execute this code, it only renders the translucid pixels: https://i.stack.imgur.com/f4AY6.png 但是,当我执行此代码时,它只呈现透明像素: https//i.stack.imgur.com/f4AY6.png

In fact, nothing renders (black screen) if I remove the second render() call (only the call, I still change the shader and set the depth mask to false), like this: 实际上,如果我删除第二个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();

But if I don't change the shader nor set glDepthMask to false after the first render, it renders the opaque pixels of my sprites correctly. 但是如果我没有更改着色器,也没有在第一次渲染后将glDepthMask设置为false,它会正确渲染我的精灵的不透明像素。

Edit: This is the fragment shader I am using for the second pass: 编辑:这是我用于第二遍的片段着色器:

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;
}

The first pass is just the same, but discarding if alpha < 1. The vertex shader is standard. 第一遍是相同的,但如果alpha <1则丢弃。顶点着色器是标准的。

So, my question here is: what is causing this? 所以,我的问题是:造成这种情况的原因是什么?

Edit 2: 编辑2:

To clarify, this renders correctly (without translucent pixels): 为了澄清,这正确呈现(没有半透明像素):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

And this doesn't render at all: 这根本不会呈现:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

glDepthMask(GL_FALSE);//Just added this line

And this also doesn't render at all: 这根本不会呈现:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

glUseProgram(_translucencyPogramID);//Just added this line

Assuming _programID is for drawing the opaque part of the bird and _translucencyPogramID is for drawing the translucent part. 假设_programID用于绘制鸟的不透明部分, _translucencyPogramID用于绘制半透明部分。

Nothing in the code you've supplied shows what the cause could be. 您提供的代码中没有任何内容显示原因可能是什么。 However it could be the result of: 然而,它可能是以下结果:

  1. You aren't actually calling render() while using _programID . 在使用_programID您实际上并未调用render()
  2. After the _programID you glClear(GL_COLOR_BUFFER_BIT) _programIDglClear(GL_COLOR_BUFFER_BIT)
  3. You're using GL_ONE_MINUS_SRC_ALPHA as glBlendFunc() 's sfactor 你正在使用GL_ONE_MINUS_SRC_ALPHA作为glBlendFunc()sfactor

So given that your _programID 's fragment shader consists of: 因此,您的_programID的片段着色器包含:

if (texel.a < 1.0)
    discard;

and your _translucencyPogramID 's fragment shader consists of: 你的_translucencyPogramID的片段着色器包括:

if (texel.a == 1.0)
    discard;

Then granted your draw loop is like this (pseudo-code): 然后授予你的绘制循环就像这样(伪代码):

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)

Then while using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) , then that should give the desired result. 然后在使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ,那应该给出所需的结果。

Edit 编辑

Then reason it breaks when you when you add glDepthMask(GL_FALSE) , is because you don't enabled it again after. 然后当你添加glDepthMask(GL_FALSE)时它会中断它,因为你之后没有再启用它。 You can check this by doing: 你可以通过这样做来检查:

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

Before you glClear(GL_DEPTH_BUFFER_BIT) . 在你glClear(GL_DEPTH_BUFFER_BIT)之前glClear(GL_DEPTH_BUFFER_BIT)

This reason it breaks is because if writing to the depth buffer is disabled, then glClear(GL_DEPTH_BUFFER_BIT) won't do anything, and thus leave the depth buffer as is. 这个原因中断是因为如果禁用写入深度缓冲区,则glClear(GL_DEPTH_BUFFER_BIT)将不执行任何操作,因此保留深度缓冲区。

As you can see below, on the second picture it sort of smears the silhouette of all the bird's frames. 正如你在下面看到的那样,在第二张照片上,它会描绘出所有鸟类画面的轮廓。 Which is because the depth buffer is never cleared, and this bird is the frontmost bird. 这是因为深度缓冲区永远不会被清除,这只鸟是最前面的鸟。 If writing to the depth buffer is enabled upon calling glClear(GL_DEPTH_BUFFER_BIT) then it correctly yields the first picture. 如果在调用glClear(GL_DEPTH_BUFFER_BIT)启用写入深度缓冲区,则它会正确生成第一个图片。

正确错误

Left: Depth writing is enabled on glClear. 左:在glClear上启用深度写入。 Right: Depth writing is disabled on glClear. 右:在glClear上禁用深度写入。

Note that this relation is true for glClear(...) and any gl*Mask(GL_FALSE) . 请注意,这种关系适用于glClear(...)和任何gl*Mask(GL_FALSE)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM