OpenGL中着色器中的Alpha值无效

huangapple go评论74阅读模式
英文:

OpenGL Alpha values having no effect in shader

问题

以下是您要翻译的内容:

我在我的2D游戏中有一个制作扫描线的简单着色器,它运行良好,代码如下:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

void main() {
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    if (mod(p.y, 6.0) == 0.0)
        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);
    else
        gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}

但是,如果我在片段颜色的vec4中更改alpha值,效果不会改变,无论在0.1还是1.0时,扫描线都是一样的黑色。我看到其他关于此问题的一些帖子建议启用混合,但我尝试过,但没有效果。

这是我的启用了混合的渲染方法:

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 0);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    Gdx.gl.glEnable(GL20.GL_BLEND);
    Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    // batch.enableBlending(); 我也尝试过这个,但没有效果
    batch.setProjectionMatrix(cam.combined);
    batch.setShader(shaderProgram);
    batch.begin();
    rendup.renderAll(batch);  // 渲染所有精灵、瓦片等
    batch.setShader(null);
    batch.end();
}
英文:

I have a simple shader to make scanlines in my 2d game which works fine and is as follows:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

void main() {
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    if (mod(p.y, 6.0)==0.0)
        gl_FragColor = vec4(0.0,0.0,0.0, 0.1);
    else
        gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}

But if I change the alpha value in the vec4 for the fragment colour, it has no effect, the scanlines are equally black at 0.1 as they are at 1.0. I saw some other questions regarding this which advised to enable blending, but I tried that to no avail.

This is my render method with blending enabled.

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 0);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    Gdx.gl.glEnable(GL20.GL_BLEND);
    Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    // batch.enableBlending(); tried this too but no effect
    batch.setProjectionMatrix(cam.combined);
    batch.setShader(shaderProgram);
    batch.begin();
    rendup.renderAll(batch);//renders all sprites, tiles etc
    batch.setShader(null);
    batch.end();
}

答案1

得分: 1

这不是混合问题。问题出在你的着色器上,它只会绘制半透明的黑色像素,或者绘制当前绘制的纹理区域的颜色。这些黑色像素会与屏幕上已有的内容混合在一起(在这种情况下是黑色的清除颜色)。

我猜想你实际想要的是扫描线不是纯黑色。因此,你应该在所有地方绘制纹理区域的颜色,并在扫描线所在的地方稍微加深颜色。你不希望修改着色器输出的 alpha 值,否则当精灵重叠时,扫描线在该区域会显得更暗。

所以,像这样修改你的着色器:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

const float DARK_LINE_BRIGHTNESS = 0.9;

void main() {
    vec4 color = v_color * texture2D(u_texture, v_texCoords);
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    if (mod(p.y, 6.0)==0.0)
        gl_FragColor = vec4(color.rgb * DARK_LINE_BRIGHTNESS, color.a);
    else
        gl_FragColor = color;
}

然而,片段着色器中应该避免使用 if/else,因为它在大多数情况下性能较差(例外情况是如果 if 语句对于连续的许多像素评估结果相同,比如使用 if (u_someUniformBoolean))。你可以像这样重新编写它:

void main() {
    vec4 color = v_color * texture2D(u_texture, v_texCoords);
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    gl_FragColor = (step(0.01, mod(p.y, 6.0)) * (1.0 - DARK_LINE_BRIGHTNESS) + DARK_LINE_BRIGHTNESS) * color;
}
英文:

This isn't a blending problem. The issue is your shader only draws either a translucent black pixel, or the color of whatever texture region is being drawn. These black pixels are just getting blended with what's already on the screen (in this case the black clear color).

I assume what you actually want here is for the scan lines not to be pure black. So you should be drawing the color of the texture region everywhere, and just darken it slightly where the scan lines are. You don't want to be modifying the alpha that the shader outputs, or when you have overlapping sprites, the scanline will appear darker in that area.

So change your shader like this:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

const float DARK_LINE_BRIGHTNESS = 0.9;

void main() {
    vec4 color = v_color * texture2D(u_texture, v_texCoords);
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    if (mod(p.y, 6.0)==0.0)
        gl_FragColor = vec4(color.rgb * DARK_LINE_BRIGHTNESS, color.a);
    else
        gl_FragColor = color;
}

However, if/else should be avoided in fragment shaders because it performs significantly worse in most cases. (Exception is if the if statement evaluates to the same value for many pixels in a row, such as with if (u_someUniformBoolean).) You could rewrite it like this:

void main() {
    vec4 color = v_color * texture2D(u_texture, v_texCoords);
    vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
    gl_FragColor = (step(0.01, mod(p.y, 6.0)) * (1.0 - DARK_LINE_BRIGHTNESS) + DARK_LINE_BRIGHTNESS) * color;
}

huangapple
  • 本文由 发表于 2020年8月27日 20:33:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63616100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定