1. Instancing
1.1 Instancing이란?
Instancing은 동일한 오브젝트를 여러 번 렌더링해야 할 때 사용되는 최적화 기법이다. 예를 들어, 게임 속에서 풀이나 나무 같은 오브젝트가 수천 개 이상 반복해서 등장하는 경우를 생각해 보자. 각 오브젝트를 따로 드로우 콜을 호출하면 CPU와 GPU 간의 통신이 반복되어 성능이 저하된다.
Instancing을 사용하면 한 번의 드로우 콜로 수천 개의 오브젝트를 동시에 그릴 수 있어, CPU와 GPU 간의 통신을 최소화하여 성능을 최적화할 수 있다.
1.2 Instancing 구현 흐름과 예제 코드
Instancing을 위해 주로 glDrawArraysInstanced()
또는 glDrawElementsInstanced()
함수를 사용하며, 인스턴스 ID인 gl_InstanceID
를 통해 각각의 오브젝트를 구분할 수 있다.
1.2.1 Uniform을 활용한 Instancing 예제
첫 번째 방법은 Uniform 배열을 사용해 인스턴스별 위치나 색상을 전달하는 것이다.
- Vertex Shader 코드
#version 330 core
layout(location = 0) in vec2 aPos; // 오브젝트 위치
layout(location = 1) in vec3 aColor; // 오브젝트 색상
out vec3 fColor;
uniform vec2 offsets[100]; // 각 인스턴스의 위치 오프셋 배열
void main() {
vec2 offset = offsets[gl_InstanceID]; // 인스턴스 ID로 각 오프셋 불러오기
gl_Position = vec4(aPos + offset, 0.0, 1.0);
fColor = aColor;
}
위 코드에서는 offsets
라는 Uniform 배열로 100개의 인스턴스 위치를 제공하고, gl_InstanceID
로 각 오프셋을 구분하여 위치를 설정한다.
- C++ 코드 (Instancing 호출)
glBindVertexArray(quadVAO); // VAO 바인딩
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100); // 100개의 인스턴스를 그리기
glDrawArraysInstanced()
의 마지막 인자는 인스턴스의 개수로, 한 번의 호출로 100개의 인스턴스를 그린다.
1.2.2 VBO를 활용한 Instancing 예제
Uniform 배열을 사용하는 대신, VBO로 각 인스턴스의 위치 데이터를 관리할 수도 있다. 이는 인스턴스의 수가 매우 많을 때 유리하다.
- VBO에 오프셋 데이터 설정
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100, &translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
- Vertex Attribute와 Divisor 설정
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glVertexAttribDivisor(2, 1); // 2번째 attribute는 gl_InstanceID가 1 증가할 때마다 갱신
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor()
를 사용해 지정된 Attribute가 인스턴스마다 업데이트되도록 설정한다. 이렇게 하면 aOffset
이 각 인스턴스별로 다르게 적용되며, 각각의 인스턴스가 지정된 위치에 렌더링된다.
- Vertex Shader (VBO Instancing)
#version 330 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aOffset;
out vec3 fColor;
void main() {
gl_Position = vec4(aPos + aOffset, 0.0, 1.0); // 각 인스턴스의 위치 오프셋을 적용
fColor = aColor;
}
1.3 Instancing을 통해 얻을 수 있는 성능 향상
이와 같은 Instancing 기법을 통해 여러 개의 동일한 오브젝트를 단일 드로우 콜로 처리함으로써, CPU와 GPU 간의 통신 비용을 줄이고 프레임 속도를 크게 향상시킬 수 있다. 수많은 오브젝트가 등장하는 장면에서 Instancing을 활용하면 매우 빠른 성능을 체감할 수 있다.
2. Anti-Aliasing
2.1 앨리어싱(Aliasing) 현상과 원인
앨리어싱(Aliasing)은 오브젝트의 경계가 계단 형태로 울퉁불퉁하게 보이는 현상을 말한다. 이는 삼각형을 픽셀로 변환하는 래스터화(rasterization) 과정에서 발생하며, 삼각형 경계 부분을 픽셀로 완벽히 채우기 어렵기 때문에 생긴다.
2.2 Anti-Aliasing 기법
안티앨리어싱은 이러한 계단 현상을 줄이는 여러 기법들을 총칭하는 말이다. 대표적인 방법으로는 슈퍼샘플링(Supersampling) 안티앨리어싱 (SSAA)와 멀티샘플링 안티앨리어싱(MSAA)가 있다.
- SSAA (Supersampling Anti-Aliasing): 원래 해상도보다 큰 해상도로 렌더링한 후, 이를 다운샘플링하여 계단 현상을 줄이는 방법이다. 하지만 큰 해상도로 렌더링하기 때문에 성능 비용이 매우 크다는 단점이 있다.
- MSAA (Multisample Anti-Aliasing): OpenGL에서 기본으로 제공하는 안티앨리어싱 기법으로, 픽셀의 여러 샘플을 조사하여 삼각형 안에 포함된 샘플의 개수에 따라 알파값을 조절하는 방식이다. SSAA보다 성능 비용이 적으면서도 뛰어난 효과를 낼 수 있어 많이 사용된다.
2.3 MSAA 적용 방법
- Window 생성 시 MSAA 활성화
glfwWindowHint(GLFW_SAMPLES, 4); // 4개의 멀티샘플 사용
- OpenGL에서 MSAA 활성화
glEnable(GL_MULTISAMPLE); // MSAA 활성화
위 코드처럼 Window를 생성하기 전에 MSAA 샘플 개수를 지정하고, OpenGL에서 MSAA 기능을 활성화하면 자동으로 안티앨리어싱이 적용된다.
2.4 MSAA를 사용한 Off-Screen Anti-Aliasing
프레임버퍼를 사용하여 오프스크린 렌더링 시에도 MSAA를 적용할 수 있다. 이를 위해 GL_TEXTURE_2D_MULTISAMPLE 텍스처 타겟을 사용하며, 프레임버퍼에 멀티샘플을 적용한 텍스처를 붙이고, 별도의 해상도 조정 단계를 거친다.
- 멀티샘플 텍스처와 렌더 버퍼 설정
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
- 멀티샘플을 일반 텍스처로 변환 (Resolve 단계)
glBindFramebuffer(GL_READ_FRAMEBUFFER, msFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
이 과정에서 멀티샘플 버퍼를 일반 버퍼로 변환하며, 최종 화면에 MSAA가 적용된 상태로 렌더링할 수 있게 된다.
'Computer Graphics > OpenGL' 카테고리의 다른 글
OpenGL 정리 - 25. Normal Mapping (0) | 2024.11.10 |
---|---|
OpenGL 정리 - 24. Shadow Mapping (0) | 2024.11.10 |
OpenGL 정리 - 22. GPU 데이터 관리 기법, UBO, Geometry Shader (0) | 2024.10.30 |
OpenGL 정리 - 21. 큐브 맵 (Cubemap) (0) | 2024.10.28 |
OpenGL 정리 - 20. 프레임 버퍼 (Frame Buffer) (0) | 2024.10.25 |