2011-11-12 4 views
1

OpenGL의 조명 시스템을 사용하지 않고 멋진 조명을 구현하기위한 탐구를 시작했습니다. Phong 확산 조명을 성공적으로 구현했습니다. Specular가 내게 문제가되고있다.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를 곱해야했던 Blinn을-퐁 ... Note again how the lit faces point towards the light source 주의의 방법 조명 된면이 광원을 향하고 내가

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 "에서로드)이

버텍스 쉐이더 소스를 달성하기 위해 (30)에 의해 하나 뿐인 인자 (S)를 곱해야한다고도 사실 .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 pt를 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 : No.이것은 모델 로컬 공간 (gl_Vertex, gl_Normal), (lightpos, lightdir) 및 눈 공간 (gl_Position = ftransform())에 대한 의미를 제공하지 못한 일부 정의되지 않은 공간입니다. 이미 말했듯이, 꼭지점 쉐이더를 사용하는 것만으로도 공통 공간, 눈 공간, 그리고 조각 쉐이더에서 조명 계산을 수행하는 것이 훨씬 쉬울 것입니다. – datenwolf

+0

로컬 모델 공간을 떠나 글로벌로 이동하려면 모델 로컬 변수에 gl_ModelView의 역수를 곱하면됩니까? 투영 및 모델 뷰 행렬은 어떻게 서로 관련이 있습니까? – Miles