理解镜面反射反光度和风氏模型反射缺陷
在风氏模型中,计算镜面反射最后要用物体反光度作为指数,对视觉中看到的光强进行幂运算得到最终结果。
1 | float spec = pow(max(dot(view_direction, light_reflect_direction), 0.0f), material.shininess); |
shininess(反光度)是控制镜面高光 “锐利程度” 的核心参数。
我们把上面的语句拆开:
dot(view_direction, light_reflect_direction),这计算的是视线方向与反射光方向夹角的余弦值(范围 [-1, 1]),我们在外层加了个max(..., 0)是默认当反射光和视线成钝角时(余弦值为负数),相当于光线没进入人眼,反光强度为0(通过学习Blinn-Phong模型我们知道这并不自然)pow(..., shininess),pow函数作为一个衰减函数,在反光度shininess很小时会衰减得很慢,例如,0.8^1 = 0.8,0.5^1 = 0.5,意味着较大范围的角度都能贡献明显的高光(高光区域大而模糊);而反光度shininess很大时会衰减得很快,例如,8^100 ≈ 0,0.95^100 ≈ 0.6,意味着只有视线与反射光方向非常接近时(夹角极小)才有高光(高光区域小而锐利)
所以反光度某种意义上是一个用来模拟表面的粗糙 / 光滑程度的参数,反光度越小,物体表面越粗糙,越大越光滑(下面两个参数资料来自AI回答)。
- 低 shininess(如 1~32):模拟粗糙表面(如木头、石头、磨砂塑料)。
这类表面会把光线向四面八方散射,所以镜面高光范围大、边缘模糊,亮度随角度变化平缓。 - 高 shininess(如 64~1024):模拟光滑表面(如金属、镜子、抛光塑料)。
这类表面的反射更集中,只有在视线接近反射光方向时才能看到高光,所以高光区域小、边缘锐利,亮度随角度变化剧烈。
由此引申出风氏模型计算镜面光的不自然之处,在物体表面粗糙时(反光度小),反光的范围大,在远处表面即使光线和视线形成钝角,我们应该还是能看到一些反射光而不是直接为0。
我们可以想象一下为什么风氏模型镜面反射表现不自然;比如我们面前放着一张砂纸,太阳在我们脑后,这时反射光和视线是为钝角的,但我们依然可以看到砂纸表面斑驳的亮点,究其原因就是砂纸表面粗糙,光线在某些地方还是能和视线形成锐角的,而不是超过一定角度就直接变暗。
我们在Blinn-Phong模型中利用半程向量解决了这个问题,但实际上这也只是一种模拟罢了,只是比传统风氏模型更自然点,不会出现在某处光线突然变暗的情况。
应该可以这么去理解,真正光滑的表面就是一个表面,而粗糙的表面是由无数细小杂乱的表面组合而成的,要计算真正的反射计算量太大,实现也过于复杂。
所以微观上可以这样理解反光度shininess,它小,表示无数小平面朝向极乱;它大,表示无数小平面朝向趋于一致。