镜面光线出现在物体的眼睛两侧和后侧

ASp*_*nce 5 opengl lighting glsl specular phong

我正在写一个Phong阴影的小测试,我正在撞击一堵砖墙,试图让镜面反射元件正常工作.它似乎工作正常,除了镜面光应用于对象的前后.(对象本身是透明的,面部手动排序CPU侧.)

请注意,漫反射组件完美地工作(仅显示在面向光源的一侧) - 这似乎排除了到达片段着色器的法线的问题,我认为.

据我所知,镜面反射分量与眼睛矢量和反射光矢量之间的角度的cos成比例.

为了保持简单,我的测试代码试图在世界空间中做到这一点.照相机位置和光矢量被硬编码(对不起)作为(0,0,4)(-0.707, 0, -0.707)分别.因此,眼睛矢量(0,0,4) - fragPosition.

由于模型矩阵仅执行旋转,因此顶点着色器仅通过模型矩阵转换顶点法线.(注意:这不是很好的做法,因为许多类型的转换都不能保持正常的正交性.通常对于普通矩阵,你应该使用模型矩阵的左上角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)); 
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

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

}
Run Code Online (Sandbox Code Playgroud)

我在这里找不到错误; 任何人都可以解释为什么镜面反射分量出现在物体的后部和面向光的一侧?

非常感谢.

Mik*_*ale 6

对于正面和背面,您的镜面反射贡献实际上是相同的,因为GLSL reflect对法线的符号不敏感.从这个参考:

reflect(I, N) = I - 2.0 * dot(N, I) * N
Run Code Online (Sandbox Code Playgroud)

所以翻转N的符号会引入两个取消的减号.换句话说,reflect反转其组成部分I沿着同一轴的符号是什么N.这不取决于N面临的方式.

如果你想从背面移除镜面反射分量,我想你需要明确检查你的背面dot(vE,vN).