Geometry Shader

Date:     Updated:

카테고리:

태그:

Main Reference
- Learn OpenGL
- Rinthel Kwon - OpenGL Lecture


Geometry Shader

Geometry Shader는 Vertex Shader와 Pixel Shader 중간에 존재하는 Shader이다. 먼저 geometry shader는 특정한 primitive와 vertex들을 input으로 받는다. 그 후 기존 vertex들을 기반으로 새로운 vertex들을 생성하고, 이들을 다시 특정한 primitive와 조합해 fragment shader로 전달해 준다. 이때 out으로 출력되는 primitive는 input primitive와 같지 않아도 된다. Geometry Shader를 잘 이용하면 아주 효과적으로 CPU의 부담을 GPU로 나눌 수 있다.


// Render()..
glDrawArrays(GL_POINTS, 0, 4);  


// geometry shader
#version 330 core

layout (points) in;
layout (line_strip, max_vertices = 2) out;

void main() {    
    gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); 
    EmitVertex();

    gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);
    EmitVertex();
    
    EndPrimitive();
}  
  • layout (points) in : input primitive는 GL_POINTS
  • layout (line_strip, max_vertices = 2) out
    • output primitive는 line_strip
    • 하나의 out primitive로 나가는 vertex의 최대 개수는 2개
  • EmitVertex : gl_Position으로 vertex 하나의 위치를 지정하고, outstream에 추가
  • EndPrimitive : 현재까지 추가한 vertex들로 primitive 생성


geometry_shader_lines

  • 위 예제를 보면 Point 4개를 vertex shader로 넘기고
  • Geometry Shader 단계에서 point마다 vertex를 추가해 line primitive로 변경


Example

// VBO
float points[] = {
    -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, // 좌측 상단
     0.5f,  0.5f, 0.0f, 1.0f, 0.0f, // 우측 상단
     0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // 우측 하단
    -0.5f, -0.5f, 1.0f, 1.0f, 0.0f  // 좌측 하단
};  


#version 330 core

layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;

out VS_OUT {
    vec3 color;
} vs_out;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); 
    vs_out.color = aColor;
}  
  • 먼저 화면을 4분면으로 나누고, 각 사분면마다 포인트 하나와 컬러 값을 지정해서 vertex shader로 전달
  • vertex shader에서는 gl_Position과 color 구조체를 geometry shader로 전달


// geometry shader
#version 330 core

layout (points) in;
layout (triangle_strip, max_vertices = 5) out;

in VS_OUT {
    vec3 color;
} gs_in[];

void main() {  
fColor = gs_in[0].color;
gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0);
EmitVertex();   
gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0);
EmitVertex();
gl_Position = position + vec4(-0.2,  0.2, 0.0, 0.0);
EmitVertex();
gl_Position = position + vec4( 0.2,  0.2, 0.0, 0.0);
EmitVertex();
gl_Position = position + vec4( 0.0,  0.4, 0.0, 0.0);
EmitVertex();
EndPrimitive();  
}
  • in/out layout 지정
  • in VS_OUT : vertex shader에서 out으로 내보낸 interface block(구조체)와 동일한 block name으로 color 받아오기
  • fColor = gs_in[0].color : geometry shader로 새로 생성한 vertex들은 모두 기존의 색과 동일하니 한 번만 지정
  • EmitVertex : gl_Position을 지정하고 EmitVertex를 실행하면, position값과 fColo값이 output stream에 추가


geometry_shader_houses_colored


fColor = gs_in[0].color; 
gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0);    // 1:좌측 하단   
EmitVertex();   
gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0);    // 2:우측 하단
EmitVertex();
gl_Position = position + vec4(-0.2,  0.2, 0.0, 0.0);    // 3:좌측 상단
EmitVertex();
gl_Position = position + vec4( 0.2,  0.2, 0.0, 0.0);    // 4:우측 상단
EmitVertex();
gl_Position = position + vec4( 0.0,  0.4, 0.0, 0.0);    // 5:꼭대기
fColor = vec3(1.0, 1.0, 1.0);
EmitVertex();
EndPrimitive();  

geometry_shader_houses_snow

  • 지붕 꼭대기 vertex만 흰 색으로 컬러를 변경하면 눈 쌓인듯한 느낌 연출 가능
  • 당연하지만, 이 결과를 보면 Rasterize 단계는 geometry shader 이후라는 것을 알 수 있음


Object Exploding Visualize Normals
geometry_shader_explosion geometry_shader_normals
  • 이 외에도, 오브젝트를 이루는 삼각형 면들을 normal 방향으로 들어올려 오브젝트가 폭팔되는 연출을 한다던가
  • vertex마다 normal 방향으로 line을 하나 그려 noraml vector를 시각화하는 것도 가능



맨 위로 이동하기

OpenGL 카테고리 내 다른 글 보러가기

댓글 남기기