OpenGL Shader – 20

GLSL 예제 – 툰 쉐이딩(Toon Shading) – 1장(총4장)
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?toon

툰 쉐이딩은 아마도 우리가 작성할 수 있는 가장 간단한 비실사적(Non-Photorealistic)인 쉐이더일 것이다. 툰 쉐이딩은 소수의 색상만을 사용하는데, 급작스러운 톤의 변화가 나타난다. 말보다는 아래의 이미지를 살펴보면 이해가 쉬울 것이다.


위의 주전자 모델에서 명도(Tone)은 각도에 의해 선택되어지는데, 사실  코사인의 각도에 기반하며, 이 각도는 실제 빛의 방향과 표면의 법선 벡터의 각이다.

그래서 빛의 방향에 근접한 법선벡터를 가지고 있다면, 명도을 계산해서 사용할 수 있다. 법선과 빛의 방향 사이의 각도가 점점 증가함에 따라 더 어두운 명암의 색조를 사용하게 된다. 코사인의 각이 명암의 세기를 제공한다.

툰쉐이더에 대한 이 섹션에서는 버텍스 당 명암의 세기를 계산하는 방식으로 시작을 한 뒤에, 계산된 명암의 세기를 프레그먼트 쉐이더로 보낸다. 여기서 OpenGL의 빛의 위치를 어떻게 쉐이더에서 접근할 수 있는지를 살펴본다.

OpenGL Shader – 19

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 변수는 초기화부분에서 임의값으로 초기화되었을 것이고 매 프레임마다 증가된다.

여기까지의 예제 코드에 대한 전체 코드는 아래를 통해 다운로드 받길 바란다.

1167513658.zip1017013023.zip