2011-11-12 68 views
1

因此,我開始尋求在不使用OpenGL照明系統的情況下實現超酷照明。我已經成功實現了Phong漫射照明。高光給我帶來麻煩。GLSL/OpenGL 2.1:使用制服的高光照明

我需要知道我使用的OpenGL常量佔用的空間是什麼,因爲它看起來是錯誤轉換的,而且會導致燈光故障。

我已經證實,通過成功加載並運行Phong漫反射着色器,我的C++代碼沒有問題。但是,C++代碼可能會將無效數據傳遞給着色器,這是我所擔心的事情之一。我將粘貼我的着色器的註釋,以及直接與着色器有關的所有C++代碼(儘管我90%確定問題出在着色器中)。

在這些圖像中,光源是大點,並顯示軸。 燈在icosphere周圍y = 0處旋轉。

這裏的漫反射,所以你得到一個想法的模型是什麼... Note I haven't done per-pixel yet... 注意我沒有每像素沒有完成......

這裏的菲涅爾照明,如圖源。 .. Note how the lit faces are facing the light, not somewhere between the light and the camera 注意如何點亮面對着光線,不顯山露水的光線和相機

這裏的之間的布林 - 海防,我不得不由30乘... Note again how the lit faces point towards the light source 再次說明了如何點亮的臉指向光源,並且也是事實,即我具有由30乘以鏡面因子(S),以實現這個

頂點着色器源

const int MAXLIGHTS = 4; 

uniform bool justcolor = false; 

uniform int lightcount; 
uniform vec4 lightposs[MAXLIGHTS]; 
uniform vec4 lightdirs[MAXLIGHTS]; 
uniform vec4 lightdifs[MAXLIGHTS]; 
uniform vec4 lightambs[MAXLIGHTS]; 

//diffuse 
vec4 D; 
//specular, normaldotlight 
float S, NdotL[MAXLIGHTS]; 
//normal, eyevec, lightvecs, halfvecs 
vec3 N, E, L[MAXLIGHTS], H[MAXLIGHTS]; 

void main() { 
    //if(lightcount > MAXLIGHTS) lightcount = MAXLIGHTS; 
    D = vec4(0.0, 0.0, 0.0, 0.0); 
    S = 0.0; 

    N = gl_Normal; 
    E = normalize(vec3(-gl_Vertex)); 

    for(int i = 0; i < lightcount; i++) 
    { 
     //calculating direction to light source 
     L[i] = normalize(vec3(lightposs[i] - gl_Vertex)); 

     //normal dotted with direction to light source 
     NdotL[i] = max(dot(N, L[i]), 0.0); 

     //diffuse term, works just fine 
     D += gl_Color * lightdifs[i] * NdotL[i]; 

     if(NdotL[i] >= 0.0) 
     { 
      //halfvector = normalize(lightdir + eyedir) 
      H[i] = normalize(L[i] + E); 

      //Blinn-Phong, only lights up faces whose normals 
      //point directly to the light source for some reason... 
      //S += max(0.0, dot(H[i], N)); 

      //Fresnel, lights up more than Blinn-Phong 
      //but the faces still point directly to the light source, 
      //not somewhere between the lightsource and myself, like they should. 
      S += pow(max(0.0, dot(reflect(L[i], N), E)), 50.0); 
     } 
     else 
     { 
      H[i] = vec3(0.0, 0.0, 0.0); 
     } 
    } 

    //currently only showing specular. To show diffuse add D. 
    gl_FrontColor = justcolor ? gl_Color : vec4(S * 0.3, S * 0.3, S * 0.3, 1.0); 

    gl_Position = ftransform(); 
} 

片段着色器源(來自「dirlight加載(從「dirlight.vs」加載) .FS「)從C++主初始化

void main() 
{ 
    gl_FragColor = gl_Color; 
} 

摘錄...

//class program manages shaders 
Program shaders = Program(); 
//attach a vertex shader, compiled from source in dirlight.vs 
shaders.addShaderFile(GL_VERTEX_SHADER, "dirlight.vs"); 
//attach a fragment shader compiled from source in dirlight.fs 
shaders.addShaderFile(GL_FRAGMENT_SHADER, "dirlight.fs"); 
//link program 
shaders.link(); 
//use program 
shaders.use(); 

//Program::getUniformLoc(const char* name) grabs the location 
//of the uniform specified 
GLint sTime = shaders.getUniformLoc("time"); 
GLint lightcount = shaders.getUniformLoc("lightcount"); 
GLint lightdir = shaders.getUniformLoc("lightdirs"); 
GLint lightdif = shaders.getUniformLoc("lightdifs"); 
GLint lightamb = shaders.getUniformLoc("lightambs"); 
GLint lightpos = shaders.getUniformLoc("lightposs"); 
GLint justcolor = shaders.getUniformLoc("justcolor"); 

glUniform1i(justcolor, 0); 
glUniform1i(lightcount, 2); 
//diffuse light colors 
GLfloat lightdifs[] = {1.f, 1.f, 1.f, 1.f, 
         1.f, 1.f, 1.f, 1.f}; 
glUniform4fv(lightdif, 2, lightdifs); 
glUniform4f(lightamb, 0.4f, 0.4f, 0.4f, 1.f); 

Excer從C++主循環... ...

//My lights rotate around the origin, where I have placed an icosphere 
GLfloat lightposs[] = {-4 * sinf(newTime), lighth, -4 * cosf(newTime), 0.0f, 
         -4 * sinf(newTime + M_PI), lighth, -4 * cosf(newTime + M_PI), 0.0f}; 
glUniform4fv(lightpos, 2, lightposs); 
+0

技術上你應該在片段着色器中進行光照計算,而不是頂點着色器;這是片段着色器的主要目的之一:實現每個片段照明模型。 – datenwolf

+0

我首先在頂點着色器中實現它,所以我可以將所有內容放在同一個位置。稍後我將轉向每像素。我不想在他們之間出現錯誤的空間,除非這是我處理的唯一事情。 – Miles

回答

4

有幾個重要的事情從你的代碼中缺少。首先,您應該將頂點位置和法線轉換爲眼睛空間。照明計算在那裏最容易。頂點位置使用模型視圖矩陣變換,法線變換與模型視圖的顛倒相反。通常光照位置在世界座標中,所以從世界到眼睛座標提供一個附加矩陣是有意義的。

+0

是我在世界空間處理的一切嗎? (在上面的源代碼中) – Miles

+1

@ MilesRufat-Latre:不。它是模型局部空間(gl_Vertex,gl_Normal)的混合體,缺少爲(lightpos,lightdir)和眼睛空間(gl_Position = ftransform())提供語義的一些未定義空間;就像我已經告訴過你的那樣:使用頂點着色器只會將事物放入一個公共空間,即眼睛空間,然後在片段着色器中進行光照計算,這將變得容易得多。 – datenwolf

+0

要離開局部模型空間並進入全局,我會乘以gl_ModelView的逆模型局部變量嗎?投影和模型視圖矩陣如何相互關聯? – Miles