openGL Alpha Blending可实现完全不透明度或透明度

时间:2018-05-23 03:18:33

标签: opengl alpha opengl-3 alphablending

ORIGINAL:

之前我曾询问过这个问题,但我最初的例子有点不完整,我想我现在可以更加具体地解决我的问题了。

对于上下文,我在旧的Apple mac计算机上使用openGL 3.3,并尝试渲染重叠的四边形图层。每个四边形都是uv映射到png 4096 x 4096纹理的一块,它具有完全透明的区域。

我想使用alpha混合,因此N层的透明部分显示了N-1层(在它后面)的不透明部分。 因为我不需要半透明,我想知道 - 有没有办法配置glBlendFuncSeparate所以片段颜色只是最前面的不透明纹素 - 不需要额外的乘法?

我试过这样的事情:

glBlendFuncSeparate(GL_SRC_COLOR, GL_DST_COLOR, GL_ONE, GL_ZERO);

但我认为我完全误解了参数的含义。我认为他们的意思是:保持源颜色并将其设置为目标颜色...应用原始alpha。 (我知道这绝对是错的。)

最初我认为这是一个xyz问题并搜索其他原因我注意到性能问题,但即使上面的函数调用导致完全错误的颜色,它也会导致我的动画即使在hello-triangle +中运行也很平滑罪(时间)翻译案例。

我会发布一些代码,但它主要包括设置顶点缓冲区和大型静态数组声明以进行测试。我的着色器基本上是直通的:(例如我的片段着色器中的主要功能:)

void main(void)
{
    vec4 texel = texture(tex0, v_uv);

    color = vec4(texel.rgb, texel.a);
}

并且纹理正确加载。我从后到前设置了渲染。

我如何设置这种渲染?

提前谢谢。

更新

我试过了:

glEnable(GL_BLEND); 
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);

但只显示透明度为白色的前层。我检查了RGBA值,看起来透明部分是[1.0,1.0,1.0,0.0]所以看起来我需要忽略alpha为0.0时的颜色,即使颜色不是[0.0,0.0,0.0,一个]。为了模拟这个,我添加了一个if (alpha is 0.0), then discard;语句,但后来又返回了。

所以功能不完全正确,或其他错误。

有关我的设置的更多信息:

(我在底部张贴了大纹理)

每个图层的顶点和索引数据太长而无法发布,但五个图层中每个图层都有三个四边形(我将相机位置传递给着色器并使用z位置值进行偏移)。这可能是低效率的单独来源。

完整的片段和顶点着色器:

//顶点

#version 330 core
precision highp float;

layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_uv;

out vec2 v_uv;

uniform mat4 u_matrix;
uniform float u_aspect;
uniform vec3 u_position_cam;

uniform int u_count_layers;

void main(void) 
{
    // scroll speed depends on the inverse of the z position
    float speed_factor = (1.0 / pow(2.0, u_count_layers - a_position.z));

    // x offset
    float X = -u_position_cam.x * speed_factor;

    // make sure the bg quad jumps back to the correct position
    X = mod(X, (u_aspect) * 2.0);
    X += a_position.x;

    // y offset 
    float Y = -clamp(u_position_cam.y, 0.0, 2.0) * speed_factor;
    Y += a_position.y;

    gl_Position = u_matrix * vec4(X, Y, a_position.z, 1.0);

    v_uv = a_uv;
}

//片段

#version 330 core
precision highp float;

in vec2 v_uv;

uniform sampler2D tex0;

out vec4 color;

void main(void)
{
    vec4 texel = texture(tex0, v_uv);

    color = vec4(texel);
}

This mostly unresolved stackoverflow question讨论了我遇到的问题 - 简而言之,许多重叠的透明形状会导致延迟,但如果相同的形状不重叠,那么一切都很好。 当然,还没有找到替代混合算法。

考虑数字 - 每个纹理部分覆盖1280 x 720像素。有5层,每层3个四边形。 对于每个像素,我正在做同样的工作N层次,所以4,608,000? 我想这可能是非常昂贵的。我也做了奇怪的模运算和偏移。 如果我试图实现视差滚动的方式太笨拙,那么它将如何有效地完成?如果肯定有更好的方法,我愿意改变我的算法/设置。我很好奇如何正确设置纹理和透明层以避免我遇到的问题。

一个想法:如果我从前到后渲染怎么办?混合功能将如何变化? (我知道你通常会从后到前渲染透明对象,但是在这里我只需要在使用alpha == 1.0命中一层时停止检查图层。)

4096x4096 bg texture "atlas"

1 个答案:

答案 0 :(得分:0)

你的这个问题非常难以理解,但似乎关键是

  

片段颜色只是最不透明的纹理元素 - 没有额外的   需要乘法

所以你是说你只想绘制那些alpha为1.0的像素,而其余的被丢弃?像下面的例子一样:

您正在绘制3个大小为3x1的纹理。第一个纹理所有3个像素都是不透明的;第二个像素是前2个像素不透明,最后一个像素不透明。现在结果应该是第一个像素来自纹理3,第二个像素来自2,第三个来自1。

如果这是真的,那么首先让我们假设您的纹理已输出1.0.0作为alpha值。清除缓冲区后,混合功能应为GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA颜色。这意味着即将到来的颜色将与其源alpha相乘并混合为当前颜色:

  • 对于字母1.0,这意味着将完全使用源颜色(乘以1.0)并完全忽略目标颜色(乘以0.0destination = source*1.0 + destination*.0。在通用语言中,这个像素将被新颜色完全重绘。
  • 对于字母.0,这意味着将完全忽略源颜色(乘以.0)并完全使用目标颜色(乘以1.0destination = source*0.0 + destination*1.0。在通用语言中,这个像素将完全保留原样,新颜色将被忽略。

您可能甚至不需要使用混合的alpha分量,因此我想GL_ZERO, GL_ONE可以应用,表示您将保留来自glClear的Alpha通道。否则,相同的规则适用于Alpha通道,因此请执行您需要的操作。

如果您需要进一步定义" opaque"你可能想在着色器中控制它。可以应用某些阈值,如:

void main(void)
{
    vec4 texel = texture(tex0, v_uv);
    color = vec4(texel.rgb, step(texel.a, 0.5));
}

请注意,即使输入纹理只有0.01.0值,除非在纹理上使用nearest滤镜,否则在着色器中可能不是这种情况。插值可以是任何大小。