GLSL中sin/cos返回值超出[-1,1]范围的原因咨询
GLSL sin/cos 超出[-1,1]范围的跨设备异常解释
问题描述
我在ShaderToy中编写了如下GLSL着色器代码:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) { // Normalized pixel coordinates (from 0 to 1) vec2 uv = fragCoord/iResolution.xy; vec3 col = vec3(0.); col.r = cos(uv.x* 0.05) > 1. ? 1. : 0.; col.g = sin(uv.y*0.05 - 1.5707963267948966) < -1. ? 1. : 0.; // Output to screen fragColor = vec4(col,1.0); }
根据数学定义,sin和cos函数的返回值应始终处于[-1,1]区间内,因此我预期屏幕会完全显示黑色。但实际在Mac设备的Chrome和Firefox浏览器中运行时,会看到一条红色窄条和一条绿色窄条,而在iPad和iPhone上无此现象,恳请解释该异常的原因。
原因解释
这是浮点数精度误差导致的硬件级计算偏差,具体细节如下:
- 不同GPU的浮点精度实现存在差异:Mac上的桌面级GPU(如Apple Silicon M系列或Intel核显)在计算三角函数时,因浮点数舍入、近似算法的特性,可能产生极轻微的结果溢出(比如
1.0000001或-1.0000001)。而iOS设备的移动GPU对三角函数的精度校准更严格,或采用了不同的近似逻辑,避免了这种微小溢出。 - 代码逻辑放大了误差:你的判断条件刚好卡在三角函数的理论边界上,一旦计算结果因精度问题略超出[-1,1],就会触发颜色通道的赋值,形成可见的窄条。比如
uv.x*0.05的范围是0到0.05,cos在该区间的结果非常接近1,微小的浮点误差就可能让结果略大于1;同理,uv.y*0.05 - π/2的范围接近-π/2,sin在此处的理论值是-1,计算误差可能让结果略小于-1。
验证与修复方案
- 验证:将判断条件改为
cos(uv.x*0.05) > 1.000001或sin(uv.y*0.05 - 1.5707963267948966) < -1.000001,异常条纹会消失,屏幕显示预期的黑色。 - 修复:实际开发中,避免依赖三角函数的严格边界做判断,或者给条件添加微小容差,比如用
cos(...) > 1.0 + 1e-6来过滤精度误差带来的异常触发。
内容的提问来源于stack exchange,提问作者Gabriel
相关产品推荐
相关产品推荐

