OpenGL模具-排除透明像素 [英] OpenGL Stencil - Exclude transparent pixels

查看:116
本文介绍了OpenGL模具-排除透明像素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有想要使用模板缓冲区用作蒙版的纹理:

I have this texture that I want to use as as mask using the Stencil buffer :

然后我想在屏幕上绘制图像IMG,该图像应仅在可见上述图像(有颜色)的地方出现,从而排除顶部边缘上方和渐变以下的透明像素.

Then I want to draw an image IMG on the screen which should appear only where the above image is visible (where there's color), thus excluding transparent pixels above the top edge and below the gradient.

问题是,每当我在屏幕上绘制图像IMG时,它都会出现在绘制图像的任何地方,无论像素是否透明.

The problem is whenever I draw my image IMG on the screen it appears everywhere where the image has been drawn, whether the pixels are transparent or not.

所以我考虑过使用ALPHA_TEST,但是它在最新的OpenGL版本中已经消失了,所以我试图在片段着色器中使用v_color.a == 0v_color.r == 0丢弃片段,但是它什么也没做...

So I thought about using the ALPHA_TEST but it's gone in the latest OpenGL versions, so I tried to discard fragment with v_color.a == 0 or v_color.r == 0 in my fragment shader but it does nothing...

片段着色器:

#ifdef GL_ES
    #define LOWP lowp
    precision mediump float;
#else
    #define LOWP
#endif

uniform sampler2D u_texture;

varying LOWP vec4 v_color;
varying vec2 v_texCoords;

void main() {
    if (v_color.a == 0) {
        discard;
    }

    gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}

顶点着色器:

attribute vec4 a_color;
attribute vec4 a_position;
attribute vec2 a_texCoord0;

uniform mat4 u_projTrans;

varying vec4 v_color;
varying vec2 v_texCoords;

void main() {
    v_color = a_color;
    v_texCoords = a_texCoord0;
    gl_Position = u_projTrans * a_position;
}

代码:

@Override
public void draw(final DrawConfig drawConfig) {
    this.applyTransform(drawConfig.getBatch(), this.computeTransform());

    // Draw mask to stencil buffer

    drawConfig.end();
    final GL20 gl = Gdx.gl;

    gl.glEnable(GL20.GL_STENCIL_TEST);
    gl.glStencilFunc(GL20.GL_ALWAYS, 1, 0xFF);
    gl.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);
    gl.glStencilMask(0xFF);
    gl.glColorMask(false, false, false, false);
    gl.glClearStencil(0);
    gl.glClear(GL20.GL_STENCIL_BUFFER_BIT);

    drawConfig.begin(Mode.BATCH);
    this.mBackground.setClippingEnabled(true); // The clipping area is a rectangle centered in the screen
    this.mBackground.draw(drawConfig);
    this.mBottomBorder.draw(drawConfig); // Border below the rectangle area
    this.mTopBorder.draw(drawConfig); // Border above the rectangle area
    drawConfig.end();

    gl.glColorMask(true, true, true, true);
    gl.glStencilFunc(GL20.GL_EQUAL, 1, 0xFF);
    gl.glStencilMask(0x00);

    // Draw elements

    this.mBackground.setClippingEnabled(false); // No clipping area, use stencil test
    this.mBackground.draw(drawConfig);
    this.mBottomBorder.draw(drawConfig);
    this.mTopBorder.draw(drawConfig);

    drawConfig.end();
    Gdx.gl.glDisable(GL20.GL_STENCIL_TEST);

    this.resetTransform(drawConfig.getBatch());
}

结果:

红色箭头表示超出边界的部分,而我想使其消失. 为了方便起见,黄色正方形是剪切区域.

The red arrows show the parts that go outside of the borders and that I want to make disappear. The yellow square is the clipping area, for your convenience.

推荐答案

您要复制的固定功能alpha测试(GL_ALPHA_TEST)是每个片段测试.它曾经在片段着色器完成后 发生,您可以使用discard自己实现.

The fixed-function alpha test (GL_ALPHA_TEST) you are trying to duplicate was a per-fragment test. It used to occur after the fragment shader finished, and you can implement it yourself using discard.

但是,当前的解决方案使用的是插入的每个顶点的alpha值,这与您试图用作蒙版的纹理无关.您需要测试分配给gl_FragColor的alpha值才能正确执行此操作:

However, your current solution is using the interpolated per-vertex alpha value, and that has nothing to do with the texture you are trying to use as a mask. You need to test the alpha value assigned to gl_FragColor to do this properly:

void main() {
    gl_FragColor = v_color * texture2D(u_texture, v_texCoords);

    if (gl_FragColor.a == 0.0) {
        discard;
    }
}

这是基于着色器的现代等效项:

That is the modern shader-based equivalent of:

glAlphaFunc (GL_NOTEQUAL, 0.0f); // Reject fragments with alpha == 0.0
glEnable    (GL_ALPHA_TEST);

这篇关于OpenGL模具-排除透明像素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆