首页 文章

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

提问于
浏览
1

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 sin(时间)中运行也很平滑翻译案例 .

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

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

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

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

我该如何设置这种渲染?

先感谢您 .

UPDATE:

我试过了:

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

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

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

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

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

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

    • 对于alpha 1.0 ,表示将完全使用源颜色(乘以 1.0 )并完全忽略目标颜色(乘以 0.0destination = source*1.0 + destination*.0 . 在通用语言中,该像素将被新颜色完全重绘 .

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

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

    如果您需要进一步定义“opaque”,您可能希望在着色器中控制它 . 某些阈值可能适用于:

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

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

相关问题