ShaderToy/GLSL中基于边距离着色矩形时对角线出现暗纹问题
解决ShaderToy中矩形距离着色的对角线暗纹问题
嘿,这个坑我之前踩过!你用max(uvn.y, uvn.x)来计算到矩形最近边的距离完全搞反了逻辑——这也是对角线暗纹出现的核心原因。
为什么max()会出问题?
max(uvn.x, uvn.y)取的是UV分量里较大的那个值,这和“到最近边的距离”完全不沾边:
- 假设你的UV是归一到
[0,1]×[0,1](从矩形一个角到对角),那么到左边的距离是uvn.x,到右边是1.0-uvn.x,到上下边同理。最近边的距离应该是这四个值里的最小值,而不是最大值。 - 更关键的是,
max()在uvn.x=uvn.y的对角线上会出现导数不连续的情况——也就是颜色梯度突然跳变,视觉上就是你看到的暗纹,完全做不到平滑插值。
正确的解决方法
第一步:计算正确的最近边距离
先根据你的UV归一方式选择对应的计算:
- UV范围是
[-1,1]×[-1,1](中心在原点):
// 到左右边的距离:1减去x绝对值,到上下边同理 float dist_x = 1.0 - abs(uvn.x); float dist_y = 1.0 - abs(uvn.y); // 取最小值得到最近边距离 float dist_to_edge = min(dist_x, dist_y);
- UV范围是
[0,1]×[0,1](从角落到对角):
float dist_left = uvn.x; float dist_right = 1.0 - uvn.x; float dist_bottom = uvn.y; float dist_top = 1.0 - uvn.y; // 多层min取四个方向里的最小值 float dist_to_edge = min(min(dist_left, dist_right), min(dist_bottom, dist_top));
第二步:添加平滑过渡(可选但推荐)
如果想要颜色过渡更柔和,避免硬边,可以用smoothstep或者自定义平滑min函数:
- 用
smoothstep快速实现:
// smoothstep(边缘起始值, 边缘结束值, 输入值) // 这里0.0到0.1的范围是平滑过渡区域,可根据需求调整 float smooth_dist = smoothstep(0.0, 0.1, dist_to_edge); vec3 color = vec3(smooth_dist);
- 自定义带参数的平滑min(控制过渡强度):
float smoothmin(float a, float b, float k) { float h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0); return mix(b, a, h) - k*h*(1.0-h); } // 使用时,k值越大过渡越平缓 float smooth_dist = smoothmin(dist_x, dist_y, 0.1); vec3 color = vec3(smooth_dist);
替换掉原来的max()逻辑后,对角线的暗纹就会消失,颜色也会按照到最近边的距离平滑变化啦。
内容的提问来源于stack exchange,提问作者Ivelate
相关产品推荐
相关产品推荐

