LibGdx 中同一 OpenGl TriStrip 内的不透明度重叠
Opacity overlap within the same OpenGl TriStrip in LibGdx
虽然我的问题完全出在三条带的不透明度上,但我想先给出一些背景信息。
最近我开始通过 LibGdx 开发一款游戏,其中涉及在屏幕上弹跳的 2D 圆圈。为了提供简洁的图形效果,我创建了一个小系统,可以为演员提供 "tail",它会随着时间的推移逐渐消失。在视觉上,它看起来像这样:
Nice Trail Example
现在看起来很满意。然而,我的问题在于部分 "trail" 效果重叠的情况,创建了一个丑陋的人工制品,我猜它是点不透明度的总和。
Ugly Trail Example
我认为这个问题在于绘制三条带的方式,特别是使用的混合方法。
用于生成trail的代码如下:
Array<Vector2> tristrip = new Array<Vector2>(); //Contains the vector information for OpenGL to build the strip.
Array<Vector2> texcoord = new Array<Vector2>(); //Contains the opacity information for the corresponding tristrip point.
// ... Code Here.... //
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
for (int i = 0; i < tristrip.size; i++) {
if (i == batchSize) {
gl20.end();
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
}
Vector2 point = tristrip.get(i);
Vector2 textcoord = texcoord.get(i);
gl20.color(color.r, color.g, color.b, color.a); // Color.WHITE
gl20.texCoord(textcoord.x, 0f);
gl20.vertex(point.x, point.y, 0);
}
gl20.end();
同样重要的是要注意条带的绘制函数在另一个 class 中以这种方式调用:
private void renderFX() {
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) { //Draws the trails for each actor
balls.get(i).drawFX();
}
}
这个问题是我新手犯的错误,还是我绘制矢量数组 tristrip 的实现从一开始就存在缺陷?如何解决混合问题,以便即使在存在急转弯的情况下也能创建更平滑的轨迹?
提前致谢...
编辑:自从最初提出这个问题以来,我已经尝试了一些可能的解决方案,还实施了 Deniz Yılmaz 关于使用 FBO 促进混合的建议。鉴于此,我的渲染函数目前看起来像这样:
private void renderFX() {
frameBuffer.begin();
Gdx.gl20.glDisable(GL20.GL_BLEND);
Gdx.gl20.glClearColor(0f, 0f, 0f, 0);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_INCR, GL20.GL_INCR);
Gdx.gl20.glStencilMask(0xFF);
Gdx.gl20.glClear(GL20.GL_STENCIL_BUFFER_BIT);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) {
Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0, 0xFF);
balls.get(i).drawFX(1f, Color.RED);
}
frameBuffer.end();
}
如图所示,我还尝试使用模板来掩盖轨迹的重叠部分。然而,这种方法会产生以下视觉效果:
Stenciled Version
同样,这并不理想,并且让我意识到通过遮罩解决这个问题不是一个好主意,因为不透明度渐变在角落永远不会平滑,因为在角落之间总会有一条锐线两个重叠的不透明度值,即使逻辑以某种方式阻止混合。
鉴于此,我还能如何解决这个问题?如果我打算为这种轨迹效果实现平滑渐变,是否应该完全放弃这种方法?
再次感谢。
glBlendFunc() 在这种情况下没有用,因为默认情况下会添加基于混合函数计算的值。
所以需要像 glBlendEquation(GL_MAX) 这样的东西
但是
单独混合是行不通的,因为它无法区分什么是背景和什么是重叠形状。
改为使用 FrameBuffer 通过 glBlendEquation 绘制轨迹。
https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects
虽然我的问题完全出在三条带的不透明度上,但我想先给出一些背景信息。
最近我开始通过 LibGdx 开发一款游戏,其中涉及在屏幕上弹跳的 2D 圆圈。为了提供简洁的图形效果,我创建了一个小系统,可以为演员提供 "tail",它会随着时间的推移逐渐消失。在视觉上,它看起来像这样:
Nice Trail Example
现在看起来很满意。然而,我的问题在于部分 "trail" 效果重叠的情况,创建了一个丑陋的人工制品,我猜它是点不透明度的总和。
Ugly Trail Example
我认为这个问题在于绘制三条带的方式,特别是使用的混合方法。 用于生成trail的代码如下:
Array<Vector2> tristrip = new Array<Vector2>(); //Contains the vector information for OpenGL to build the strip.
Array<Vector2> texcoord = new Array<Vector2>(); //Contains the opacity information for the corresponding tristrip point.
// ... Code Here.... //
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
for (int i = 0; i < tristrip.size; i++) {
if (i == batchSize) {
gl20.end();
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
}
Vector2 point = tristrip.get(i);
Vector2 textcoord = texcoord.get(i);
gl20.color(color.r, color.g, color.b, color.a); // Color.WHITE
gl20.texCoord(textcoord.x, 0f);
gl20.vertex(point.x, point.y, 0);
}
gl20.end();
同样重要的是要注意条带的绘制函数在另一个 class 中以这种方式调用:
private void renderFX() {
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) { //Draws the trails for each actor
balls.get(i).drawFX();
}
}
这个问题是我新手犯的错误,还是我绘制矢量数组 tristrip 的实现从一开始就存在缺陷?如何解决混合问题,以便即使在存在急转弯的情况下也能创建更平滑的轨迹?
提前致谢...
编辑:自从最初提出这个问题以来,我已经尝试了一些可能的解决方案,还实施了 Deniz Yılmaz 关于使用 FBO 促进混合的建议。鉴于此,我的渲染函数目前看起来像这样:
private void renderFX() {
frameBuffer.begin();
Gdx.gl20.glDisable(GL20.GL_BLEND);
Gdx.gl20.glClearColor(0f, 0f, 0f, 0);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_INCR, GL20.GL_INCR);
Gdx.gl20.glStencilMask(0xFF);
Gdx.gl20.glClear(GL20.GL_STENCIL_BUFFER_BIT);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) {
Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0, 0xFF);
balls.get(i).drawFX(1f, Color.RED);
}
frameBuffer.end();
}
如图所示,我还尝试使用模板来掩盖轨迹的重叠部分。然而,这种方法会产生以下视觉效果:
Stenciled Version
同样,这并不理想,并且让我意识到通过遮罩解决这个问题不是一个好主意,因为不透明度渐变在角落永远不会平滑,因为在角落之间总会有一条锐线两个重叠的不透明度值,即使逻辑以某种方式阻止混合。
鉴于此,我还能如何解决这个问题?如果我打算为这种轨迹效果实现平滑渐变,是否应该完全放弃这种方法?
再次感谢。
glBlendFunc() 在这种情况下没有用,因为默认情况下会添加基于混合函数计算的值。
所以需要像 glBlendEquation(GL_MAX) 这样的东西
但是
单独混合是行不通的,因为它无法区分什么是背景和什么是重叠形状。
改为使用 FrameBuffer 通过 glBlendEquation 绘制轨迹。
https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects