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

片段着色器渲染随机纹理出现线条伪影:排查与UV偏移可行性分析

随机纹理渲染的线条伪影问题

我在用片段着色器渲染随机纹理时出现了线条状伪影,试过修改纹理的minFilter参数但没用。想问问问题可能出在代码哪个阶段?能不能通过偏移极端UV坐标解决?

相关着色器代码:

uniform sampler2D uTexture;
        
vec2 hash2D2D (vec2 s){
    return fract(sin(mod(vec2(dot(s, vec2(127.1, 311.7)), dot(s, vec2(269.5,183.3))), 3.14159))*43758.5453);
}

vec4 tex2DStochastic(sampler2D tex, vec2 UV){
    mat4x3 BW_vx;
    vec2 skewUV = mat2x2(1.0 , 0.0 , -0.57735027 , 1.15470054) * UV;
    vec2 vxID = vec2(floor(skewUV));
    vec3 tNoise = vec3(fract(skewUV), 0);
    tNoise.z = 1.0 - tNoise.x - tNoise.y;   
    
    if(tNoise.z > 0.0){
        BW_vx = mat4x3(
            vec3(vxID, 0),
            vec3(vxID + vec2(0, 1), 0),
            vec3(vxID + vec2(1, 0), 0),
            tNoise.zyx
        );
    }else{
        BW_vx = mat4x3(
            vec3(vxID + vec2 (1, 1), 0),
            vec3(vxID + vec2 (1, 0), 0),
            vec3(vxID + vec2 (0, 1), 0),
            vec3(-tNoise.z, 1.0-tNoise.y, 1.0-tNoise.x)
        );
    }

    return  texture2D( tex, (UV + hash2D2D(BW_vx[0].xy)) ) * (BW_vx[3].x)+
            texture2D( tex, (UV + hash2D2D(BW_vx[1].xy)) ) * (BW_vx[3].y)+
            texture2D( tex, (UV + hash2D2D(BW_vx[2].xy)) ) * (BW_vx[3].z);
}


vec4 color = tex2DStochastic(uTexture, vUv*5.0);

输出效果:
随机纹理线条伪影


问题定位

线条伪影核心出现在三角形网格的边界硬分支判断阶段——也就是代码里tNoise.z > 0.0的分支切换逻辑。当UV处于网格边界附近时,相邻像素可能会进入不同分支,导致采样的网格顶点ID(vxID)突变,哈希函数输出的偏移量随之跳变,最终形成明显的线条断层。修改minFilter没用,因为伪影不是纹理过滤导致的,而是采样逻辑的不连续性。

极端UV偏移的可行性

可以偏移极端UV,但这只是治标不治本的方法——它只能掩盖局部边界的问题,没法从根源解决分支切换带来的采样突变。

具体修复方案

1. 用平滑权重替代硬分支

去掉if-else的硬判断,改为对所有可能的网格顶点采样,并用平滑过渡的权重混合结果,彻底消除边界处的采样突变:

vec4 tex2DStochastic(sampler2D tex, vec2 UV){
    vec2 skewUV = mat2x2(1.0 , 0.0 , -0.57735027 , 1.15470054) * UV;
    vec2 vxID = floor(skewUV);
    vec3 tNoise = vec3(fract(skewUV), 0);
    tNoise.z = 1.0 - tNoise.x - tNoise.y;   

    // 计算平滑权重,将负权重置0后归一化
    vec3 weights = max(tNoise, 0.0);
    float weightSum = dot(weights, vec3(1.0));
    weights /= weightSum;

    // 采样四个网格顶点对应的偏移纹理
    vec4 sample0 = texture2D(tex, UV + hash2D2D(vxID));
    vec4 sample1 = texture2D(tex, UV + hash2D2D(vxID + vec2(0, 1)));
    vec4 sample2 = texture2D(tex, UV + hash2D2D(vxID + vec2(1, 0)));
    vec4 sample3 = texture2D(tex, UV + hash2D2D(vxID + vec2(1, 1)));

    // 混合四个采样结果,包含tNoise.z为负时的权重
    return sample0 * weights.z + sample1 * weights.x + sample2 * weights.y + sample3 * max(-tNoise.z, 0.0) / weightSum;
}

2. 优化哈希函数的连续性

原哈希函数在整数输入跳变时,输出可能存在微小不连续,可以换成更平滑的实现:

vec2 hash2D2D(vec2 s) {
    vec3 p = vec3(s.xy, 1.0) * vec3(127.1, 311.7, 269.5);
    p = fract(p * 0.015);
    p += dot(p, p.yzx + 19.19);
    return fract(vec2(p.x * p.y, p.y * p.z));
}

这个版本的哈希函数在输入变化时输出过渡更自然,能进一步减少边界处的跳变伪影。

3. 调整UV缩放时机

当前代码先缩放UV再计算斜网格,可能导致边界密度过高。可以尝试先计算斜网格再缩放,或者调整缩放倍数,避免边界过于密集放大伪影:

// 改成先计算skewUV再缩放
vec2 skewUV = mat2x2(1.0 , 0.0 , -0.57735027 , 1.15470054) * (vUv * 5.0);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:44:55