2013-11-15 35 views
4

我正在写一个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

需要sccreenshot效果,你使用什么几何? –

+0

此外,这是可怕的,你应该把方向是作为制服,并有一个单独的矩阵来转换法线,而统一的尺度是必需的,这是唯一的,如果一个统一的尺度是一个等距,这并非总是如此。 –

+0

嗨亚历克,对于硬编码的方向抱歉,试着想像他们是制服。我这样做是为了让它们超简单,但我在这里找不到一个不一致的地方。屏幕截图:http:/ben.am/temp/specular-problem.png – ASpence

回答

4

你的镜面贡献实际上将成为前相同,背朝因为GLSL reflect是不敏感的标志的正常。从this reference

reflect(I, N) = I - 2.0 * dot(N, I) * N 

所以翻转N的符号会引入两个取消的减号。换句话说,reflect所做的是将I组件的符号反转,该组件的符号与N的轴相同。这并不取决于N面临的方式。

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

+1

或乘以兰伯特术语 - 也就是说,sf * = df – bjorke

+0

非常感谢迈克,那就是问题所在。一个简单的方法来修复我现在使用的后反射高光,就像这样:'float sf = 0.0;如果(df> 0.0){/ *计算sf * /}' – ASpence

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

+0

同样值得注意的是,1.0作为w coord表示“位置”和0.0作为方向 –

+0

之间有很好的联系。谢谢@jpaari,你说得对,fragpos_world转换应该用w = 1.0来完成。另一方面,正常转换应该用w = 0.0来完成。然而,不幸的是,问题仍然存在。 – ASpence