이 코드는 격자를 OpenGL로 렌더링할 준비를 완료하는 함수입니다. 배열로 정점 및 인덱스 데이터를 설정한 후, 이를 OpenGL의 VBO, IBO, VAO에 바인딩하여 효율적으로 GPU에서 접근할 수 있게 합니다.
void Grid::CreateGrid(GLfloat XDim, GLfloat ZDim, int XDiv, int ZDiv)
{
// Calculate total vertices and indices.
GLuint vertexNum = 3 * (XDiv+1) * (ZDiv+1) * 2;
GLuint indexNum = ((XDiv+1) + (ZDiv+1)) * 2;
// Allocate required space for vertex and indice location.
GLfloat* gridVertex = new GLfloat[ vertexNum ];
GLushort* gridIndices = new GLushort[ indexNum ];
// Store unit division interval and half length of dimension.
GLfloat xInterval = XDim/XDiv;
GLfloat zInterval = ZDim/ZDiv;
GLfloat xHalf = XDim/2;
GLfloat zHalf = ZDim/2;
int i = 0;
// Assign vertices along X-axis.
for( int j=0; j<XDiv+1; j++){
gridVertex[i++] = j*xInterval - xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = zHalf;
gridVertex[i++] = j*xInterval - xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = -zHalf;
}
// Assign vertices along Z-axis.
for( int j=0; j<ZDiv+1; j++){
gridVertex[i++] = -xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = j*zInterval - zHalf;
gridVertex[i++] = xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = j*zInterval - zHalf;
}
i = 0;
// Assign indices along X-axis.
for( int j=0; j<XDiv+1; j++ ){
gridIndices[i++] = 2*j;
gridIndices[i++] = 2*j+1;
}
// Assign indices along Z-axis.
for( int j=0; j<ZDiv+1; j++ ){
gridIndices[i++] = ((XDiv+1)*2) + (2*j);
gridIndices[i++] = ((XDiv+1)*2) + (2*j+1);
}
// Create name buffer object ID
GLuint size = vertexNum*sizeof(float);
glGenBuffers(1, &vIdGrid);
// Create VBO for Grid
glBindBuffer( GL_ARRAY_BUFFER, vIdGrid);
glBufferData( GL_ARRAY_BUFFER, size, 0, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, size, gridVertex );
// Create IBO for Grid
unsigned short indexSize = sizeof( unsigned short )*indexNum;
glGenBuffers(1, &iIdGrid);
glBindBuffer( GL_ARRAY_BUFFER, iIdGrid );
glBufferData( GL_ARRAY_BUFFER, indexSize, 0, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, indexSize, gridIndices );
// Create Vertex Array Object
glGenVertexArrays(1, &Vertex_VAO_Id);
glBindVertexArray(Vertex_VAO_Id);
// Create VBO and set attribute parameters
glBindBuffer( GL_ARRAY_BUFFER, vIdGrid );
glEnableVertexAttribArray(VERTEX_LOCATION);
glVertexAttribPointer(VERTEX_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, iIdGrid );
// Make sure the VAO is not changed from outside code
glBindVertexArray(0);
// Unbind buffer
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
delete gridVertex;
delete gridIndices;
}
코드 분석 >
GLuint vertexNum = 3 * (XDiv+1) * (ZDiv+1) * 2;
GLuint indexNum = ((XDiv+1) + (ZDiv+1)) * 2;
- vertexNum: 각 X 및 Z축 방향으로 (XDiv + 1)개의 점을 생성하고, 각 점은 3개의 GLfloat 값(X, Y, Z 좌표)을 가지므로 총 크기를 계산합니다.
- indexNum: X축과 Z축 각각에 대해 인덱스를 설정할 수 있는 크기입니다.
GLfloat* gridVertex = new GLfloat[vertexNum];
GLushort* gridIndices = new GLushort[indexNum];
- gridVertex: 정점 좌표를 저장하는 배열입니다.
- gridIndices: 정점 인덱스를 저장하는 배열입니다.
GLfloat xInterval = XDim / XDiv;
GLfloat zInterval = ZDim / ZDiv;
GLfloat xHalf = XDim / 2;
GLfloat zHalf = ZDim / 2;
- xInterval 및 zInterval은 각각 X축과 Z축 방향의 격자 간격입니다.
- xHalf와 zHalf는 X축 및 Z축의 절반 길이로, 격자를 중심에 배치하기 위해 사용됩니다.
for (int j = 0; j < XDiv + 1; j++) {
gridVertex[i++] = j * xInterval - xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = zHalf;
gridVertex[i++] = j * xInterval - xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = -zHalf;
}
for (int j = 0; j < ZDiv + 1; j++) {
gridVertex[i++] = -xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = j * zInterval - zHalf;
gridVertex[i++] = xHalf;
gridVertex[i++] = 0.0f;
gridVertex[i++] = j * zInterval - zHalf;
}
- XDiv+1 개의 점을 X축 방향으로 설정합니다.
- 각각의 점은 gridVertex 배열에 순차적으로 X, Y, Z 좌표로 저장됩니다.
- Z축 방향으로 동일한 방식으로 정점을 설정하여 gridVertex 배열에 추가합니다.
for (int j = 0; j < XDiv + 1; j++) {
gridIndices[i++] = 2 * j;
gridIndices[i++] = 2 * j + 1;
}
for (int j = 0; j < ZDiv + 1; j++) {
gridIndices[i++] = ((XDiv + 1) * 2) + (2 * j);
gridIndices[i++] = ((XDiv + 1) * 2) + (2 * j + 1);
}
- 각 X축 선에 대해 두 개의 인덱스를 추가하여 정점 연결을 정의합니다.
- Z축 선의 인덱스도 유사하게 추가하여 정점 연결을 정의합니다.
glGenBuffers(1, &vIdGrid);
glBindBuffer(GL_ARRAY_BUFFER, vIdGrid);
glBufferData(GL_ARRAY_BUFFER, vertexNum * sizeof(float), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexNum * sizeof(float), gridVertex);
glGenBuffers(1, &iIdGrid);
glBindBuffer(GL_ARRAY_BUFFER, iIdGrid);
glBufferData(GL_ARRAY_BUFFER, indexSize, 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, indexSize, gridIndices);
- vIdGrid VBO를 생성하고, gridVertex 데이터를 GPU 메모리에 전송합니다.
- iIdGrid IBO를 생성하고, gridIndices 데이터를 GPU 메모리에 전송합니다.
glGenVertexArrays(1, &Vertex_VAO_Id);
glBindVertexArray(Vertex_VAO_Id);
glBindBuffer(GL_ARRAY_BUFFER, vIdGrid);
glEnableVertexAttribArray(VERTEX_LOCATION);
glVertexAttribPointer(VERTEX_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iIdGrid);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
delete[] gridVertex;
delete[] gridIndices;
- VAO를 생성하여 VBO 및 IBO의 설정을 저장합니다.
- VAO를 활성화하여 정점 속성(VERTEX_LOCATION)을 설정하고, 버퍼를 VAO에 바인딩합니다.
- VAO와 VBO, IBO의 바인딩을 해제하여 외부에서 변경되지 않도록 하고, CPU 메모리에 할당된 배열을 해제합니다.
렌더링 코드 >
void Grid::Render()
{
glEnable( GL_DEPTH_TEST );
glUseProgram( program->ProgramID );
static int k = 0;
TransformObj->TransformPushMatrix();
TransformObj->TransformRotate(20, 1, 0, 0);
TransformObj->TransformRotate(k++, 0, 1, 0);
TransformObj->TransformTranslate(0.0f, -10, -7);
glUniformMatrix4fv( MVP, 1, GL_FALSE,(float*)TransformObj->TransformGetModelViewProjectionMatrix() );
TransformObj->TransformPopMatrix();
glBindVertexArray(Vertex_VAO_Id);
glDrawElements(GL_LINES, ((XDivision+1) + (ZDivision+1) )*2, GL_UNSIGNED_SHORT, (void*)0);
}
- TransformPushMatrix():
- 현재 행렬을 스택에 저장하여 이후 변환 작업에 영향을 주지 않도록 합니다. 나중에 TransformPopMatrix()를 호출하여 이 시점의 행렬 상태로 복원할 수 있습니다.
- 첫 번째 회전 TransformRotate(20, 1, 0, 0);:
- TransformRotate(20, 1, 0, 0);는 X축을 기준으로 20도 회전을 적용합니다.
- 이는 오브젝트가 화면에서 위아래로 약간 기울어지도록 만듭니다.
- 두 번째 회전 TransformRotate(k++, 0, 1, 0);:
- Y축을 기준으로 k++도 만큼 회전을 적용합니다. 이때 k는 매번 증가하는 값이므로, 오브젝트는 Y축을 중심으로 계속해서 회전하게 됩니다.
- 이 회전은 화면에서 오브젝트가 좌우로 도는 것처럼 보입니다.
- 이동 TransformTranslate(0.0f, -10, -7);:
- Z축 방향으로 -7만큼, Y축 방향으로 -10만큼 이동합니다.
- 이는 격자를 카메라에서 일정 거리만큼 떨어진 위치에 배치하도록 설정하며, 화면의 아래쪽으로 이동시킵니다.
- glUniformMatrix4fv를 사용한 MVP 행렬 설정:
- TransformGetModelViewProjectionMatrix()를 통해 계산된 최종 변환 행렬(MVP)을 glUniformMatrix4fv로 셰이더에 전달합니다. 이 행렬은 모든 변환이 적용된 최종 행렬입니다.
- MVP 행렬은 모델, 뷰, 투영 행렬을 합성한 것이며, 격자가 변환된 좌표 공간에서 올바르게 렌더링되도록 합니다.
'Opengles 3.0 with Android' 카테고리의 다른 글
Chapter 3.5 Primitive Restart (2) | 2024.10.31 |
---|---|
Chapter 3.4 Instance 렌더링 (0) | 2024.10.30 |
Chatper 3.2 Grouping Uniform and Creating Buffers (0) | 2024.10.26 |
Chapter 2.2 (Vertex Array object) 사용한 Cube 렌더링 (1) | 2024.10.22 |
Chapter 2.1 VBO(Vertex Buffer Object) 사용하여 정사각형 렌더링. 해본다. (0) | 2024.10.17 |