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

如何修复OpenGL片段着色器生成网格的闪烁(scintillation)伪影?

解决方案:基于屏幕像素的网格线渲染

你的问题核心在于网格线宽是基于纹理空间的固定比例定义的,没有考虑相机旋转、缩放时,纹理空间到屏幕像素空间的映射会发生变化——比如45度旋转时,纹理空间的单位长度在屏幕上会被拉伸,导致同一线宽在屏幕上的像素数忽多忽少,平移时还会因为采样对齐问题产生闪烁。

要解决这个问题,必须基于屏幕像素来定义网格线宽,让线宽始终保持固定的像素数量,不受相机变换影响。下面是修改后的代码和关键思路:

修改后的片段着色器代码

if (uDrawGrid) {
    vec2 uv = fTexCoordinate;
    // 设定网格线的目标像素宽度(比如2像素,可根据需求调整)
    float targetLinePixelWidth = 2.0;
    // 设定网格间距(纹理空间单位,对应原代码的千分位精度)
    float gridUVSpacing = 0.001;

    // 获取当前纹理坐标的屏幕像素导数:计算每个屏幕像素对应纹理空间的变化量
    vec2 dUVdx = dFdx(uv);
    vec2 dUVdy = dFdy(uv);
    // 计算纹理空间中,对应1个屏幕像素的长度(综合x、y方向的变换)
    vec2 uvPerPixel = sqrt(dUVdx * dUVdx + dUVdy * dUVdy);

    // 转换为纹理空间的线宽阈值:目标像素宽度 × 每个像素对应的纹理长度
    vec2 lineUVThreshold = targetLinePixelWidth * uvPerPixel;

    // 计算当前片段到最近网格线的距离
    vec2 gridFract = fract(uv / gridUVSpacing);
    vec2 gridDist = min(gridFract, 1.0 - gridFract) * gridUVSpacing;

    // 用平滑过渡判断是否属于网格线区域,避免硬边缘的闪烁
    float lineXAlpha = smoothstep(lineUVThreshold.x, lineUVThreshold.x * 0.9, gridDist.x);
    float lineYAlpha = smoothstep(lineUVThreshold.y, lineUVThreshold.y * 0.9, gridDist.y);
    float lineAlpha = clamp(lineXAlpha + lineYAlpha, 0.0, 1.0);

    if (lineAlpha > 0.0) {
        // 混合网格颜色与底层颜色(与原代码混合逻辑一致)
        vec4 gridColor = vec4(0.25 + topColor.r * 0.5, 0.25 + topColor.g * 0.5, 0.25 + topColor.b * 0.5, 1.0);
        color = mix(color, gridColor, lineAlpha);
    }
}

关键改进点说明

  1. 基于屏幕像素定义线宽
    使用GLSL内置函数dFdx/dFdy获取纹理坐标在屏幕像素上的导数,这能精确计算出每个屏幕像素对应纹理空间的长度,从而将目标像素线宽转换为纹理空间的阈值,保证无论相机如何旋转、缩放,网格线在屏幕上的宽度始终一致。

  2. 替换round为fract计算距离
    fract函数直接计算当前坐标到最近网格线的距离,比round更高效,同时避免了千分位截断带来的精度误差,减少平移时的闪烁。

  3. 平滑过渡替代硬判断
    用smoothstep代替原代码的<=硬判断,让网格线边缘有一个小的过渡区间,避免像素边界处的突然跳变,彻底解决闪烁问题。

额外注意事项

  • 如果网格是基于世界空间而不是纹理空间的,只需将代码中的fTexCoordinate替换为世界空间坐标,再用同样的导数方法计算即可。
  • 保持precision highp float;开启,避免导数计算的精度损失。
  • 可根据需求调整targetLinePixelWidth(线宽像素数)和gridUVSpacing(网格间距)参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:34:56