GLSL 예제 – 툰쉐이딩 마지막 장.. (4/4)
원본 : http://www.lighthouse3d.com/opengl/glsl/index.php?toon3
툰쉐이딩을 끝내기 전에 한가지 더 살펴보자 : lightDir 변수를 사용하는 대신에 OpenGL 빛을 사용한 것. OpenGL에서 빛을 하나 정의하고 이 빛의 방향을 쉐이더에서 사용하는 방법이다. 주의: glEnable을 사용해서 빛을 활성화할 필요가 없는데, OpenGL에서 이 빛을 실제로 사용하지는 않을 것이기 때문이다.
우리는 OpenGL에서 첫번째 빛(GL_LIGHT0)이 Directional 빛이라고 가정하겠다.
GLSL은 OpenGL 상태의 일부에 접근할 수 있는데, 바로 빛과 같은 속성에 접근할 수 있다. GLSL은 빛의 속성에 대한 C언어 형식의 구조체를 정의하고 있는데 각 빛에 대한 속성을 정의하기 위한 배열로 존재한다.
struct gl_LightSourceParameters {
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
};
uniform gl_LightSourceParamters gl_LightSource[gl_MaxLights];
위의 구조체와 변수를 이용해서 버텍스 쉐이더에서 빛의 방향을 얻어낼 수 있는데, 구조체의 필드중에 position을 이용하면 된다. 여기서 다시 우리는 OpenGL 어플리케이션에서 빛의 방향 벡터가 정규화되었다고 가장하겠다.
OpenGL은 스펙상 빛의 위치가 지정되면 이 위치 좌표가 자동으로 눈 공간 좌표계(eye space coordinate), 예를 들어서 카메라 좌표계로 바뀐다. 우리는 좌표체계가 바뀌어도 빛의 위치가 정규화된 상태로 유지된다고 가정할 수 있다. 이 가정은 모델뷰해열의 좌측상단의 3×3 부분의 행렬이 직교일때 옳다(만약 gluLookAt함수를 사용하고, 어플리케이션에서 좌표계의 크기조정을 하지 않았다면 확실히 옳다).
우리는 법선벡터를 눈 공간 좌표계(카메라 좌표계)로 변환해야 하며, 빛의 방향벡터와 법선벡터 사이의 각을 계산하기 위해 내적 계산을 해야 한다.
법선벡터를 카메라 좌표계로 변환하기 위해서는 미리 정의된 Uniform 변수인 gl_NormalMatrix를 사용한다. 이 행렬 변수는 모델뷰 매트릭스의 좌상단의 3×3 부분의 역행렬의 전치 행렬이다. 우리는 하나의 버텍스 마다 법선 변환을 수행할 것인데 아래의 코드가 바로 이 변환에 대한 코드이다.
varying vec3 normal;
void main()
{
normal = gl_NormalMatrix * gl_Normal;
gl_Position = ftransform();
}
아래의 코드처럼 프레그먼트 쉐이더에서 빛의 위치를 얻어와 빛의 밝기값을 계산한다.
varying vec3 normal;
void main()
{
float intensity;
vec3 color;
vec3 n = normalize(normal);
intensity = dot(vec3(gl_LightSource[0].position, n);
if(intensity > 0.95)
color = vec4(1.0, 0.5, 0.5, 1.0);
else if(intensity > 0.5)
color = vec4(0.6, 0.3, 0.3, 1.0);
else if(intensity > 0.25)
color = vec4(0.4, 0.2, 0.2, 1.0);
else
color = vec4(0.2, 0.1, 0.1, 1.0);
gl_FragColor = color;
}
최종 소스 코드는 다음을 통해 다운로드 받길 바란다.1264150041.zip1096160345.zip
쉽게 잘쓰셨네요. 국내에서 이렇게 쉽고 쓸만한걸 공개적으로 쓴 콘텐츠 별로 없는것 같던데 장수하세요 (수명도 콘텐츠도)
감사합니다. 많이 부족한 글임에도..
항상 감사드립니다. 많은 도움이 됩니다. 그런데 혹시 GLSL에서 접근할 수 있는 라이트 구조체나 재질 구조체라는것이요…. OPENGL어플 안에서 정의하고 설정만 해 놓으면 자동으로 유니폼 변수로 들어가는 건가요?? 아니면 구조체와 유니폼 변수를 실제 코드에 작성하고 어플 안에서 값을 넣어주어야 하나요??…