libgdx open gles 2.0 模板 alpha 遮罩
Posted
技术标签:
【中文标题】libgdx open gles 2.0 模板 alpha 遮罩【英文标题】:libgdx open gles 2.0 stencil alpha masking 【发布时间】:2014-07-18 08:14:26 【问题描述】:我正在寻找一种解决方案,通过 open gles 2.0 在 libgdx 中使用模板缓冲区实现 alpha 屏蔽。
我已经设法使用模板缓冲区和着色器实现简单的 alpha 掩码,如果片段的 alpha 通道大于某个指定值,它就会被丢弃。效果很好。
问题是当我想使用一些渐变图像蒙版或绑定 png 蒙版时,我没有得到我想要的(我得到没有 alpha 通道的“填充”矩形蒙版),而是我想要平滑淡出蒙版.
我知道问题是在模板缓冲区中只有 0 和 1,但我想写入模板一些其他值,这些值表示在片段着色器中传递的片段的实际 alpha 值,并使用该值来自模板以某种方式进行一些混合。 我希望我已经解释了我想要得到的东西,如果可能的话。
我最近开始玩OpenGL ES,所以还是有一些误解。
我的问题是:如何设置和模板缓冲区来存储除 0 和 1 以外的值,以及如何在以后使用这些值进行 alpha 屏蔽?
提前发送。
这是我目前的模板设置:
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_STENCIL_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// setup drawing to stencil buffer
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
spriteBatch.setShader(shaderStencilMask);
spriteBatch.begin();
// push to the batch
spriteBatch.draw(Assets.instance.actor1, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, Assets.instance.actor1.getRegionWidth(), Assets.instance.actor1.getRegionHeight());
spriteBatch.end();
// fix stencil buffer, enable color buffer
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
// draw where pattern has NOT been drawn
Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0x1, 0xff);
decalBatch.add(decal);
decalBatch.flush();
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);
decalBatch.add(decal2);
decalBatch.flush();
【问题讨论】:
Stenciling 不允许部分 alpha 值。为了获得介于两者之间的值,我认为您必须将您的东西绘制到 FrameBuffer 中,然后使用 FrameBuffer 的颜色纹理和表示 alpha 的纹理通过多重纹理绘制到屏幕上。但根据您的具体需求,可能会有更简单的解决方案。 我试图掩盖 3d 平面,例如一个平面代表面具,另一个平面在面具平面后面。我希望在面罩的纹理透明的地方变得透明。我目前在 Libgdx 中使用贴花。如果没有 fps 下降,这是否可能? 平面是指 3D 空间中的矩形?如果两个矩形的大小、方向和位置完全相同,那么您可以使用多纹理来实现,尽管这需要对贴花进行一些变通。 是的,平面基本上是 3D 空间中的矩形。面具应该是静态的,面具后面的平面可以移动。并且重叠部分应该被屏蔽。 我只能想到涉及FrameBuffers的方法。是否影响 FPS 取决于你的瓶颈是什么。 【参考方案1】:我能想到的唯一方法是使用 FrameBuffer。
选项 1
将场景的背景(不会被遮罩的东西)绘制到 FrameBuffer 中。然后将没有蒙版的整个场景绘制到屏幕上。然后使用 FrameBuffer 的颜色附件将您的蒙版贴花绘制到屏幕上。这种方法的缺点是,在 android 上的 OpenGL ES 2.0 中,FrameBuffer 可以具有 RGBA4444,而不是 RGBA8888,因此在颜色位深度发生变化的遮罩边缘会出现可见的接缝。
选项 2
将您的蒙版贴花绘制为对您的 FrameBuffer 不透明的 B&W。然后将背景绘制到屏幕上。当你绘制任何可以被遮罩的东西时,用多重纹理绘制它,乘以 FrameBuffer 的颜色纹理。潜在的缺点是,任何可以被遮罩的东西都必须使用自定义着色器进行多纹理绘制。但是,如果您只是使用贴花,那么这实际上并不比选项 1 复杂。
以下内容未经测试...可能需要一些调试。
在这两个选项中,我将继承 CameraGroupStrategy 以在绘制蒙版贴花时与 DecalBatch 一起使用,并覆盖 beforeGroups
以同时设置第二个纹理。
public class MaskingGroupStrategy extends CameraGroupStrategy
private Texture fboTexture;
//call this before using the DecalBatch for drawing mask decals
public void setFBOTexture(Texture fboTexture)
this.fboTexture = fboTexture;
@Override
public void beforeGroups ()
super.beforeGroups();
fboTexture.bind(1);
shader.setUniformi("u_fboTexture", 1);
shader.setUniformf("u_screenDimensions", Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
在您的着色器中,您可以像这样获得 FBO 纹理颜色:
vec4 fboColor = texture2D(u_fboTexture, gl_FragCoord.xy/u_screenDimensions.xy);
那么对于选项 1:
gl_FragColor = vec4(fboColor.rgb, 1.0-texture2D(u_texture, v_texCoords).a);
或者对于选项 2:
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
gl_FragColor.a *= fboColor.r;
【讨论】:
嘿,它在桌面上完美运行!但是在android上什么都没有画出来。你知道为什么吗?我尝试过使用帧缓冲格式 8888 和 4444,但它是一样的。 我已经调试...绘图到帧缓冲区工作,但使用自定义组策略的步骤不会在屏幕上绘制任何内容。这是我的 beforeGroupsMethod: Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);着色器.开始(); shader.setUniformMatrix("u_projTrans", camera.combined); gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE1); fboTexture.bind(1); shader.setUniformi("u_fboTexture", 1); shader.setUniformf("u_screenDimensions", Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE0); shader.setUniformi("u_texture", 0); 当某些东西在桌面上运行而不是在 Android 上运行时,对我来说这通常是因为着色器中的某些东西导致着色器无法编译。编译着色器后,将其用于调试目的:if (!shader.isCompiled())Gdx.app.log("shader compile failed", shader.getLog());
。这将告诉您编译时发生的任何警告或错误。它实际上为您提供了错误发生的行号和列号,而不是它们是否发生在顶点着色器或片段着色器中,因此有时您必须同时检查两者。
嘿,我已经在手机上尝试过我的代码,它正在工作......我也在 STB 设备上尝试过,但没有任何东西被绘制出来。着色器中没有错误或警告日志。我什至尝试将其替换为绘制简单的红色框,但这没有任何区别。你知道一些可能有帮助的设置吗? STB 设备是我的目标平台,所以它必须在它上面工作。有什么建议么?这是果冻豆 4.2.2。
我找到了解决方案:我唯一需要添加的是 calulus 中的 v_color 用于片段着色器中的片段颜色。事件没用,我猜STB上的编译器版本有问题或类似的东西。以上是关于libgdx open gles 2.0 模板 alpha 遮罩的主要内容,如果未能解决你的问题,请参考以下文章
使用 Open GL ES 2.0 创建 OFF SCREEN 表面