【问题标题】:Why am I seeing these blending artifacts in my GLSL shader?为什么我会在我的 GLSL 着色器中看到这些混合伪影?
【发布时间】:2019-09-15 19:52:02
【问题描述】:

我正在尝试创建一个着色器,将彩色“斑点”(有点像粒子)叠加在一起。这似乎应该是一项简单的任务,但是当斑点混合时,我会得到奇怪的“条带”状伪影。

首先,这是我所追求的行为(使用 Photoshop 图层复制):

请注意,三个颜色层都设置为混合模式“线性减淡(添加)”,据我了解,这是 Photoshop 的“加法”混合模式。

如果我合并颜色图层并将生成的图层设置为“正常”混合,那么我可以随意更改背景颜色。

显然,加法混合在非黑色背景上不起作用,所以最后我还希望/需要着色器在最终混合到可能具有任何颜色的背景之前支持这种颜色的预合并。 但是,我现在满足于只专注于让加法黑色混合正常工作,因为事实并非如此。

这是我当前状态下的着色器代码。

const int MAX_SHAPES = 10;
vec2 spread = vec2(0.3, 0.3);
vec2 offset = vec2(0.0, 0.0);
float shapeSize = 0.3;
const float s = 1.0;
float shapeColors[MAX_SHAPES * 3] = float[MAX_SHAPES * 3] (
  s, 0.0, 0.0,
  0.0, s, 0.0,
  0.0, 0.0, s,
  s, 0.0, 0.0,
  s, 0.0, 0.0,
  s, 0.0, 0.0,
  s, 0.0, 0.0,
  s, 0.0, 0.0,
  s, 0.0, 0.0,
  s, 0.0, 0.0
);

vec2 motionFunction (float i) {
  float t = iTime;

  return vec2(
    (cos(t * 0.31 + i * 3.0) + cos(t * 0.11 + i * 14.0) + cos(t * 0.78 + i * 30.0) + cos(t * 0.55 + i * 10.0)) / 4.0,
    (cos(t * 0.13 + i * 33.0) + cos(t * 0.66 + i * 38.0) + cos(t * 0.42 + i * 83.0) + cos(t * 0.9 + i * 29.0)) / 4.0
  );
}

float blend (float src, float dst, float alpha) {
  return alpha * src + (1.0 - alpha) * dst;
}

void mainImage (out vec4 fragColor, in vec2 fragCoord) {
    float aspect = iResolution.x / iResolution.y;
    float x = (fragCoord.x / iResolution.x) - 0.5;
    float y = (fragCoord.y / iResolution.y) - 0.5;
    vec2 pixel = vec2(x, y / aspect);

    vec4 totalColor = vec4(0.0, 0.0, 0.0, 0.0);
    for (int i = 0; i < MAX_SHAPES; i++) {
        if (i >= 3) {
            break;
        }

        vec2 shapeCenter = motionFunction(float(i));

        shapeCenter *= spread;
        shapeCenter += offset;
        float dx = shapeCenter.x - pixel.x;
        float dy = shapeCenter.y - pixel.y;
        float d = sqrt(dx * dx + dy * dy);
        float ratio = d / shapeSize;
        float intensity = 1.0 - clamp(ratio, 0.0, 1.0);
        totalColor.x = totalColor.x + shapeColors[i * 3 + 0] * intensity;
        totalColor.y = totalColor.y + shapeColors[i * 3 + 1] * intensity;
        totalColor.z = totalColor.z + shapeColors[i * 3 + 2] * intensity;
        totalColor.w = totalColor.w + intensity;
    }

    float alpha = clamp(totalColor.w, 0.0, 1.0);
    float background = 0.0;
    fragColor = vec4(
        blend(totalColor.x, background, alpha),
        blend(totalColor.y, background, alpha),
        blend(totalColor.z, background, alpha),
        1.0
    );
}

这是一个 ShaderToy 版本,您可以在其中实时查看它 — https://www.shadertoy.com/view/wlf3RM 或者作为视频——https://streamable.com/un25t

视觉伪影应该很明显,但这里有一个视频可以指出它们:https://streamable.com/kxaps (不过,我认为它们在此之前链接的视频中更为普遍。这个动作确实让它们弹出。)

也可以作为静态图片进行对比:

基本上,在某些神奇的阈值上会出现“边缘”。我不知道他们是如何到达那里或如何摆脱他们的。非常感谢您的帮助。

【问题讨论】:

    标签: opengl-es glsl glsles


    【解决方案1】:

    内线是 totalColor.w 达到 1 的位置,因此 alpha 在它们内部被限制为 1。你用白色描绘的外侧是圆圈的边缘。

    我修改了您的 ShaderToy 链接,将 float alpha = clamp(totalColor.w, 0.0, 1.0); 更改为 float alpha = 1.0; 并将 float intensity = 1.0 - clamp(ratio, 0.0, 1.0); 更改为 float intensity = smoothstep(1.0, 0.0, ratio);(以平滑圆圈的边缘),现在它看起来像第一张图片。

    【讨论】:

    • 非常感谢!这使得黑色背景场景按预期工作。还有关于 Smoothstep 的 TIL。
    猜你喜欢
    • 2020-07-08
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    相关资源
    最近更新 更多