Shader Model 4.0 에는 Geometry Shader 가 새로 추가 됐다. 이 geometry shader 를 간단하게 소개하고 샘플 코드를 통해 간단한 사용법을 설명해보려고 한다.

일단 Geometry shader 를 간단한 소개부터 해본다(vertex/fragment(pixel) shader 를 이미 알고 있다는 가정이다).

각 점(vertex)의 정보가 파이프라인에서 흐를 때, vertex shader 에서 거친 점들이 fragment shader(HLSL 의 pixel shader 와 같은 것)로 바로 가기 전에 geometry shader 를 거친다. geometry shader 는 삼각형(혹은 사각형.. 등의 프로그래머가 설정) 단위로 입력을 받고 출력 역시 삼각형(역시 다른 모양도 가능하다. 심지어, 입력과 출력의 모양이 다를 수도 있다[1].)으로 하여 보낸다. 이때 삼각형을 수정 될수도 있고 삭제 될 수도 있고 심지어 추가가 될 수도 있다. 그 후 이 삼각형은 fragment shader 에서 받게 된다.

Geometry shader 를 해보기 위해서는 일단 G8x 시리즈의 그래픽 카드Geforce 8000 대 그래픽 카드)가 필요하다. 테스트를 위해서라면 Emulator 가 있긴 하다. 하지만 굉장히 느리니, 그냥 어떻게 작동하는지 단일 화면만 보고 싶을 때나 사용이 가능할듯 하다. -_-;

그리고 지금까지 최신 버전인 OpenGL 2.1 에서는 아직 geometry shader 를 지원하지 않는다. 따라서, 이것을 사용하기 위해서는 NVIDIA 의 extension 을 사용해야한다(사실 EXT 를 붙여주기만 하면 되는 간단한 문제다).

먼저, 처음 geometry shader 를 해보기 위해 참고한 곳은  CIRL GPU GLSL Geometry Shader Tutorial 이곳이다. 이곳에는 간단한 샘플 코드가 있는데, 몇가지 주의할 점을 같이 소개한다.

설명이 좀 길었는데, 사실 사용법은 매우 간단하다.

Sample Code (Language : cpp)
  1. VertexShaderID = glCreateShader( GL_VERTEX_SHADER );
  2. glShaderSource( VertexShaderID, 1, &VertexShaderData, NULL );
  3. glCompileShader( VertexShaderID );
  4.  
  5. FragmentShaderID = glCreateShader( GL_FRAGMENT_SHADER );
  6. glShaderSource( FragmentShaderID, 1, &FragmentShaderData, NULL );
  7. glCompileShader( FragmentShaderID );
  8.  
  9. GeometryShaderID = glCreateShader( GL_GEOMETRY_SHADER_EXT );
  10. glShaderSource( GeometryShaderID, 1, &GeometryShaderData, NULL );
  11. glCompileShader( GeometryShaderID );
  12.  
  13.  
  14. ProgramID = glCreateProgram();
  15. glAttachShader( ProgramID, VertexShaderID );
  16. glAttachShader( ProgramID, FragmentShaderID );
  17.  
  18. glProgramParameteriEXT( ProgramID,
  19.     GL_GEOMETRY_INPUT_TYPE_EXT, GL_TRIANGLES );
  20. glProgramParameteriEX( ProgramID,
  21.     GL_GEOMETRY_OUTPUT_TYPE_EXT,GL_TRIANGLES );
  22.  
  23. int temp;
  24. glGetIntegerv( GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &temp );
  25. glProgramParameteriEXT( ProgramID,
  26.     GL_GEOMETRY_VERTICES_OUT_EXT,temp );
  27.  
  28. glLinkProgram( ProgramID );
  29. glUseProgram( ProgramID );

기존의 vertex/fragment shader 를 사용하는 것과 크게 다르지 않다. 눈여겨 볼것은..
1. GL_GEOMETRY_SHADER_EXT 처럼 _EXT 가 붙는다.
2. VertexShaderData 는 char* 형으로 실제 쉐이더 데이터가 string 형식으로 들어간다.
3. (매우 중요) glLinkProgram 이 호출 되기 전에 glProgramParameteriEXT 의 세팅이 끝나야 한다.
4. 이 코드에서는 오류 검출/로그 보기 등이 생략되어 있다. 실제 구현할때는 매우 중요하다.

3번에 적었듯이 중요한 점은 Parameter 설정이 Link 전에 이루어져야 한다는 것이다. 그렇지 않으면 geometry shader 가 아에 동작하지 않는다.

실제 Geometry shader code 를 작성하는 것은 의외로 간단하다. 아무것도 안하는 샘플 코드는 다음과 같다.

Sample code of Geometry Shader (Language : cpp)
void main(void)
{
    for( int i=0; i < gl_VerticesIn; i++ )
    {
        gl_Position = gl_PositionIn[i];
        EmitVertex();
    }
   
EndPrimitive();
}

참고 : 원래 geometry shader 파일 처음에 다음의 문구를 추가해야 한다.
#version 120
#extension GL_EXT_geometry_shader4 : enable
이것을 추가하지 않으면 warning 이 일어난다. 하지만 내 경우는 이것을 추가하면 에러가 났고, 추가하지 않으면 warning 이 일어나는 상태에서 잘 동작했다.

gl_VerticesIn 은 각 primitive 당 vertex 개수를 의미한다. 삼각형이 입력이 되니 gl_VerticesIn 은 값은 내부적으로 3으로 인식 할 것이다. gl_PositionIn[i]; 은 입력되는 vertex 의 위치를 의미하고, gl_Position 은 출력을 의미한다.

각 vertex 의 출력 설정이 끝나면, EmitVertex(); 를 호출한다. 삼각형의 경우 3개, 사각형의 경우 4개의 EmitVertex 를 마치고 나면 EndPrimitive(); 함수로 해당 primitive 의 설정이 끝났음을 알린다.

Geometry Shader 에서 입력과 출력으로 사용할 수 있는 것들은 다음과 같다[2].

입력!!

vec4 gl_FrontColorIn[gl_VerticesIn];
vec4 gl_BackColorIn[gl_VerticesIn];
vec4 gl_FrontSecondaryColorIn[gl_VerticesIn];
vec4 gl_BackSecondaryColorIn[gl_VerticesIn];
vec4 gl_TexCoordIn[gl_VerticesIn][];
float gl_FogFragCoordIn[gl_VerticesIn];
vec4 gl_PositionIn[gl_VerticesIn];
float gl_PointSizeIn[gl_VerticesIn];
vec4 gl_ClipVertexIn[gl_VerticesIn];

출력!!

vec4 gl_Position;
vec4 gl_FrontColor;
vec4 gl_BackColor;
vec4 gl_FrontSecondaryColor;
vec4 gl_BackSecondaryColor;
vec4 gl_TexCoord[]; // at most gl_MaxTextureCoords
float gl_FogFragCoord;

1. gl_Position 에 출력하는 것은 필수가 아닌 옵션이다. 다라서 gl_Position 에 아무것도 넣지 않으면 출력이 되지 않고, 이 방법으로 기존에 불가능했던, 선택적으로 fragment shader 로 정보를 넘기지 않는 것이 가능하다[3].
2. glTexCoord 를 사용할때는 index 순서를 잘 봐야 한다. 예를 들어 0번의 texure coordinate 에 저장하기 위해서는
glTexCoord[0] = glTexCoordIn[i][0];
형식으로 사용한다.
3. 이 이외에도, int gl_PrimitiveID; 를 사용할 수 있다. 이것은 primitive 가 넘어올때 그 순서에 따라 기록된 번호를 참고하는 것이다. (예를 들어서 삼각형을 처음 100개만 그리고 나머지는 그리지 않겠다. 할 경우 이 값을 통해 제어할 수 있다.)
4. gl_Layer 로 사용하는 Layer 개념이 있는데, 이것은 Frame Buffer Object 와 관련된 기능이라 설명을 생략한다. Frame Buffer Object 는 아직 OpenGL 2.1 표준도 아니다. Frame Buffer Object 는 일반적으로 텍스쳐 등에 바로 그리기 위해서 사용된다. 이것 없이는 하드웨어 버퍼에 그린 후 텍스쳐 메모리로 복사를 하는 과정을 거쳐야한다. 또 하나 주의 할 것은 NVIDIA 의 Frame Buffer Object 와 기존에 사용되는 용어인 framebuffer 는 전혀 다른 것이다. 이 frame buffer object 와 layer 의 사용은 1-pass cubemap 생성을 할 때 사용될 수 있는데, 기회가 되면 나중에 설명해보도록 하겠다(지금 구현은 끝났고, 속도 테스트 준비 중인데, 6-pass 생성보다 그다지 빨라질 것 같진 않다). - 아, 참고로 이 framebuffer object 는 위에 말한 emulator 에서는 작동하지 않는다.

사실상 geometry shader 를 사용하는 것은 그다지 어렵지 않은데, 관련된 이슈를 같이 적다보니까 분량이 많아졌다. 사실상 굉장히 좋은 기능이긴 한데, geometry shader 에서 나가는 primitive 가 많이 질 경우 이 정보들이 GPU 의 느린 global memory 로 들어갔다 나온다는 얘기가 있었다. 이렇게 되면 많이 느려지는 요소가 될듯 하다. 이 점에 대해서는 좀 더 테스트를 해봐야 겠고, 어쨌거나 잘 쓰면 매우 훌륭한 기능임에는 틀림이 없다.

아, 마지막으로... 내가 알기로는 DirectX 9.0 에서는 그래픽 카드와 상관 없이 geometry shader 가 지원하지 않는 것으로 알고 있다. Vista 에서만 지원하는 DirectX 10(혹은 10.1)에서만 geometry shader 를 지원하도록 되어 있는데, OpenGL + GLSL 에서는 운영체제에 상관 없이 그래픽카드만 지원을 하면 geometry shader 를 사용할 수가 있다.


  1. 예를 들면 삼각형을 입력 받고 wireframe 을 그리기 위해 각 삼각형 당 3개의 선으로 바꿔주면, 모든 물체가 wireframe 으로 보여지게 된다. [본문으로]
  2. 이것은 NVIDIA Extension 에 나와 있는 내용으로, 실제로 NVIDIA Extension 은 모든것이 담겨 있고 매우 자세하다. http://developer.download.nvidia.com/opengl/specs/GL_EXT_geometry_shader4.txt 단, 샘플 코드도 거의 없고 읽기 편하지도 않다. 하지만 geometry shader 를 하기 위해서라면 한번 봐두면 좋을 듯 하다. [본문으로]
  3. 이 말이 무슨말이냐 하면, 현재 fragment shader 에서는 discard 명령어로 fragment shader 도중 pixel 을 쓰는 것을 취소 할 수 있었다. 하지만 vertex shader 에서는 discard 명령을 지원하지 않고 있다. 지금도 여전히 지원하지는 않지만, geometry shader 를 이용함으로써 discard 명령과 비슷하게 primitive 그리기를 취소할 수가 있다. [본문으로]
크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/04/13 10:14 2008/04/13 10:14

트랙백 주소 :: http://www.hybrid.pe.kr/tt/trackback/344

댓글을 달아 주세요

  1. ㄹ듀르 2008/04/20 18:36  댓글주소  수정/삭제  댓글쓰기

    맛있는 포스트네요. 잘 먹었습니다.

  2. leeligen 2008/04/24 03:14  댓글주소  수정/삭제  댓글쓰기

    정말 큰 도움이 되었어요 감사합니다

  3. Tree 2010/01/09 21:33  댓글주소  수정/삭제  댓글쓰기

    이리저리 검색하다 방문했습니다. geometry shader 에 대해 설명하는 글을 처음 보게 되었군요...잘 구경하고 갑니다...

[로그인][오픈아이디란?]