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

GLSL噪声着色器出现锐利线条:原因排查与修复咨询

问题描述

我正在学习使用GLSL编写噪声着色器,拼凑出了以下可运行的片段着色器(顶点着色器为默认):

float rand(vec2 cord)
{
    return fract(sin(dot(cord, vec2(12.9898, 78.233)))*43758.5453);
}

void main()
{
    vec2 uv = gl_FragCoord.xy;

    vec2 i = floor(uv);
    vec2 f = fract(uv);

    vec2 c0 = i + vec2(0.0,0.0);
    vec2 c1 = i + vec2(1.0,0.0);
    vec2 c2 = i + vec2(0.0,1.0);
    vec2 c3 = i + vec2(1.0,1.0);

    float r0 = rand(c0);
    float r1 = rand(c1);
    float r2 = rand(c2);
    float r3 = rand(c3);

    float b = mix(r0,r1,f.x);
    float t = mix(r2,r3,f.x);

    gl_FragColor = vec4(mix(b,t,f.y),0.0,0.0,1.0);
}

该着色器本应在整数点生成随机值并进行插值,但在整数边界处出现了明显的锐利线条。我猜测可能是舍入误差导致,因rand函数对2D位置变化极为敏感,整数点处的微小舍入差异引发了较大变化。现咨询:该问题判断是否正确?若正确该如何修复?若错误该如何更好地排查问题?


问题分析与修复

1. 问题判断:你的猜测完全正确

gl_FragCoord.xy是浮点型像素坐标,在整数像素边界附近,浮点精度误差会导致相邻像素的floor(uv)结果不一致:比如某像素的uv.x本应为整数N,却因精度偏差变成N-1.0000001,此时floor(uv.x)得到N-1;而相邻像素的uv.x是N.0000001,floor结果为N。这种网格划分的跳变,加上你的rand函数对输入微小变化极度敏感,直接导致插值结果出现突变,形成锐利线条。

2. 修复方案

方案一:强制对齐整数网格

将gl_FragCoord.xy先转换为整数类型再转回浮点,消除边界处的精度误差:

void main()
{
    vec2 uv = vec2(ivec2(gl_FragCoord.xy)); // 先转整数再转回浮点,确保网格严格对齐
    vec2 i = floor(uv);
    vec2 f = fract(gl_FragCoord.xy); // 小数部分保留原始浮点坐标的精度

    vec2 c0 = i + vec2(0.0,0.0);
    vec2 c1 = i + vec2(1.0,0.0);
    vec2 c2 = i + vec2(0.0,1.0);
    vec2 c3 = i + vec2(1.0,1.0);

    float r0 = rand(c0);
    float r1 = rand(c1);
    float r2 = rand(c2);
    float r3 = rand(c3);

    float b = mix(r0,r1,f.x);
    float t = mix(r2,r3,f.x);

    gl_FragColor = vec4(mix(b,t,f.y),0.0,0.0,1.0);
}

这样i的取值会严格对应整数网格,不会出现边界处的跳变。

方案二:替换更鲁棒的随机函数

原rand函数依赖sin和大乘数,对输入精度偏差过于敏感。可以改用基于哈希的稳定实现(GLSL 130+支持位操作):

float rand(vec2 p)
{
    p = fract(p * vec2(127.1, 311.7));
    p += dot(p, p + 33.33);
    return fract(p.x * p.y);
}

这种哈希函数对输入的微小浮点偏差鲁棒性更强,即使存在少量精度误差,输出的随机值也不会出现剧烈跳变。

3. 通用排查思路(若猜测错误时)

  • 可视化调试:将i.x或i.y作为颜色输出,查看整数网格是否在边界处出现异常跳变,确认网格划分是否正常。
  • 隔离测试rand函数:固定输入整数坐标,对比相邻整数点的输出,确认是否因精度问题导致随机值突变。
  • 替换插值逻辑:用固定常量代替rand输出,测试插值是否正常,排除mix函数的使用问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:21:58