我刚尝试实现镜面高光。问题是,当远离表面移动时,高光变得越来越强烈,高光的边缘变得非常刺眼。当移动太靠近表面时,高光完全消失。
这是我的片段着色器的相关部分。所有计算都在视图空间中。我使用定向太阳光。
// samplers
vec3 normal = texture2D(normals, coord).xyz;
vec3 position = texture2D(positions, coord).xyz;
float shininess = texture2D(speculars, coord).x;
// normalize directional light source
vec3 source;
if(directional) source = position + normalize(light);
else source = light;
// reflection
float specular = 0;
vec3 lookat = vec3(0, 0, 1);
float reflection = max(0, dot(reflect(position, normal), lookat));
int power = 5;
specular = shininess * pow(reflection, power);
// ...
// output
image = color * attenuation * intensity * (fraction + specular);
这是我的灯光缓冲区的截图。你可以看到,最重要的镜筒根本没有镜面高光,而远处的镜筒则闪耀得太强烈。中间的桶根据需要点亮。
我做错了什么?
答案 0 :(得分:2)
您正在从物体位置计算反射矢量,而不是使用反转的光线方向(从物体指向光源)。
这就像在图中使用V代替L:
另外,我认为光泽应该是你的表达的指数,而不是线性增加镜面贡献的东西。
答案 1 :(得分:1)
我认为变量命名让你很困惑。 从我正在阅读的内容(假设你处于相机空间而没有习惯性知识)
vec3 lookat = vec3(0, 0, 1);
float reflection = max(0, dot(reflect(position, normal), lookat));
lookat
是定向灯,position
是实际的lookat
。
确保normal
(它可能已经规范化)并position
(lookat
)已标准化。
一个不太混乱的代码是:
vec3 light_direction = vec3(0, 0, 1);
vec3 lookat = normalize(position-vec3(0,0,0));
float reflection = max(0, dot(reflect(light_direction, normal), -lookat));
如果不对position
进行规范化,则reflection
会有偏差。当position
远离相机vec3(0,0,0)
注意lookat
不是常数;它会改变每个位置。 lookat = vec3(0,0,1)
正在查看视图空间中的单个位置。