为什么我的 GLSL 着色器呈现分裂?

Why is my GLSL shader rendering a cleavage?

我正在研究 2D 中的延迟照明技术,使用帧缓冲区使用 GL_MAX 混合方程式累积光源。

这是我将一个光源(几何体是没有纹理的四边形,我只使用片段着色器进行着色)渲染到我的缓冲区时得到的结果:

这正是我想要的 - 光源衰减。然而,当两个光源彼此靠近时,当它们重叠时,它们似乎在它们相遇的地方产生较低的 RGB 值,如下所示:

为什么两者之间有一条较暗的线?我期望使用 GL_MAX 混合方程它们可以平滑地相互混合,使用最大值每个位置的碎片。

这是 FBO 的设置(使用 LibGDX):

    Gdx.gl.glClearColor(0.14f, 0.14f, 0.19f, 1); 
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    Gdx.gl.glBlendEquation(GLMAX_BLEND_EQUATION);
    Gdx.gl.glBlendFunc(GL20.GL_SRC_COLOR, GL20.GL_DST_COLOR);
    Gdx.gl.glEnable(GL20.GL_BLEND);

我认为在使用这个等式时实际上不需要调用 glBlendFunc。 GLMAX_BLEND_EQUATION 设置为 0x8008

varying vec2 v_texCoords;
varying vec2 v_positionRelativeToLight;
uniform sampler2D u_texture;
uniform vec3 u_lightPosition;
uniform vec3 u_lightColor;

void main() {
    float distanceToLight = length(v_positionRelativeToLight);
    float falloffVarA = 0.1;
    float falloffVarB = 1.0;
    float attenuation = 1.0 / (1.0 + (falloffVarA*distanceToLight) + (falloffVarB*distanceToLight*distanceToLight));
    float minDistanceOrAttenuation = min(attenuation, 1.0-distanceToLight);
    float combined = minDistanceOrAttenuation * attenuation;
    gl_FragColor = vec4(combined, combined, combined, 1.0);
}

这里传递了额外的变量,因为这个片段着色器通常更复杂,但我将其缩减以仅显示衰减和混合的行为方式。

这发生在我渲染的每个光源相遇的地方 - 而不是我期待的颜色,两个光源的相遇 - 两个四边形之间的等距点,是我想要的更深的颜色'我期待。知道为什么以及如何解决它吗?

这是从第二张图像中减去第一张图像的结果:

第一个的背景不是很黑,因此右侧变黄了,但除此之外,您可以清楚地看到左侧的黑色区域保留了原始值,较暗的弧形区域是两个灯的值评估但右侧更大,然后是原始光未接触到的右侧所有区域。

因此我认为您正在获得最大选择混合。但是你想要的是加法混合:

Gdx.gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE);

... 并保留混合方程的默认值 GL_FUNC_ADD

您的结果是最大混合的预期外观(就像 Photoshop 中的加亮混合模式)。深色接缝看起来不合适可能是因为每盏灯的非线性衰减,但它在数学上是正确的。如果你给它引入一种明亮的非白色光,它看起来会更令人反感。

如果将灯光渲染到具有反转颜色和乘法混合的帧缓冲区,然后使用反转颜色渲染帧缓冲区,则可以解决此问题。然后数学计算出来没有接缝,但它看起来不会像加法混合产生的那样异常明亮。

在帧缓冲区上使用纯白色透明颜色,然后使用标准 GL_ADD 混合方程和混合函数 GL_ONE_MINUS_DST_COLOR 渲染灯光。然后将您的 FBO 纹理渲染到屏幕上,再次反转颜色。

用你的方法画了两盏灯

加法绘制的两盏灯

两盏灯,依次绘制 GL_ONE_MINUS_DST_COLOR、GL_ZERO 和 GL_ADD

以上结果,反转