镜面高光取决于相机距离
Posted
技术标签:
【中文标题】镜面高光取决于相机距离【英文标题】:Specular highlights depend on camera distance 【发布时间】:2014-01-23 22:02:46 【问题描述】:我刚刚尝试实现镜面高光。问题是当远离表面移动时,高光变得越来越强,高光的边缘变得非常刺眼。当移动太靠近表面时,高光会完全消失。
这是我的片段着色器的相关部分。所有计算都在视图空间中。我使用定向太阳光。
// 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.5, 1.0, 1.5
。这会产生问题吗?不过方向灯和点光源的问题是一样的。
没有足够的代码。展示你如何构建模型视图矩阵。例如,如果你看向量是 ls like x, y, z, 1 这可能是个问题
您应该编辑问题并指定坐标系、查看器和灯光状态。 source
、directional
、light
、arriving
和 faced
未用于最终方程! vec3 lookat = vec3(0, 0, 1);
看起来像定向灯
@a.lasram lookat
是相机的朝向。正如问题中所述,由于我在视图空间中进行所有计算,因此它直指前方。 source
是光的位置,对于点光源它只是由light
位置统一设置,对于定向光,它设置为表面位置加光方向。 arriving
是从光到表面的归一化向量,用于reflection
计算。 “观众和灯光状态”是什么意思?那我会在问题中添加这个。
【参考方案1】:
您正在从对象位置计算反射矢量,而不是使用反转的光方向(从对象指向光源)。
这就像在此图中使用 V 而不是 L:
另外,我认为光泽度应该是你表达的指数,而不是线性乘以高光贡献的东西。
【讨论】:
谢谢。当使用float reflection = max(0, dot(reflect(normalize(source - position), normal), lookat));
时,不再有可见的亮点。当我将specular
乘以 10 时,会出现某种突出显示,但它仍然以某种方式迷失方向。如何进一步调试我的问题?我知道矩阵是正确的,因为漫射照明适用于点光源。
我认为你应该使用:specular = pow(reflection, shininess);顺便说一句,我也发现很难调试着色器......我通常做“颜色调试”(即:en.wikibooks.org/wiki/Cg_Programming/Unity/Debugging_of_Shaders)
那么shininess
值的范围是多少?我的表面根本没有镜面反射。当将shininess
设置为零时,pow 函数将变为 1,并添加到照明中,而不是相乘。我可以将着色器的单个步骤的屏幕截图打印到屏幕上。哪些阶段会有所帮助?
好的,问题解决了。我不得不使用负向量reflect(-normalize(source - position), normal)
。此外,我现在对线性因子和指数都使用了光泽参数min(shininess, 1) * pow(reflection, shininess)
。效果很好。
我还注意到一件事:您将观察向量用作 (0,0,1),而在 RHS 中,查看器总是朝向负 Z 轴。【参考方案2】:
我认为变量命名会让您感到困惑。 根据我正在阅读的内容(假设您在相机空间中并且没有惯用手知识)
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)
正在查看视图空间中的单个位置。
【讨论】:
当我们需要从点到相机的向量时,不会 (position - vec3(0, 0,0)) 返回从“相机”到该点的向量吗? @racarate (position - vec3(0, 0,0)) 是从相机到该位置的矢量,这是“看”。然而你是对的:点应该在反射光线和从指向相机的位置的向量之间(-lookat)以上是关于镜面高光取决于相机距离的主要内容,如果未能解决你的问题,请参考以下文章