You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复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;
}

问题根源

  1. blanket函数区间判断逻辑失效:map函数中已对p.y执行pmod(p.y, 1.0)归一化,导致传入blanket的p.y被限制在0-1区间,再用原始的p.y > 0 && p.y <1这类区间判断完全错误,引发颜色逻辑混乱导致闪烁。
  2. 层级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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:44:54