Computer Graphics/OpenGL

OpenGL 정리 - 6. GLSL (OpenGL Shader Language)

surkim 2024. 9. 11. 14:17

이번에는 GLSL(OpenGL Shader Language)에 대해 배운 내용을 정리하겠다. GLSL은 OpenGL에서 그래픽을 처리하기 위해 셰이더 프로그램을 작성하는 데 사용되는 C 기반 언어이다. 이 포스팅에서는 GLSL의 기본 구조와 주요 개념, 사용 가능한 데이터 타입, 셰이더 입출력 방식에 대해 살펴보겠다.

1. GLSL이란?

  • GLSL: OpenGL에서 셰이더를 작성하기 위해 제공되는 언어로, GPU에서 동작하는 작은 프로그램을 작성하는 데 사용된다. 이러한 프로그램은 정점별, 픽셀별로 병렬 처리되어 높은 성능을 제공한다.
  • 대표적인 셰이더 언어:
    • HLSL: DirectX용 셰이더 언어
    • Metal: Metal API를 위한 셰이더 언어
    • cg: nVidia가 제시한 셰이더 언어

2. GLSL의 기본 구조

GLSL 코드는 다음과 같은 형태로 작성된다:

 

#version version_number

in type in_variable_name;
out type out_variable_name;

uniform type uniform_name;

void main() {
  // 입력값 처리 후 결과 출력
  out_variable_name = ...;
}
  • in: 셰이더로 들어오는 입력 변수
  • out: 셰이더의 출력 변수
  • uniform: 모든 셰이더 스레드에서 동일한 값을 사용하는 전역 변수

3. GLSL에서 사용 가능한 데이터 타입

  • 기본 타입:
    • int, float, double, uint, bool
  • 벡터 타입:
    • vecX: float형 벡터 (vec2, vec3, vec4)
    • ivecX: int형 벡터
    • uvecX: uint형 벡터
    • bvecX: bool형 벡터
    • dvecX: double형 벡터
  • 행렬 타입:
    • matX: float형 행렬 (mat2, mat3, mat4)
    • bmatX, imatX, umatX, dmatX: 각각 bool, int, uint, double형 행렬

4. 벡터 및 행렬의 사용

벡터와 행렬은 GLSL에서 그래픽 데이터를 처리하는 데 자주 사용된다. 벡터의 각 요소에 접근할 때는 .x, .y, .z, .w 또는 .r, .g, .b, .a를 사용할 수 있다. 이 방식은 swizzling이라고 불리며, 원하는 요소를 조합해 새로운 벡터를 만들 수 있다.

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;

5. 셰이더의 입출력 (In/Out)

모든 셰이더는 그 용도에 맞는 입출력 변수가 선언되어 있어야 한다. 입출력 변수는 inout으로 정의되며, 정점 셰이더와 프래그먼트 셰이더에서 중요한 역할을 한다.

5-1. 정점 셰이더(Vertex Shader)

정점 셰이더는 각 정점의 위치 정보를 입력받아, 출력 위치를 계산하는 역할을 한다. 반드시 gl_Position에 정점의 최종 위치를 출력해야 한다.

layout (location = 0) in vec3 aPos;
void main() {
    gl_Position = vec4(aPos, 1.0);
}

5-2. 래스터화(Rasterization)

정점 셰이더의 출력값은 래스터화 과정에서 보간되어, 프래그먼트 셰이더로 전달될 픽셀 값을 계산한다.

5-3. 프래그먼트 셰이더(Fragment Shader)

프래그먼트 셰이더는 래스터화된 정점 셰이더의 출력값을 픽셀 단위로 처리하여 최종 색상을 계산하는 역할을 한다.

out vec4 FragColor;
void main() {
    FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 빨간색 출력
}

6. Uniform 변수

Uniform 변수는 셰이더 프로그램에 전달되는 글로벌 값이다. 모든 셰이더 스레드에서 동일한 값을 갖고 있기 때문에, 전역 상태나 설정값을 전달하는 데 유용하다.

Uniform 변수는 다음과 같이 사용된다:

  1. **glGetUniformLocation()**으로 셰이더 프로그램에서 uniform 변수의 위치를 얻는다.
  2. glUniform...() 함수를 통해 값을 셰이더에 전달한다.
int uniformLoc = glGetUniformLocation(program, "myUniform");
glUniform1f(uniformLoc, 0.5f);

7. GLSL에서 배운 핵심 개념 정리

  • GLSL은 C와 유사한 문법을 사용하는 셰이더 언어로, 벡터와 행렬 같은 데이터 타입을 제공하여 3D 그래픽 처리에 최적화되어 있다.
  • 정점 셰이더는 정점의 위치를 계산하고, 프래그먼트 셰이더는 픽셀의 최종 색상을 계산한다.
  • inout 키워드를 사용하여 셰이더 간의 데이터를 주고받는다.
  • uniform 변수를 통해 셰이더 프로그램에서 사용할 글로벌 데이터를 설정할 수 있다.