镜面高光取决于相机距离

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 这可能是个问题 您应该编辑问题并指定坐标系、查看器和灯光状态。 sourcedirectionallightarrivingfaced 未用于最终方程! 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(可能已经标准化)和positionlookat)已经标准化。

一个不太容易混淆的代码是:

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));

如果不规范化positionreflection 将有偏差。当position 远离相机vec3(0,0,0) 时,偏差会很大

注意lookat 不是一个常数;每个位置都会发生变化。 lookat = vec3(0,0,1) 正在查看视图空间中的单个位置。

【讨论】:

当我们需要从点到相机的向量时,不会 (position - vec3(0, 0,0)) 返回从“相机”到该点的向量吗? @racarate (position - vec3(0, 0,0)) 是从相机到该位置的矢量,这是“看”。然而你是对的:点应该在反射光线和从指向相机的位置的向量之间(-lookat)

以上是关于镜面高光取决于相机距离的主要内容,如果未能解决你的问题,请参考以下文章

遥感影像的全色多光谱高光谱图像

GLSL 灯光/高光随相机移动

推荐最好的 3D 映射工具?

镜面高光故障 OpenGL

相机测试camera报告的问题

学习光照的一些参数