Advanced OpenGL(8) - Geometry Shader

흑빡·2026년 7월 7일

그래픽스

목록 보기
43/50
post-thumbnail

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();
}

이게 거의 전부라고 봐도 됨

in layout

in 입력 옵션은 어떤 형식의 도형으로 입력이 주어지는지 알려주는거임

옵션glDrawArrays 그리기 옵션필요 정점 수
pointsGL_POINTS 원시를 그릴 때(1개)
linesGL_LINES 또는 GL_LINE_STRIP을 그릴 때(2개)
lines_adjacencyGL_LINES_ADJACENCY 또는 GL_LINE_STRIP_ADJACENCY(4개)
trianglesGL_TRIANGLES, GL_TRIANGLE_STRIP 또는 GL_TRIANGLE_FAN(3개)
triangles_adjacencyGL_TRIANGLES_ADJACENCY 또는 GL_TRIANGLE_STRIP_ADJACENCY(6개)

우리가 만약 glDrawArrays에서 GL_TRIANGLE을 그리고자 한다면
옵션을 triangle로 맞춰줘야함

out layout

그리려고하는 도형과 출력할 정점의 최대 개수를 제공해주면 됨

도형옵션
points
line_strip
삼각형triangle_strip

이렇게 그리려는 도형을 제공해주고

예를들어 삼각형 2개로 사각형을 그린다고 했을때
필요한 최대 정점 개수는 4개이므로

layout(triangle_strip, max_vertices = 4) out;

이렇게 제공해주면 됨

triangle_strip의 삼각형 그려지는 순서

제공되는 정점이 7개이면 7-2개의 삼각형이 만들어짐
그리고 만들어지는 삼각형은 (1,2,3) (2,3,4) (3,4,5) (4,5,6) (5,6,7)의 정점 순서로 만들어짐

EmitVertex, EndPrimitive

먼저 glsl에서는

in gl_Vertex
{
    vec4  gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
} gl_in[];

이런 인터페이스를 제공함

이 인터페이스는 이전단계의 쉐이더에서 넘겨진 데이터들임

따라서 Geometry Shader에서 직접 gl_Position에 뭔가를 제공하고싶으면
gl_Position = gl_in[0].glPosition;
이런식으로 제공해주면 됨

그리고 인터페이스가 배열형식으로 제공되는 이유는 정점이 여러개라서 그럼

그럼
EmitVertex가 뭐겠음?
Geometry shader에서 바꾼/만든 정점 적용하는거임

그럼
EndPrimitive는?
Geometry Shader에서 모든게 끝났으니 이제 마무리 짓는거임

예시

float points[] = 
{
    -0.5f,  0.5f, // top-left
     0.5f,  0.5f, // top-right
     0.5f, -0.5f, // bottom-right
    -0.5f, -0.5f  // bottom-left
};

이렇게 4개의 정점이 있음

#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 5) out;

void build_house(vec4 position)
{    
    gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0);    // 1:bottom-left
    EmitVertex();   
    gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0);    // 2:bottom-right
    EmitVertex();
    gl_Position = position + vec4(-0.2,  0.2, 0.0, 0.0);    // 3:top-left
    EmitVertex();
    gl_Position = position + vec4( 0.2,  0.2, 0.0, 0.0);    // 4:top-right
    EmitVertex();
    gl_Position = position + vec4( 0.0,  0.4, 0.0, 0.0);    // 5:top
    EmitVertex();
    EndPrimitive();
}

void main() {    
    build_house(gl_in[0].gl_Position);
}

그리고 이런 Geometry shader를 만들음
출력할 도형은 점인데,
쉐이더에서 삼각형으로 변환하는거임

각 정점에 대해 특정 vector값을 더해준다음 그걸로 삼각형을 그릴거임

그리고 출력해줌

glDrawArrays(GL_POINTS, 0, 2);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawArrays(GL_POINTS, 2, 2);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

그럼 아래처럼 나옴

딱 3개의 삼각형으로 그려진거 확인가능~

그럼 여기에 색상을 입혀보자

Geometry Shader에 in을 통해 변수를 받아야하는데...
일단 먼저 points를 약간 수정

float points[] = {
    -0.5f,  0.5f, 	1.0f, 0.0f, 0.0f, // top-left
     0.5f,  0.5f, 	0.0f, 1.0f, 0.0f, // top-right
     0.5f, -0.5f, 	0.0f, 0.0f, 1.0f, // bottom-right
    -0.5f, -0.5f, 	1.0f, 1.0f, 0.0f  // bottom-left
};  

vertex shader를 약간 수정

#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;
}

이전 챕터에서 공부한 인터페이스 블록 사용함

그리고 geometry에서 받아주면 되는데...

#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 5) out;

in VS_OUT
{
    vec3 color;
}gs_in[];

out vec3 fColor;

void build_house(vec4 position)
{
    fColor = gs_in[0].color;
    gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0);    // 1:bottom-left
    EmitVertex();
    gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0);    // 2:bottom-right
    EmitVertex();
    gl_Position = position + vec4(-0.2,  0.2, 0.0, 0.0);    // 3:top-left
    EmitVertex();
    gl_Position = position + vec4( 0.2,  0.2, 0.0, 0.0);    // 4:top-right
    EmitVertex();
    gl_Position = position + vec4( 0.0,  0.4, 0.0, 0.0);    // 5:top
    //additional
    fColor = vec3(1.0, 1.0, 1.0);
    EmitVertex();

    EndPrimitive();
}

void main() 
{
    build_house(gl_in[0].gl_Position);
}

이렇게 사용함
geometry shader는 입력이 정점들의 집합이므로 무조건 배열형식으로 in을 받아주면 됨

in vec3 outColor[];도 가능

쉐이더는 간단하게 vertex - geometry - fragment로 이어짐
따라서 geometry shader를 만든 이상, fragment로 색상을 넘겨줘야하니 이렇게 하는거 ㅇㅇ

그리고 fragment shader는 그냥 in받으면

이런 화면이 출력됨~~~

코드를 놓쳤다면

LearnOpenGL - geometry_shader_houses.cpp 이걸 참고!

Geometry Shader 사용 이유

cpu에서 정점 할당하고 gpu로 넘겨서 사용하는것보다
간단한 도형(e.g 잔디, 나뭇잎 등)은 gpu에 특정 정점만 주어지고,
그 정점을 토대로 gpu에서 정점을 만들어 특정 도형을 만드는게 더 빠르고 간단함

즉 gpu의 속도에서 바로바로 만들어내기때문에 속도가 어마어마하게 빠르게 동작하는거임

profile
그래픽스 하는 퍼그

0개의 댓글