我正在写一个关于Phong阴影的小测试,我正在撞击一堵砖墙,试图让镜面反射元件正常工作。它似乎工作正常,除了镜面反射光应用于前面和前面。物体的后部。 (对象本身是透明的,面部手动对CPU侧进行排序。)
请注意,漫反射组件工作正常(仅显示在面向光源的一侧) - 我认为这似乎排除了到达片段着色器的法线问题。
据我所知,镜面反射分量与眼睛矢量和眼睛之间的角度的cos成比例。反射光矢量。
为了让事情变得简单,我的测试代码试图在世界空间中做到这一点。摄像机位置和光矢量分别是(0,0,4)
和(-0.707, 0, -0.707)
的硬编码(抱歉)。因此,眼睛向量是(0,0,4) - fragPosition
。
由于模型矩阵仅执行旋转,因此顶点着色器仅通过模型矩阵转换顶点法线。 (注意:这不是好习惯,因为许多类型的转换都不能保持正常的正交性。通常对于普通矩阵,you should use模型矩阵的左上角3x3的逆转置。)为了简单起见,片段着色器在单个浮点颜色通道上操作,并跳过镜面反射指数(/使用指数为1)。
顶点着色器:
#version 140
uniform mat4 mvpMtx;
uniform mat4 modelMtx;
in vec3 inVPos;
in vec3 inVNormal;
out vec3 normal_world;
out vec3 fragpos_world;
void main(void) {
gl_Position = mvpMtx * vec4(inVPos, 1.0);
normal_world = vec3(modelMtx * vec4(inVNormal, 0.0));
fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0));
}
片段着色器:
#version 140
uniform float
uLightS,
uLightD,
uLightA;
uniform float uObjOpacity;
in vec3 normal_world, fragpos_world;
out vec4 fragOutColour;
void main(void) {
vec3 vN = normalize(normal_world);
vec3 vL = vec3(-0.707, 0, -0.707);
// Diffuse:
// refl in all directions is proportional to cos(angle between -light vector & normal)
// i.e. proportional to -l.n
float df = max(dot(-vL, vN), 0.0);
// Specular:
// refl toward eye is proportional to cos(angle between eye & reflected light vectors)
// i.e. proportional to r.e
vec3 vE = normalize(vec3(0, 0, 4) - fragpos_world);
vec3 vR = reflect(vL, vN);
float sf = max(dot(vR, vE), 0.0);
float col = uLightA + df*uLightD + sf*uLightS;
fragOutColour = vec4(col, col, col, uObjOpacity);
}
我在这里找不到错误;任何人都可以解释为什么镜面反射分量出现在物体的后部和面向光的一侧?
非常感谢。
答案 0 :(得分:5)
对于正面和背面,您的镜面反射贡献实际上是相同的,因为GLSL reflect
对法线的符号不敏感。来自this reference:
reflect(I, N) = I - 2.0 * dot(N, I) * N
所以翻转N的符号会引入两个取消的减号。换句话说,reflect
做的是反转与I
在同一轴上的N
分量的符号。这不取决于N
面临的方式。
如果您想从背面移除镜面反射成分,我认为您需要明确检查dot(vE,vN)
。
答案 1 :(得分:0)
尝试更改
fragpos_world = vec3(modelMtx * vec4(inVPos, 0.0));
到
fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0));
因为http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/#Homogeneous_coordinates