2013-11-15 55 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