OpenGL ES는 3차원 컴퓨터 그래픽스 API인 OpenGL(Open Graphic Library)의 임베디드 시스템을 위한 버전이다. ES가 Embaedded System을 의미한다.
OpenGL은 다양한 API를 제공하며 해당 API들을 통해 점, 선, 삼각형, 사각형, 빛 등을 화면에 그릴 수 있다. 즉, OpenGL은 화면에 뭔가 그릴 수 있도록 도와주는 API들로 이루어진 라이브러리다.
비슷한 API로 Windows에는 DirectX가 있다. 차이점은 OpenGL은 크로스 플랫폼을 지원한다.
OpenGL ES가 화면에 Object를 그리는 방법
기본 개념
1. Vertex (정점)
대표적으로는 Position을 나타낸다. 2D는 (x, y), 3D는 (x, y, z) 정보를 가진다. 그 외에 색상 정보 등을 가지고 있다. Color는 RGBA(색의 3원 색인 Red, Green, Blue와 명암을 나타내는 Alpha 값)로 나타낸다.
2. Polygon (다각형)
Vertex 두 개를 연결하면 선이다. 세 개를 연결하면 삼각형이 된다. 이렇게 Vertex를 연결해서 만든 면을 Polygon이라고 한다. Polygon은 3D 그래픽에서 물체를 표현할 때 쓰이는 기본 단위인 다각형이다. OpenGL에서 Polygon의 최소 단위는 삼각형(triangle)이다. 사각형은 두 개의 삼각형을 연결해서 표현한다.
3. Shader
Vertex 정보를 바탕으로 GPU가 실제로 화면에 그릴 수 있도록 처리하는 프로그램이다. 대표적으로 두 가지 프로그램이 있다.
Vertex Shader (정점 셰이더)
Vertex 정보를 2D 또는 3D 공간에 배치하는 작업을 한다. 각 정점의 최종 위치를 생성하며 정점마다 한 번씩 실행한다. OpenGL은 정점 집합을 취해 점, 선 및 삼각형으로 만든다.
Fragment Shader (프레그먼트 셰이더)
점, 선 또는 삼각형의 각 프레그먼트 최종 색상을 생성하며 프레그먼트마다 한 번 실행된다. 프레그먼트는 픽셀과 유사한 단일 색상의 작고 직사각형인 영역이다.
Fragment Shader의 주목적은 GPU에게 최종적인 프레그먼트의 색이 무엇이 되어야 하는지 알려주는 것이다. 기본 요소의 모든 프레그먼트에 대해 한 번씩 호출되므로 삼각형이 1000개의 프레그먼트로 매핑되면 Fragment Shader는 1000번 호출된다.
4. Rasterization
Vertex Shader를 통해 변환된 데이터를 Fragment Shader에서 처리 가능한 정보로 바꿔주는 과정을 Rasterization이라고 한다. 이런 처리를 하는 것을 Rasterizer라고 한다.
GL_LINE_LOOP : 정점 배열을 순서대로 이어 선을 그리고 첫 번째와 마지막 정점도 이어서 그린다.
GL_TRIANGLES : 정점 3개를 이어서 삼각형을 그린다. 2개의 삼각형을 그리려면 6개의 정점이 필요하다.
GL_TRIANGLE_STRIP : 첫 삼각형을 그릴 때는 정점 3개를 이어서 삼각형을 그리고, 다음 삼각형부터 하나의 추가 정점만 필요하다. 이전 정점 두 개를 이어서 그리기 때문이다. ex) (v0, v1, v2), (v1, v2, v3), (v2, v3, v4), (v3, v4, v5)
GL_TRIANGLE_FAN : 첫 삼각형 시작 정점을 기준으로 이전 삼각형의 마지막 정점과 추가 정점을 이용하여 삼각형을 그린다. 첫 번째 삼각형을 그릴 때는 (v0, v1, v2), 두 번째는 (v0, v2, v3), 세 번째는 (v0, v3, v4)의 순으로 반복하여 그린다. 마지막은 (v0, v4, v5)이다.
Projection과 View 설정을 마치면 다음과 같이 안드로이드 가로 화면에서도 도형의 비율이 유지되는 것을 확인할 수 있다.
up vector가 (0,1,0)이면 y축 방향으로 카메라의 위쪽이 위를 향하여 위와 같은 모습이 된다.
참고로 up vector 설정을 통해 카메라의 위쪽 방향을 아래로 변경한 모습은 다음과 같다. 즉, up vector가 (0,-1,0)이다.
사각뿔(3D 도형) 그리기
삼각형을 그리는 방법을 응용하여 입체감이 있는 3D 도형인 사각뿔을 그릴 수 있다.
사각뿔을 그리기 위한 좌표를 다음과 같다.
static float triangleCoords[] = { //넣는 순서는 반시계 방향입니다.
//front
0.0f, 0.5f, 0.0f, // 상단 vertex
-0.5f, -0.5f, 0.5f, // 왼쪽 아래 vertex
0.5f, -0.5f, 0.5f, // 오른쪽 아래 vertex
//right
0.0f, 0.5f, 0.0f, // 상단 vertex
0.5f, -0.5f, 0.5f, // 왼쪽 아래 vertex
0.5f, -0.5f, -0.5f, // 오른쪽 아래 vertex
//back
0.0f, 0.5f, 0.0f, // 상단 vertex
0.5f, -0.5f, -0.5f, // 왼쪽 아래 vertex
-0.5f, -0.5f, -0.5f, // 오른쪽 아래 vertex
//left
0.0f, 0.5f, 0.0f, // 상단 vertex
-0.5f, -0.5f, -0.5f, // 왼쪽 아래 vertex
-0.5f, -0.5f, 0.5f // 오른쪽 아래 vertex
};
삼각형을 그릴 때 각 점을 넣는 순서가 반시계 방향인 것은 동일하다. 주의할 점은 외부(바깥쪽)에서 바라보는 시점으로 반시계 방향이다. 정면이 아니다.
앞선 좌표 정보를 그림으로 나타내면 다음과 같다.
최초 좌표는 전면 삼각형이다. 다음 삼각형의 좌표는 우측 삼각형의 좌표이다. 다시 한번 말하지만 이때 반시계 기준은 View가 Model을 외부에서 바라볼 때이다. 그다음은 뒷면 삼각형이고 이때도 외부에서 Model을 바라보는 기준으로 좌표 순서를 정해야 한다. 마지막은 좌측 삼각형이 된다.
여기까지 진행한 후 실행하면 위와 같은 화면이 나타난다. 사각뿔이 아닌데?
3D의 형태를 눈으로 확인하기 위해서는 View Matrix도 아래와 같이 변경해야 한다.