为什么衰减光的强度会不平滑地降低?

Why is there a non-smooth reduction in intensity for attenuated light?

我正在尝试在 Phong 着色器中实现光衰减。 pixel/fragment 着色器执行以下计算(每个光源):

float3 refl = reflect(e, n);
float dist = length(L.xyz);
float3 l = normalize(L.xyz);
float attn = 1.0 / (1.0 + 1.0 / 30 * dist + 1.0 / 700 * dist * dist);
d += saturate(dot(n,l)) * gLightColor[i].xyz * attn.xxx;
s += pow(saturate(dot(-refl, l)), power) * gLightColor[i].xyz;

其中:

为简单起见,我忽略了衰减对镜面反射颜色的影响,并使用了一些内置的衰减系数。通常,我得到正确的行为:

当我增加光源和物体之间的距离时,强度的降低变得不平滑:

我得到的是圆环而不是渐变。这是浮点精度的问题吗?如何在所有距离上获得平滑的强度变化?

使用 D3D 9 和 HLSL 着色器模型 3。

您正在遇到 color banding。当你降低光的强度时,你基本上会越来越多地拉伸渐变。由于每种颜色都由三个 8 位颜色通道显示,因此输出精度有限。在某些时候,当一种颜色的区域变得太宽时,您可以看到两种颜色之间的单个台阶,因为您的眼睛可以识别颜色的两个平坦区域之间的边界,即使它们接近 (0, 64, 64) 到(0, 63, 63).

由于普通显示器仅支持 24 位颜色,唯一可行的解​​决方案 afaik 是应用 dithering. This breaks up the flat color areas by adding a noise pattern, so the eye can't catch the borders so easily. I'm sure a google search shows some interesting links, how to implement some kind of dithering (such as this)。