为什么我会在我的 GLSL 着色器中看到这些混合瑕疵?
Why am I seeing these blending artifacts in my GLSL shader?
我正在尝试创建一个着色器,该着色器可以叠加混合彩色 "blobs"(有点像粒子)。这看起来应该是一项简单的任务,但当斑点混合时,我变得很奇怪 "banding"-like artifacts。
首先,这是我想要的行为(使用 Photoshop 图层复制):
请注意,三个颜色层都设置为混合模式 "Linear Dodge (Add)",据我所知,这是 Photoshop 的 "additive" 混合模式。
如果我合并颜色图层并将生成的图层设置为 "Normal" 混合,然后我可以随意更改背景颜色。
显然加法混合不会在非黑色背景上工作,所以最后我也会 want/need 着色器来支持这种颜色的预合并,然后最终混合到一个可以有任何颜色。 但是,我现在满足于只专注于让 additive-on-top-of-black 混合正常工作,因为它不是。
这是我的着色器代码的当前状态。
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
(不过,我认为它们在这个之前链接的视频中更为普遍。动作真的让它们突然出现。)
也作为静态图片进行对比:
基本上,有"edges"出现在某些魔法门槛上。我不知道他们是如何到达那里或如何摆脱他们的。非常感谢您的帮助。
内线是 totalColor.w
达到 1 的地方,因此 alpha
在其中被限制为 1。你用白色描出的外面的是圆圈的边缘。
我修改了你的 ShaderToy link,将 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);
(以平滑圆圈的边缘)和现在看起来像第一张图片了。
我正在尝试创建一个着色器,该着色器可以叠加混合彩色 "blobs"(有点像粒子)。这看起来应该是一项简单的任务,但当斑点混合时,我变得很奇怪 "banding"-like artifacts。
首先,这是我想要的行为(使用 Photoshop 图层复制):
请注意,三个颜色层都设置为混合模式 "Linear Dodge (Add)",据我所知,这是 Photoshop 的 "additive" 混合模式。
如果我合并颜色图层并将生成的图层设置为 "Normal" 混合,然后我可以随意更改背景颜色。
显然加法混合不会在非黑色背景上工作,所以最后我也会 want/need 着色器来支持这种颜色的预合并,然后最终混合到一个可以有任何颜色。 但是,我现在满足于只专注于让 additive-on-top-of-black 混合正常工作,因为它不是。
这是我的着色器代码的当前状态。
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 (不过,我认为它们在这个之前链接的视频中更为普遍。动作真的让它们突然出现。)
也作为静态图片进行对比:
基本上,有"edges"出现在某些魔法门槛上。我不知道他们是如何到达那里或如何摆脱他们的。非常感谢您的帮助。
内线是 totalColor.w
达到 1 的地方,因此 alpha
在其中被限制为 1。你用白色描出的外面的是圆圈的边缘。
我修改了你的 ShaderToy link,将 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);
(以平滑圆圈的边缘)和现在看起来像第一张图片了。