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

GLSL值噪声函数中两种br写法为何结果不同且存在断层?

为什么GLSL中vec2(bl.x+1., bl.y)和bl + vec2(1.,0.)会导致值噪声出现断层差异?

问题现象

在实现GLSL值噪声时,两种看似等价的br坐标计算方式,却产生了完全不同的结果:

  • 使用vec2 br = vec2(bl.x+1.,bl.y)时,输出图像出现明显断层;
  • 改成vec2 br = bl + vec2(1.,0.)后,断层完全消失。
    且仅修改br变量时有此影响,修改tl、tr的构造方式不会触发问题。

初始代码(存在断层)

float valueNoise(vec2 v, float n){
    v*=n;
    vec2 bl = floor(v);
    vec2 fr = fract(v);
    vec2 br = vec2(bl.x+1.,bl.y);
    vec2 tl = vec2(bl.x,bl.y+1.);
    vec2 tr = vec2(bl.x+1.,bl.y+1.);
    float top = mix(random2D(tl),random2D(tr), fr.x);
    float bottom = mix(random2D(bl),random2D(br), fr.x);
    return mix(bottom, top, fr.y);
}

修改后代码(修复断层)

float valueNoise(vec2 v, float n){
    v*=n;
    vec2 bl = floor(v);
    vec2 fr = fract(v);
    vec2 br = bl + vec2(1.,0.);
    vec2 tl = vec2(bl.x,bl.y+1.);
    vec2 tr = vec2(bl.x+1.,bl.y+1.);
    float top = mix(random2D(tl),random2D(tr), fr.x);
    float bottom = mix(random2D(bl),random2D(br), fr.x);
    return mix(bottom, top, fr.y);
}

原因分析

这是浮点数精度误差导致的,核心差异在于GLSL对两种运算的处理逻辑:

  1. 分量单独运算的隐患:
    bl是floor(v)的结果,表面上是整数,但当v的数值很大时,某些整数无法被32位浮点数精确存储(比如大于2^24的整数)。此时bl.x+1.的计算可能因为精度损失,得到一个比预期整数小一点点的浮点数(例如本该是10000000的结果,实际存储为9999999.999999998)。当这个值传入random2D()时,函数内部如果再次对坐标做取整/哈希处理,会被识别为和预期不同的整数坐标,导致噪声值突变,产生断层。

  2. 向量加法的稳定性:
    bl + vec2(1.,0.)是直接对整个向量做加法运算,GLSL的向量运算会保证整数浮点数的加法精度(只要数值在可精确表示范围内,整数加1的结果一定是精确的整数浮点数),不会出现上述的精度损失。因此random2D()拿到的是正确的相邻整数坐标,噪声过渡自然平滑。

补充建议

之所以修改tl、tr没出现问题,是因为测试场景中bl.y的数值刚好在浮点数精确表示范围内。如果后续处理更大的y轴坐标范围,tl = vec2(bl.x,bl.y+1.)也可能出现同样的断层问题。建议统一使用向量加法的方式计算所有相邻坐标,避免精度隐患:

vec2 br = bl + vec2(1., 0.);
vec2 tl = bl + vec2(0., 1.);
vec2 tr = bl + vec2(1., 1.);

内容的提问来源于stack exchange,提问作者Ivan Kucha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:00:56