OpenGL Shader – 17

GLSL Samples – Hello World in GLSL
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?minimal

이 섹션은 Hello World에 대한 GLSL 판이다. 가장 기본적인 내용을 수행하는 쉐이더를 살펴볼 것이다 : 버텍스의 변환, 단일 색상으로 프리미티브 렌더링하여 화면 표시.

버텍스 쉐이더
이전 섹션중에 버텍스 쉐이더 부분에서 언급했듯이, 버텍스 쉐이더는 버텍스의 변환을 담당한다. OpenGL의 고정기능과 동일한 내용을 수행하는 버텍스의 변환을 수행하는 쉐이더를 살펴볼 것이다.

고정기능은 다음과 같이 모델뷰 행렬과 투영행렬에 의해 변환을 수행한다.

vTrans = projection * modelview * incomingVertex

GLSL에서 위의 내용을 수행하는 코드를 작성하려면 모델뷰 행렬과 투영행렬을 얻을 수 있도록 OpenGL에 접근할 필요가 있다. 이전에 언급했듯이, OpenGL의 상태 중 일부를 GLSL에서 접근할 수 있는데, 주로 언급한 투영행렬과 모델뷰행렬이다. 행렬은 이미 정의된 Uniform 변수를 통해서 제공된다.

uniform mat4 gl_ModelViewMatrix;
uniform mat4 gl_ProjectionMatrix;

하나 더 필요한 것은 입력 버텍스에 접근하는 것이다. 이런 버텍스는 하나씩 하나씩 버텍스 쉐이더에 접근되는데 Attribute 변수를 통해서 제공된다.

attribute vec4 gl_Vertex;

행렬에 의해 변환된 버텍스를 출력하기 위해서, 쉐이더는 반드시 미리 정의된 변수인 gl_Position을 사용해야 하며 gl_Position은 vec4로 선언된 변수다.

위처럼 한다면, 이제 버텍스 쉐이더를 작성하는게 가능하다. 하지만 아직은 버텍스 변환 연산만 가능하다. 주의할 것은 버텍스 변환 이외의 다른 기능은 작동하지 않는데, 예를들어 빛계산은 수행되지 않는다.

버텍스 쉐이더는 main 함수를 가져야만 한다.

void main()
{
    gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
}

위의 코드에서, 투영행렬은 모든 버텍스에 대해서 모델뷰행렬과 곱해지는데, 이것은 분명이 시간 낭비다. 왜냐하면 투영행렬과 모델뷰행렬은 모든 버텍스에 대해서 변하지 않는다. 이 행렬들은 Uniform 변수다.

GLSL은 몇개의 파생된 행렬을 제공하는데, 바로 gl_ModelViewProjecteionMatrix로써, 투영행렬과 모델뷰행렬을 곱한 결과 매트릭스이다. 이 변수를 사용해 다시 코드를 작성하면…

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

위의 두 main() 함수에 대한 쉐이더의 최종 결과는 동일하다. 그런데 고정기능과 동일한 변환을 보장하는가? 음… 이론적으로 그렇다. 그러나 버텍스의 변환의 실제 절차는 여기와 달리 동일한 순서를 따르지 않는다. 이것은 보통 그래픽 카드에 매우 최적화된 작업인데, 최적화의 이점을 취하기 위해 하나의 특별한 기능이 제공된다. 이 기능의 또 다른 이유는 float 데이터 타입의 정밀도에 제약이 있기 때문이다. 계산이 다른 순서로 이뤄질때, 이 제한된 정밀도로 인해 다른 결과가 얻어진다. 그래서 GLSL은 최고의 수행속도뿐만 아니라 고정기능과 동일한 결과를 항상 얻을 수 있는 함수를 제공한다. 바로 마법과 같은 그 함수는:

vec4 ftransform(void);

이 함수는 입력받은 버텍스를 변환한 결과를 반환하며, 고정기능과 동일한 단계를 수행해 고정기능과 동일한 결과를 제공한다. 이제 쉐이더는 다음과 같이 재작성될 수 있다.

void main()
{
    gl_Position = ftransform();
}

프레그먼트 쉐이더
프레그먼트 쉐이더 역시 프레그먼트의 색상을 설정할 수 있는 미리 정의된 변수를 가지고 있다: gl_FragColor. 버텍스 쉐이더의 경우에서처럼, 프레그먼트 쉐이더 역시 main 함수를 가지고 있다. 다음 코드는 푸르스름한 색상으로 모든 프레그먼트를 그리는 프레그먼트 쉐이더 코드이다.

void main()
{
	gl_FragColor = vec4(0.4, 0.4, 0.8, 1.0);
}

위의 버텍스 쉐이더와 프레그먼트 쉐이더를 적용한 결과는 아래와 같다.

“OpenGL Shader – 17”에 대한 5개의 댓글

  1. ㅎㅎ ^^ 고정독자분이 생긴듯해서 좋습니다~
    쉐이더에 대한 글은 단순하지만, 그 결과는 매우 화려하죠.
    기회가 된다면 추후에 쉐이더를 응용한 화려한 강좌를 별도로 올려보고 싶습니다~ 그럼 열심히 하시구요~ ^^

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다