如何修复GLSL中彩色平面的闪烁问题?
彩色平面闪烁问题修复方案
我fork了一个ShaderToy项目,简化后学习时遇到彩色平面闪烁的问题,推测问题出在vec3 blanket(vec3 d, vec3 p, vec3 rd, vec3 col)和vec3 map(vec3 p)函数中,相关代码如下:
vec3 blanket(vec3 d, vec3 p, vec3 rd, vec3 col) { // float g0 = getRug(vec2(p.x - d.z, p.z), d.y); // col = light(p, rd, color(d, g0)); // vec3 v = vec3(g0); // col = v; // vec2 p = uv; // p.x -= d.z; p.z /= 4.; p.z = p.z + .5; p.z = 1. - p.z; p.x -= d.z; p.x /= 4.; p.x += .5; float t = mod(floor(iTime / 1.), 4.); if (p.y > 0. && p.y < 1.0) { if (t == 0.) { col = RED; } else if (t == 1.) { col =BLUE ; } else if (t == 2.) { col = GREEN; } else if (t == 3.) { col =YELLOW ; } } if (p.y > -1. && p.y < 0.0) { if (t == 0.) { col = BLUE; } else if (t == 1.) { col = GREEN; } else if (t == 2.) { col = YELLOW; } else if (t == 3.) { col = RED; } } if (p.y > -2. && p.y < -1.0) { if (t == 0.) { col = GREEN; } else if (t == 1.) { col = YELLOW; } else if (t == 2.) { col = RED; } else if (t == 3.) { col = BLUE; } } if (p.y > -3. && p.y < -2.) { if (t == 0.) { col = YELLOW; } else if (t == 1.) { col = RED; } else if (t == 2.) { col = BLUE; } else if (t == 3.) { col = GREEN; } } if (p.y > -4. && p.y < -3.) { /*if (t == 0.) { col = texture(iChannel0, p.xz).xyz; } else if (t == 1.) { col = texture(iChannel1, p.xz).xyz; } else if (t == 2.) { col = texture(iChannel2, p.xz).xyz; } else if (t == 3.) { col = texture(iChannel3, p.xz).xyz; }*/ if (t == 0.) { col = RED; } else if (t == 1.) { col = BLUE; } else if (t == 2.) { col = GREEN; } else if (t == 3.) { col = YELLOW; } /*else if (t == 2.) { col = vec3(0.0, 0.0, 1.0); } else if (t == 3.) { col = vec3(1.0, 1.0, 0.0); }*/ } return col; } vec3 map(vec3 p) { vec3 a = vec3(0); float t = iTime; // scroll the y axis up all the time p.y -= t - .5; // id of y axis domain repition float id = floor(p.y / 1.0) + .5; // x value to offset carpets so they fly left and right float xoff = max(0.0, (id + t) * 2.0); xoff = xoff * xoff * sign(sin(id * pi)); ; // domain repition in the y axis p.y = pmod(p.y, 1.0); // Add some low poly waves to the carpets // float sb = .7; // float wscl = 0.06; // p.y += psin(p.x * 4.0 + id, sb) * wscl; // p.y -= psin(p.z * 4.0 + id, sb) * wscl; // calculate box sdf a.x = box(p - vec3(xoff, 0, 0), vec3(2, 0.025, 2)); // pass some info to coloring code a.y = id; a.z = xoff; return a; }
问题根源
blanket函数区间判断逻辑失效:map函数中已对p.y执行pmod(p.y, 1.0)归一化,导致传入blanket的p.y被限制在0-1区间,再用原始的p.y > 0 && p.y <1这类区间判断完全错误,引发颜色逻辑混乱导致闪烁。- 层级ID计算不稳定:
map中id = floor(p.y / 1.0) + .5的计算方式存在微小跳变风险,加上blanket与map的时间逻辑未对齐,进一步加剧闪烁。
修复步骤
1. 替换blanket的区间判断依据
放弃使用被归一化的p.y,改用map传递的d.y(存储平面原始层级ID)判断当前层级,保证颜色逻辑准确:
float t = mod(floor(iTime), 4.); float layer = d.y; if (layer == 0.5) { col = (t == 0.) ? RED : (t == 1.) ? BLUE : (t == 2.) ? GREEN : YELLOW; } else if (layer == -0.5) { col = (t == 0.) ? BLUE : (t == 1.) ? GREEN : (t == 2.) ? YELLOW : RED; } else if (layer == -1.5) { col = (t == 0.) ? GREEN : (t == 1.) ? YELLOW : (t == 2.) ? RED : BLUE; } else if (layer == -2.5) { col = (t == 0.) ? YELLOW : (t == 1.) ? RED : (t == 2.) ? BLUE : GREEN; } else if (layer == -3.5) { col = (t == 0.) ? RED : (t == 1.) ? BLUE : (t == 2.) ? GREEN : YELLOW; }
2. 优化map的层级ID计算
简化id计算逻辑,避免跳变:
float id = floor(p.y) + 0.5;
3. 统一时间基准
两处函数使用相同的iTime计算逻辑,确保颜色切换与平面滚动同步。
完整修复后代码片段
vec3 blanket(vec3 d, vec3 p, vec3 rd, vec3 col) { p.z /= 4.; p.z = p.z + .5; p.z = 1. - p.z; p.x -= d.z; p.x /= 4.; p.x += .5; float t = mod(floor(iTime), 4.); float layer = d.y; if (layer == 0.5) { col = (t == 0.) ? RED : (t == 1.) ? BLUE : (t == 2.) ? GREEN : YELLOW; } else if (layer == -0.5) { col = (t == 0.) ? BLUE : (t == 1.) ? GREEN : (t == 2.) ? YELLOW : RED; } else if (layer == -1.5) { col = (t == 0.) ? GREEN : (t == 1.) ? YELLOW : (t == 2.) ? RED : BLUE; } else if (layer == -2.5) { col = (t == 0.) ? YELLOW : (t == 1.) ? RED : (t == 2.) ? BLUE : GREEN; } else if (layer == -3.5) { col = (t == 0.) ? RED : (t == 1.) ? BLUE : (t == 2.) ? GREEN : YELLOW; } return col; } vec3 map(vec3 p) { vec3 a = vec3(0); float t = iTime; p.y -= t - 0.5; float id = floor(p.y) + 0.5; float xoff = max(0.0, (id + t) * 2.0); xoff = xoff * xoff * sign(sin(id * pi)); p.y = pmod(p.y, 1.0); a.x = box(p - vec3(xoff, 0, 0), vec3(2, 0.025, 2)); a.y = id; a.z = xoff; return a; }
内容的提问来源于stack exchange,提问作者little_little_nothing
相关产品推荐
相关产品推荐

