WebGL网格线宽度不均:每5条线异常变粗问题排查
网格线每5条异常变粗的问题排查请求
我用以下片元着色器绘制网格:
precision highp float; uniform vec2 CANVAS_SIZE; uniform float GRID_WIDTH; uniform vec4 GRID_COLOR; float isGridLine(float ordinate, float target, float halfThickness) { return step(ordinate, target + halfThickness) * step(target - halfThickness, ordinate); } void main() { vec2 uv = (gl_FragCoord.xy / CANVAS_SIZE); float halfGridWidth = GRID_WIDTH / 2.0; float gridLine = 0.0; for (float i = 0.0; i < 1.0; i += 0.05) { gridLine += isGridLine(uv.y, i, halfGridWidth); gridLine += isGridLine(uv.x, i, halfGridWidth); } gl_FragColor = mix(vec4(uv.rg, 0.0, 1.0), GRID_COLOR, step(1.0, gridLine)); }
顶点着色器仅通过JavaScript传入的顶点位置生成填充视口的静态平面,代码如下:
precision highp float; attribute vec2 _vertexPosition; void main() { gl_Position = vec4(_vertexPosition, 0.0, 1.0); }
目前遇到异常:每第5条网格线会略微变粗,但着色器中并无针对第5条线的特殊逻辑。已完成排查:排除浮点精度问题(高低精度模式下均存在该异常),更换不同屏幕分辨率后,异常表现一致。恳请协助分析该问题的原因。

问题原因分析
核心问题出在循环的浮点累加精度误差上:
- 0.05是二进制无法精确表示的无限循环浮点数,用
i += 0.05累加时,多次循环后会产生偏差。当循环到第20次时,理论上i应等于1.0,但实际累加值会略小于1.0,导致循环多执行一次。 - 这次额外循环会在
i≈1.0的位置再画一条线,而这个位置和最后一条正常线(i=0.95)的位置极度接近,两条线重叠就造成了“变粗”的视觉效果——每20次循环对应4个0.05间隔(即第5条线),所以每第5条线会出现重叠。
修复方案
有两种简单的修复方式:
- 改用整数循环计算目标位置:彻底避免浮点累加误差,示例代码:
void main() { vec2 uv = (gl_FragCoord.xy / CANVAS_SIZE); float halfGridWidth = GRID_WIDTH / 2.0; float gridLine = 0.0; // 用整数循环控制次数,计算每个目标位置 for (int i = 0; i < 20; i++) { float target = float(i) * 0.05; gridLine += isGridLine(uv.y, target, halfGridWidth); gridLine += isGridLine(uv.x, target, halfGridWidth); } gl_FragColor = mix(vec4(uv.rg, 0.0, 1.0), GRID_COLOR, step(1.0, gridLine)); }
- 调整循环终止条件:直接限制循环次数为20次,把
i < 1.0改成i <= 0.95,避免多执行一次循环。
内容的提问来源于stack exchange,提问作者BanksySan
相关产品推荐
相关产品推荐

