OpenGLES3.0_Example/Chapter_3/app/src/main/cpp/Scene/InstanceCube.cpp at main · dlgmlals3/OpenGLES3.0_Example
Contribute to dlgmlals3/OpenGLES3.0_Example development by creating an account on GitHub.
github.com

인스턴스 렌더링(Instanced Rendering)은 동일한 **메시(Mesh)**를 여러 개 렌더링할 때 성능 최적화를 위해 사용된다.
1000개의 동일한 물체를 렌더링을 가정하면
인스턴스 렌더링을 사용하지 않으면
- 각 물체마다 다른 MVP 행렬을 적용해야 하기 때문에
- 1000번의 draw call과, 1000번의 uniform 설정함수를 실행해야 한다.
반면 인스턴스 렌더링을 사용하게 되면,
- 1회의 draw call로 여러 객체를 처리가 가능하다.
- 변환 행렬이 유니폼이 아닌 버텍스 어트리뷰트로 사용한다.
📌 인스턴스 렌더링 vs 유니폼 변경 방식 비교
유니폼 변경 |
- 개별 객체마다 다른 변환 적용 가능 - 코드가 간단하고 구현이 쉬움 |
- glDrawElements() 호출이 많아지면 성능 저하 - CPU와 GPU 간의 호출 오버헤드 증가 |
- 렌더링할 객체 수가 적을 때 (수십 개 이하) - 각 개체마다 완전히 다른 변환이 필요할 때 |
인스턴스 렌더링 |
- glDrawElementsInstanced() 한 번으로 여러 객체 처리 가능 (Draw Call 최소화) - 대량 렌더링 시 성능이 크게 향상됨 |
- 변환 행령을 유니폼을 사용하지 않고 버텍스 어트리뷰트 값을 사용 |
- 대량 객체 렌더링 (수백 개 이상) 필요할 때 - 동일한 객체를 한꺼번에 그릴 때 (예: 군집 렌더링) |
✅ 인스턴스 렌더링(Instanced Rendering) 주요 함수
- glVertexAttribDivisor()를 이용해 인스턴스별 속성 설정 (변환 행렬 사용)
- divisor = 0: 속성이 각 정점마다 갱신됩니다.
- divisor = 1: 속성이 각 인스턴스마다 갱신됩니다.
- divisor = n: 속성이 매 n개의 인스턴스마다 갱신됩니다.
- glDrawElementsInstanced()로 한 번에 여러개의 메쉬를 렌더링
Code
1. 정점, 인덱스, 인스턴스 위치 데이터 준비
float cubeVerts[] = {
// 정점 좌표 (X, Y, Z)
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f
};
unsigned short cubeIndices[] = {
0, 1, 2, 2, 3, 0, // 앞면
4, 5, 6, 6, 7, 4, // 뒷면
0, 1, 5, 5, 4, 0, // 밑면
2, 3, 7, 7, 6, 2, // 윗면
0, 3, 7, 7, 4, 0, // 왼쪽면
1, 2, 6, 6, 5, 1 // 오른쪽면
};
glm::vec3 instanceOffsets[100]; // 변환 행렬
for (int i = 0; i < 100; i++) {
float x = (i % 10) * 2.0f; // X축 정렬 (10 x 10)
float y = ((i / 10) % 10) * 2.0f; // Y축 정렬
float z = 0.0f; // 평면 배치
instanceOffsets[i] = glm::vec3(x, y, z);
}
2. VBO, IBO, 인스턴스 변환행렬 VBO
GLuint vbo, ibo, instanceVBO;
glGenBuffers(1, &vbo);
glGenBuffers(1, &ibo);
glGenBuffers(1, &instanceVBO);
// 정점 및 색상 VBO
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVerts), cubeVerts, GL_STATIC_DRAW);
// 인덱스 IBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
// 인스턴스 오프셋 VBO
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(instanceOffsets), instanceOffsets, GL_STATIC_DRAW);
3. VAO 설정 ( Vertex Attribute 설정 정보 저장 & 로딩 용이)
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// 1. 정점 속성 설정
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
// 2. 인스턴스 위치 속성 설정
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glVertexAttribDivisor(1, 1); // 인스턴스마다 1번만 업데이트
// 3. 인덱스 바인딩
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
// VAO 보호
glBindVertexArray(0);
4. 셰이더 설정
#version 300 es
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aOffset;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main() {
vec3 finalPosition = aPos + aOffset; // 인스턴스별 위치 적용
gl_Position = projection * view * model * vec4(finalPosition, 1.0);
}
5. 렌더링
glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0, 100);
/*
// 인스턴스 사용하지 않는 경우.
for (int i = 0; i < 100; i++) {
glm::mat4 model = glm::translate(glm::mat4(1.0f), instanceOffsets[i]);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
}
*/
주요 함수 설명
void glVertexAttribDivisor(GLuint index, GLuint divisor);
인스턴스 렌더링(instance rendering) 시에 각 속성이 얼마나 자주 갱신되어야 하는지 지정하는 함수입니다. 이 함수는 여러 인스턴스를 동시에 렌더링할 때, 각 인스턴스에 대해 정점 속성(예: 위치, 색상, 변환 행렬 등)을 다르게 설정할 수 있도록 합니다.
매개변수 설명
- index: 속성의 위치로, glVertexAttribPointer로 지정한 속성 인덱스와 동일합니다.
- divisor: 이 속성이 얼마나 자주 갱신될지를 나타내는 값입니다.
- divisor = 0: 속성이 각 정점마다 갱신됩니다. 이는 일반적인 VBO처럼 작동하여, 하나의 정점마다 속성 데이터가 변경됩니다.
- divisor = 1: 속성이 각 인스턴스마다 갱신됩니다. 예를 들어, 변환 행렬처럼 각 인스턴스마다 다르게 설정할 필요가 있는 속성에 사용합니다.
- divisor = n: 속성이 매 n개의 인스턴스마다 갱신됩니다. 예를 들어, divisor = 2라면 2개의 인스턴스마다 속성이 한 번씩 갱신됩니다.
void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
OpenGL에서 **인스턴스 렌더링(instance rendering)**을 수행하는 함수로,
하나의 드로우 호출로 여러 인스턴스를 한꺼번에 렌더링할 수 있게 해줍니다. 이 함수는 각 인스턴스가 동일한 정점 데이터를 사용하지만, 위치, 크기, 회전과 같은 변환이 인스턴스마다 다를 때 유용합니다.
매개변수 설명
- mode: 그리기 모드를 지정합니다. 렌더링할 기본 도형을 정의하는 값으로, 다음 중 하나를 사용할 수 있습니다.
- GL_TRIANGLES: 삼각형을 사용해 도형을 그림
- GL_LINES: 선을 사용해 도형을 그림
- GL_POINTS: 점을 사용해 도형을 그림
- 그 외에 GL_TRIANGLE_STRIP, GL_LINE_STRIP 등 다양한 도형이 있습니다.
- count: 각 인스턴스에서 사용할 정점 인덱스의 개수입니다.
- 예를 들어, 삼각형으로 구성된 큐브는 36개의 정점 인덱스를 사용하므로 count = 36을 지정합니다.
- type: 인덱스 배열에 있는 값의 자료형을 지정합니다.
- 주로 GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT 중 하나를 사용합니다.
예를 들어, 인덱스 배열이 unsigned int 타입이라면 GL_UNSIGNED_INT로 설정합니다.
- 주로 GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT 중 하나를 사용합니다.
- indices: 인덱스 배열의 시작 위치에 대한 포인터입니다.
- 인덱스 버퍼 객체(IBO)에서 데이터를 사용할 경우, 0으로 설정하고 IBO를 미리 바인딩합니다.
- instancecount: 생성할 인스턴스의 개수입니다.
- 예를 들어, 1000개의 큐브 인스턴스를 렌더링하고 싶다면 instancecount = 1000으로 설정합니다.
'Opengles 3.0 with Android' 카테고리의 다른 글
Chapter 4. OBJ Loader (0) | 2025.03.08 |
---|---|
Chapter 3.3 Primitive Restart < Skip > (2) | 2025.02.24 |
Chatper 3.1 Layout Qualifier, Grouping Uniforms(UBO) (0) | 2025.02.24 |
Chapter 2.5 VAO ? VBO ? ( 참고 ) (1) | 2025.02.22 |
Chapter 2.1 Shader Build (0) | 2025.02.22 |