CreateVBO 함수에서 VBO와 EBO를 생성하고 데이터들을 전송한 뒤,
Render 함수에서 셰이더에 데이터를 연결하고 삼각형 두 개를 그려 정사각형을 렌더링합니다.
void Square::CreateVBO() {
// VBO 생성 -> 바인딩 -> 버퍼에 데이터 복사
glGenBuffers(1, &bufferId);
glBindBuffer(GL_ARRAY_BUFFER, bufferId);
// 버텍스 배열 먼저 넣고 뒤에 컬러 배열 있음.
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
// EBO 생성 -> 바인딩 -> 버퍼 복사
glGenBuffers(1, &indexId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);
}
void Square::Render() {
glUseProgram( program->ProgramID );
// 버퍼 정보를 셰이더에 알려줌
char attrib = ProgramManagerObj->ProgramGetVertexAttribLocation(program, (char*)"VertexPosition");
glVertexAttribPointer(attrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(attrib);
char attribColor = ProgramManagerObj->ProgramGetVertexAttribLocation(program, (char*)"VertexColor");
// 버텍스 배열 이후에 컬러 배열 있음.
glVertexAttribPointer(attribColor, 3, GL_FLOAT, GL_FALSE, 0, (void*)sizeof(vertices));
glEnableVertexAttribArray(attribColor);
// 렌더링 삼각형 2개는 count : 6, 마지막 인자는 0이면 바인딩된 인덱스 버퍼 처음부터 사용.
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
CreateVBO 함수 설명
- VBO 생성 및 데이터 전송:
- **glGenBuffers**로 VBO를 생성하고, **glBindBuffer**로 VBO를 바인딩합니다.
- **glBufferData**는 VBO에 필요한 메모리를 할당합니다. 이때 정점 데이터와 색상 데이터를 한 번에 보낼 공간을 확보한 후, **glBufferSubData**를 사용해 먼저 정점 데이터를 전송하고, 그 다음에 색상 데이터를 전송합니다.
- 정점 데이터는 vertices 배열, 색상 데이터는 colors 배열에서 가져와 메모리에 복사됩니다.
- EBO 생성 및 데이터 전송:
- **glGenBuffers**로 EBO를 생성하고, **glBindBuffer**로 EBO를 바인딩한 뒤, **glBufferData**로 인덱스 데이터를 GPU로 전송합니다.
- 인덱스 데이터는 indexes 배열로부터 가져와, 정점들을 어떻게 연결해 삼각형을 그릴지를 결정합니다.
Render 함수 설명
- 셰이더 프로그램 활성화:
- **glUseProgram**으로 현재 사용할 셰이더 프로그램을 활성화합니다. 이 셰이더는 정점과 색상 데이터를 처리하는 역할을 합니다.
- 정점 및 색상 속성 설정:
- **glVertexAttribPointer**는 VBO에서 가져온 데이터를 셰이더 속성과 연결하는 함수입니다. 정점 데이터는 VBO의 처음부터 시작되며, 색상 데이터는 정점 데이터 뒤에 위치해 있습니다.
- **glVertexAttribPointer**에서 오프셋을 주어, sizeof(vertices)만큼 이동한 후 색상 데이터를 참조하게 설정합니다.
- 정점 속성 활성화:
- **glEnableVertexAttribArray**는 지정된 속성을 활성화하여 GPU가 해당 데이터를 참조할 수 있게 해줍니다. 정점 위치와 색상 두 가지 속성을 모두 활성화합니다.
- 렌더링 호출:
- glDrawElements 함수는 인덱스 배열을 사용하여 도형을 그리는 함수입니다. 이 코드에서는 **2개의 삼각형(총 6개의 인덱스)**을 사용하여 정사각형을 그립니다.
- **GL_TRIANGLES**는 삼각형을 그리는 모드이며, 인덱스 배열을 사용하여 정점 데이터를 재사용할 수 있습니다.
요약
CreateVBO 함수는 정점 데이터와 색상 데이터를 GPU 메모리에 전송하고, 인덱스 버퍼를 설정하여 삼각형 두 개를 그리기 위한 데이터를 준비합니다.
Render 함수는 준비된 데이터를 셰이더 프로그램과 연결하고, **glDrawElements**를 사용해 인덱스 배열을 통해 도형을 렌더링합니다.
이 방식은 정점 데이터를 효율적으로 관리하며, 중복된 정점 데이터의 재사용을 통해 성능을 최적화할 수 있습니다.
=========================================================================================
API 설명
1. glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage)
- 설명: 버퍼를 할당하고 데이터를 채워넣는 함수.
- target: 버퍼의 유형을 지정 (GL_ARRAY_BUFFER는 정점 데이터를 위한 버퍼).
- size: 할당할 버퍼의 크기(바이트 단위).
- data: 버퍼에 채울 초기 데이터.
- usage: 데이터의 사용 패턴을 지정 (GL_STATIC_DRAW, GL_DYNAMIC_DRAW 등).매개변수:
2. glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
- 설명: 이미 할당된 버퍼에서 일부 데이터를 업데이트하는 함수.
- target: 업데이트할 버퍼의 유형 (GL_ARRAY_BUFFER).
- offset: 업데이트할 데이터가 시작될 오프셋(바이트 단위). 버퍼에서 어느 위치부터 데이터를 변경할지 결정.
- size: 업데이트할 데이터의 크기(바이트 단위).
- data: 버퍼의 오프셋에 덮어쓸 새로운 데이터.매개변수:
3. glGenBuffers(GLsizei n, GLuint* buffers)
- 설명: 버퍼 객체를 생성하는 함수.
- 매개변수:
- n: 생성할 버퍼의 개수.
- buffers: 생성된 버퍼 ID를 저장할 배열.
4. glBindBuffer(GLenum target, GLuint buffer)
- 설명: 지정된 버퍼 객체를 바인딩하여 이후의 작업들이 이 버퍼에 적용되도록 설정.
- 매개변수:
- target: 바인딩할 버퍼의 유형 (GL_ARRAY_BUFFER).
- buffer: 바인딩할 버퍼 객체의 ID.
5. glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer)
- 설명: 정점 데이터를 셰이더 속성과 연결해주는 함수.
- index: 셰이더에서 참조할 정점 속성 위치 (예: 위치, 색상 등).
- size: 정점 속성의 요소 수 (예: 3이면 x, y, z).
- type: 데이터 타입 (GL_FLOAT).
- normalized: 정규화 여부.
- stride: 정점 사이의 바이트 간격.
- pointer: 버퍼에서 데이터가 시작될 오프셋 위치.매개변수:
pointer가 nullptr 이면 바인딩 된 버퍼에서 데이터를 가져옴
6. glEnableVertexAttribArray(GLuint index)
- index: 활성화할 정점 속성의 인덱스. 이 인덱스는 **glVertexAttribPointer()**에서 지정한 정점 속성의 인덱스와 일치해야 해.
- 예를 들어, 위치 데이터가 glVertexAttribPointer(0, ...)로 설정되었다면, 위치 속성 배열을 활성화하기 위해 glEnableVertexAttribArray(0)를 사용해
7. glDrawArrays(GLenum mode, GLint first, GLsizei count)
- 설명: 현재 바인딩된 버퍼를 기반으로 정점 데이터를 그리는 함수.
매개변수:
- mode: 그릴 도형의 유형 (GL_TRIANGLES 등).
- first: 그리기 시작할 첫 번째 정점의 인덱스.
- count: 그릴 정점의 개수.
8. glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
매개변수 설명
- mode (GLenum):
- 그릴 도형의 **프리미티브 타입(Primitive Type)**을 지정합니다.
- 대표적인 값들은 다음과 같습니다:
- GL_TRIANGLES: 정점 3개씩 모아서 삼각형을 그립니다.
- GL_TRIANGLE_STRIP: 정점들이 줄을 지어 삼각형을 형성하는 방식입니다.
- GL_LINES: 두 개의 정점으로 선을 그립니다.
- GL_POINTS: 점을 그립니다.
- count (GLsizei):
- 인덱스 배열의 요소 개수를 나타냅니다. 즉, 그릴 도형에 필요한 인덱스의 수입니다.
- 예를 들어, 삼각형 두 개를 그리기 위해서는 6개의 인덱스가 필요합니다.
- type (GLenum):
- 인덱스 배열에 저장된 데이터의 타입을 지정합니다.
- 사용 가능한 값은 GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, 또는 **GL_UNSIGNED_INT**입니다.
- 인덱스 배열이 1바이트, 2바이트, 또는 4바이트 크기의 정수 값으로 저장될 수 있기 때문에 이에 따라 타입을 설정해 줍니다.
- indices (const void*):
- 인덱스 배열의 시작 위치를 나타냅니다. 보통 0을 넣어 사용하며, 이는 GPU에 바인딩된 인덱스 버퍼의 처음부터 인덱스 데이터를 읽으라는 의미입니다.
- **EBO(Element Buffer Object)**에 바인딩된 버퍼에서 인덱스 데이터의 시작 주소를 참조할 때 이 값이 사용됩니다.
질문
glVertexAttribPointer와 vec4
glVertexAttribPointer 함수에서 size는 정점당 몇 개의 요소를 셰이더로 보낼 것인지를 결정하는 값입니다. 이 값이 2로 설정되었으므로, 각 정점에 대해 x, y 좌표만 전달되고, z와 w 좌표는 전달되지 않습니다.
셰이더에서 vec4와 glVertexAttribPointer의 상호작용
셰이더에서 VertexPosition이 **vec4**라면, OpenGL은 자동으로 부족한 값을 기본값으로 채워줍니다. 만약 **2개의 값(x, y)**만 전달되면, 셰이더에서 z는 0.0, w는 1.0으로 자동 설정됩니다.
즉, 다음과 같이 동작합니다:
- glVertexAttribPointer에서 2개의 값을 전달: (x, y).
- 셰이더의 vec4는 자동으로 다음과 같이 채워집니다: (x, y, 0.0, 1.0).
이 방식은 2D 데이터를 3D 공간에 표시하려고 할 때 자주 사용됩니다. 즉, z축이 0인 평면 위에서 도형을 그리는 것이며, w는 1.0으로 유지되어 동일한 좌표계 변환이 적용됩니다.
'Opengles 3.0 with Android' 카테고리의 다른 글
Chatper 3.2 Grouping Uniform and Creating Buffers (0) | 2024.10.26 |
---|---|
Chapter 2.2 (Vertex Array object) 사용한 Cube 렌더링 (1) | 2024.10.22 |
Chapter 1.3 Touch Event 받아서 Triangle 색상 변경해보기 (0) | 2024.10.15 |
Chapter 1.2 Vertex Buffer 사용해보기 (0) | 2024.10.12 |
Chapter 1.1 Shader Build (0) | 2024.10.12 |