GLSL 예제 – Flatten Shader(납작 쉐이더? =_=;)
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?flatten
쉐이더 프로그래밍은 3차원 장면에 새로운 효과를 넣는데 매우 유용하다. 이 작은 예는 버텍스가 기묘한 방법으로 가공되는 것을 보여준다.
먼저 3D 모델을 납작하게 렌더링시키기 위해, 모델뷰 변환을 적용하기 전에 z 좌표의 값을 0으로 설정한다. 아래의 버텍스 쉐이더가 이 연산을 수행한다.
void main(void)
{
vec4 v = vec4(gl_Vertex);
v.z = 0.0;
gl_Position = gl_ModelViewProjectionMatrix * v;
}
위의 코드를 보면, 먼저 지역변수(v)에 gl_Vertex를 복사하고 있다. gl_Vertex는 GLSL에서 제공하는 Attribute 변수이며, 버텍스 쉐이더가 수행되는 동안에는 읽기전용으로 사용할 수 있는 변수이다. 읽기전용이기 때문에 지역변수에 복사하여 값을 변환시킨것이다.
프레그먼트 쉐이더는 단지 색상만을 지정하므로, 이전 섹션(Hello World 예제)에서 제공한 코드와 동일하다.
이 쉐이더는 각 버텍스의 z 좌표를 0으로 지정한다. 주전자 3D 모델에 적용을 해보면, 아래의 그림처럼 납작해진 것으로 표현된다.
됐다. 이제 여기서 좀 응용을 해보자. 버텍스의 z값을 sin함수와 sin함수의 변수는 버텍스의 x좌표로 해면 주전자 모델이 너울거리는 것처럼 표시된다.
void main(void)
{
vec4 v = vec4(gl_Vertex);
v.z = sin(5.0 * v.x) * 0.25;
gl_Position = gl_ModelViewProjectionMatrix * v;
}
이제 이 간단한 예제에 마지막으로 버텍스 에니메이션 효과를 적용해보자. 이 효과를 위해서, 시간을 추적하거나 프레임 카운터를 위한 변수가 필요하다. A vertex shader can’t keep track of values between vertices, let alone between frames. 그래서 OpenGL 어플리케이션에 변수를 하나 정의하고, 이 변수를 Uniform 변수로 쉐이더에 넘겨야 한다. OpenGL 어플리케이션에 “time”이라는 이름의 변수가 있는데, 이변수는 프레임을 카운터하고, 같은 이름의 Uniform 변수가 쉐이더 안에 있다.
버텍스 쉐이더에 대한 코드는 다음과 같다.
uniform float time;
void main(void)
{
vec4 v = vec4(gl_Vertex);
v.z = sin(5.0*v.x + time*0.01)*0.25;
gl_Position = gl_ModelViewProjectionMatrix * v;
}
Uniform 변수를 설명한 섹션에서 언급했듯, OpenGL 어플리케이션에서는 다음 두단계가 필요하다.
- setup : Uniform 변수의 위치를 얻는다.
- render : Uniform 변수를 갱신한다.
setup 부분은 다음 코드와 같다.
loc = glGetUniformLocationARB(p, "time");
위의 코드에서 인자 p는 쉐이더 프로그램의 헨들이고, time은 버텍스 쉐이더에서 정의한 Uniform 변수의 이름이다. loc 변수는 GLint 형이며 render 함수에서 접근할 수 있는 위치에 정의되어야 한다.
render 함수는 아래와 같다.
void renderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLootAt(0, 0, 5, 0, 0, 0, 0, 1, 0);
glUniform1fARB(loc, time);
glutSolidTeaport(1);
time += 0.1;
glutSwapBuffers();
}
time 변수는 초기화부분에서 임의값으로 초기화되었을 것이고 매 프레임마다 증가된다.
여기까지의 예제 코드에 대한 전체 코드는 아래를 통해 다운로드 받길 바란다.