대메뉴 바로가기 본문 바로가기

데이터 기술 자료

데이터 기술 자료 상세보기
제목 라즈베리 파이와 OpenGL ES 1.x 프로그래밍
등록일 조회수 7074
첨부파일  

오픈 하드웨어의 그래픽 탐구

라즈베리 파이와 OpenGL ES 1.x 프로그래밍



지난 시간에는 라즈베리 파이에서 OpenGL ES를 출력하기 위한 비디오코어(VideoCore) API와 EGL 그리고 간단한 OpenGL ES의 명령어를 살펴봤다. OpenGL ES는 3.x 버전까지 개발됐지만 1.x와 2.0과 호환되지 않는다. OpenGL ES 1.1은 2.0에 비해 수학적 계산이 적어 배우기 쉽지만 2.0에 비해서는 기능이 제한적이다. 오픈 하드웨어의 OpenGL ES의 그래픽 탐구 두 번째 시간에서는 OpenGL ES 1.1를 살펴본다.



3차원 컴퓨터 그래픽 기술에는 OpenGL과 다이렉트3D(Direct 3D)가 있다. 다이렉트3D는 마이크로소프트(이하 MS) 윈도우 환경을 위한 3D 그래픽 API로, OpenGL보다 사용이 편해 2000년 중반까지 많은 게임에서 다이렉트3D를 도입했다. 그러나 2008년 아이폰 출시를 기점으로 모바일 시대가 본격화되면서 OpenGL이 3D 그래픽의 주류로 자리매김했다.

● OpenGL과 OpenGL ES
OpenGL은 수퍼컴퓨터와 3D로 유명한 실리콘그래픽스(Silicon Graphics Inc)에서 만든 워크스테이션용 IrisGL을 1992년 7월 오픈소스로 개방한 2D 및 3D 그래픽 처리를 위한 표준 그래픽 라이브러리다. OpenGL 1.0은 약 250여 개의 API를 제공하는데, 단순한 기하도형에서부터 복잡한 3차원 이미지를 생성할 수 있다. OpenGL은 거의 모든 운영체제(이하 OS)에서 지원되고, 이식성이 뛰어나 한 번 만든 코드는 다른 플랫폼에서도 별다른 변경 없이 사용할 수 있다. 현재 OpenGL은 크로노스그룹(Khronos Group)에 의해 관리되고 있으며, 가장 최신 버전은 4.x다.

OpenGL이 PC에서 널리 사용되기 시작한 것은 존 카멕(John Carmack)이 OpenGL로 2D와 3D를 결합한 툼(DOOM)과 완전한 3D 게임인 퀘이크(Quake)를 개발하면서부터다. 퀘이크가 등장하기 이전까지만 해도 OpenGL로 3D 게임을 개발한다는 것이 불가능한 일로 여겨졌다. 그러나 존 카멕은 OpenGL에서 게임을 위한 API만 별도로 라이브러리화해 게임을 제작하며 이러힌 인식을 바꿔버렸다. 존 카맥이 자신이 만든 게임의 소스 코드를 공개한 덕분에 OpenGL이 빠르게 확산될 수 있었다. 그 후 존 카맥은 2014년 페이스북이 인수한 오큘러스VR에서 최고기술책임자(CTO)직을 맡고 있다. OpenGL은 다이렉트3D의 성능 문제가 불거진 틈을 타 PC 시장에서도 각광받기 시작했다. 2000년대 들어서는 다양한 임베디드와 모바일 기기로에까지 쓰이기 시작했다. OpenGL은 PC를 타겟으로 한 만큼 임베디드에 쓰기에 너무 무거웠기에 임베디드에 맞게 수정한 OpenGL ES(GLES, OpenGL for Embedded System)가 등장하게 됐다.





● OpenGL ES 1.1과 OpenGL ES 2.0
2003년 7월 28일 OpenGL ES 1.0이 발표됐다. OpenGL 1.3에 기반을 뒀었는데, OpenGL ES 1.1에 이르러 OpenGL 1.5 기반으로 변경됐다. OpenGL 1.x는 2차원 텍스처만 제공한다. GLfloat나 GLdouble와 같은 중복된 자료형과 관련 함수도 빠졌다. glBegin()이나 glEnd()와 같은 폴리곤을 그리는 API는 제공하지 않는다. 대신 버텍스 배열을 이용해 삼각형 위주로 그리는 방식으로 메모리 사용량을 줄이면서 처리 성능을 높였다.

2007년 3월에는 OpenGL ES 2.0이 발표됐다. OpenGL 2.0 기반의 이 라이브러리는 GLSL(OpenGL Shading Language)라는 새로운 쉐이딩 언어를 지원해 보다 동적인 3차원 그래픽 처리가 가능했지만, OpenGL ES 1.x와는 호환되지 않았다. 쉐이딩 언어는 C 언어나 어셈블리와 같은 저수준 언어로, CPU가 아닌 GPU에서 동적으로 컴파일되고 실행 가능하다(HLSL: High Level Shading Language).

OpenGL ES 2.0은 기존 OpenGL ES 1.x가 고정된 파이프라인(Pipeline)를 가진 것과 달리 GLSL을 이용해 동적 파이프라인을 처리할 수 있다. CPU는 논리 연산을 위한 프로세서지만 그래픽과 같은 2차원 공간을 처리하는 데에는 적합하지는 않다. 반면 GPU는 2차원이나 3차원 공간에 최적화된 병렬 구조의 부동소수점을 빠르게 처리할 수 있다. 게다가 GPU에서 OpenGL 하드웨어 가속 기능을 지원할 경우 더욱 빠르게 처리할 수 있다. 2012년 8월 OpenGL 4.3을 기반의 OpenGL ES 3.0이, 2014년 3월에는 OpenGL 4.5를 기반으로 OpenGL ES 3.1이 공개됐다. OpenGL ES 3.x는 OpenGL 2.0과 하위 호환이 가능하고, 안드로이드 4.3과 iOS7에서 사용할 수 있다.



OpenGL ES 1.x의 모델링

OpenGL ES 1.x는 간단한 API를 통해 3D 그래픽 모델링이 가능하다. 2D 공간에서의 드로잉과 관련된 코드는 지난 시간에 이미 살펴본 만큼 이번 시간에는 투영(Projection), 변환 등 기본 개념 소개에 집중하겠다.

● OpenGL의 모델링과 투영
OpenGL에서의 3차원 입체 모형들은 각각의 점과 면으로 구성된다. OpenGL에서는 이러한 점을 버택스(Vertex)라고, 면은 프레그먼트(Gragment)라고 부른다. 정육면체를 예로 들면 8개의 점이 필요한데, 점 사이의 거리는 일정하다. 2개의 점을 이어 12개의 선을 그리고, 4개의 점과 4개의 선을 채우는 6개의 면의 면적은 같다. 만약 정육면체 주변에 조명이 있으면, 빛에 따라 밝은 면과 그림자가 생길 것이다. OpenGL은 이를 컴퓨터 내부에서 입체적으로 그릴 수 있는데, 버텍스와 프레그먼트를 통해 도형을 표현한다. 3차원 도형은 버텍스에 의해 위치와 크기, 모양이 결정되고 빛에 영향을 받는 색상은 프래그먼트로 표현한다. 모니터와 프린터와 같은 출력장치는 2차원만을 표현할 수 있다. 최근 3D 프린터나 증강현실과 같은 기술이 등장했으나 여전히 일반적인 모니터는 3차원을 2차원으로 변환하는 과정이 필요하다. 이러한 변환을 이해하기 위해서는 OpenGL의 파이프라인에 대해 알아야 한다. OpenGL은 변환, 절단, 투영 등의 과정을 통해 3차원을 래스터화해 사용자 모니터에 표시한다. 3차원을 2차원 공간으로 변환할 때 필요한 기법이 ‘투영’이다. 투영은 입체를 사용자에게 보이는 방법을 정의하는 것으로, 이것에 의해 3차원 공간이 2차원으로 어떻게 변환할지를 결정하게 된다. 투영에는 2차원으로 그릴 때 모두 같은 크기로 그리는 직교(Orthogonality)와 사용자가 보는 거리에 따라 가까우면 작게, 멀면 크게 표현하는 원근법(Perspective) 이 두 가지 방법이 있다.

● OpenGL의 API와 좌표계 설정
이전 연재에서 삼각형의 좌우 대칭이 맞지 않았는데, 이러한 문제도 투영과 좌표계 범위를 추가하는 것으로 해결할 수 있다.



<리스트 1> 좌표계 추가 /*~ 중간 생략 ~ */ /* 색상 버퍼 비트(GL_COLOR_BUFFER_BIT) 지우기 */ glClear(GL_COLOR_BUFFER_BIT); /* 직교 투영으로 좌표계의 범위를 설정한다. */ glOrthof(-1.778f, 1.778f, -1.0f, 1.0f, -1.0f, 1.0f); /* 현재 윈도우에 OpenGL의 표시를 위한 영역의 설정 */ glViewport(0, 0, screenWidth, screenHeight); /* 출력될 도형을 위한 좌표 설정 */ GLfloat points[] = { -0.5, -0.5, 0.0, /* 좌측 아래 */ 0.5, -0.5, 0.0, /* 우측 아래 */ 0.0, 0.5, 0.0, }; /* 중앙 위쪽 */ /*~ 중간 생략 ~ */



OpenGL의 명령어는 <라이브러리 접두어><루트 명령어><매개변수 수><인자 타입>과 같은 형식을 가지고 있다. 라이브러리 접두어로는 gl을 사용한다. 다음의 명령어에서 [] 안의 문자들은 선택적이라는 뜻이다. 인수의 형태나 개수는 함수에 따라 가변적으로 달라진다. 때문에 함수는 접미 부분을 빼고 <라이브러리 접두어>와 <루트 명령어> 중심으로 사용한다.

glXXXX[2,3,4][s,i,f,d][v](x,y,z,w);

<매개변수 수>를 의미하는 접미어는 2, 3, 4 총 세 가지 값을 가진다. 원친적으로 2차원 평면공간에서는 z축을 생략한 x, y 좌표만 사용할 수 있다. 3차원 좌표는 x, y, z로 표현하지만 분수 표현을 위해 w(분모)를 사용할 수도 있다. w가 생략되면 1로, z를 생략하면 0으로 간주한다. <인자 타입>을 명시하는 접미어는 s, l, f, d 총 네 가지로, 각각 GLshort, GLiant, GLfloat, GLdouble를 의미한다. 색상이나 위치는 일반적으로 0.0~1.0의 실수값이므로 GLfloat를 많이 사용한다. 만약 소수점 이하 자리가 필요 없으면 GLint 타입을, 더 높은 절밀도가 필요하다면 GLdouble 타입을 사용하면 된다. 마지막의 v(vector)는 구성하는 값들을 배열로 전달하면 된다.

예컨대 앞서 소개한 glColor4f() 함수의 경우 <라이브러리 접두어>인 gl은 OpenGL의 함수라는 의미며, <루트 명령어>인 Color은 색상과 관련된 명령어다. 또한 <매개변수 수>인 4는 이 함수에서 4개의 인자를, <인자의 타입>인 f는 인자의 형태로 float 타입을 사용한다는 의미다. OpenGL에서 2차원 공간에 있는 객체는 거리감이 없기 때문에 일반적으로 직교 투영을 사용하는데, glOrtho( ) 함수는 다음과 같은 인자를 갖는다.

glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

직교 투영을 위한 glOrtho 함수의 맨 앞의 인자 2개는 x축의 왼쪽과 오른쪽을 의미한다. 세 번째와 네 번째 인자는 y축에서의 위쪽과 아래쪽을, 다섯 번째와 여섯 번째 인자는 z축에서의 앞쪽과 뒤쪽을 뜻한다.



OpenGL의 기본 좌표계는 -1.0에서 1.0 사이의 값을 가진다. glOrtho() 함수를 통해 이러한 좌표계의 범위를 지정할 수 있다. 일반적으로 스마트TV의 화면비는 16:9이므로 x축의 좌표를 1.7777…로 변경하면 삼각형의 가로 세로 비율을 1:1로 설정할 수 있다. 앞선 예제 코드를 실행하면 <그림 4>처럼 중앙에 정삼각형이 출력된다.



glViewport() 함수로는 현재 윈도우에서 보여질 영역을 정의할 수 있다. 즉 현재 윈도우에서 OpenGL이 사용할 공간을 설정할 수 있는 것이다.

glViewport (GLint x, GLint y, GLsizei width, GLsizei height);

glViewport()의 x, y는 뷰포트의 왼쪽 아래 좌표이며, width, height는 폭과 높이를 의미한다. 일반적인 그래프와 달리 OpenGL은 왼쪽 아래점을 y축의 기준점으로 삼는다. 앞서 정삼각형을 출력한 코드를 <리스트 2>와 같이 수정해 보자.



<리스트 2> glViewport() 함수 추가 /*~ 중간 생략 ~ */ /* 직교 투영으로 좌표계의 범위를 설정한다. */ glOrthof(-1.778f, 1.778f, -1.0f, 1.0f, -1.0f, 1.0f); /* 현재 윈도우에 OpenGL의 표시를 위한 영역의 설정 */ glViewport(0, 0, screenWidth/2, screenHeight/2); /* 출력될 도형을 위한 좌표 설정 */ GLfloat points[] = { -0.5, -0.5, 0.0, /* 좌측 아래 */ /*~ 중간 생략 ~ */



<리스트 2>를 빌드하면 OpenGL이 화면의 1/4 지역만 사용하는 것을 확인할 수 있다.





OpenGL ES 1.1을 이용한 3차원 애니메이션

지금까지 배운 내용을 바탕으로 색상을 추가해 3차원 객체를 그려보고, 이를 변환해 애니메이션을 제작해 보자. 3차원 객체는 2차원에 비해 버텍스 수가 더 많고 많은 공간을 생각해야 하므로 좀 더 복잡하다. 이전 연제에서 작성한 코드를 <리스트 3>처럼 수정하자.



<리스트 3> 3차원 객체 그리기 /*~ 중간 생략 ~ */ /* OpenGL에서 glClear( ) 함수로 버퍼를 지울때의 색상을 설정 */ glClearColor(0.15f, 0.25f, 0.35f, 1.0f); /* 색상 버퍼 비트와 깊이(Depth) 버퍼 비트 지우기 */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 현재의 매트릭스 모드를 GL_PROJECTION로 설정 */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* 직교 투영으로 좌표계의 범위를 설정한다. */ glOrthof(-1.778f, 1.778f, -1.0f, 1.0f, -10.0f, 10.0f); /* 현재 윈도우에 OpenGL의 표시를 위한 영역의 설정 */ glViewport(0, 0, GScreenWidth, GScreenHeight); glEnable(GL_DEPTH_TEST); /* 현재의 매트릭스 모드를 GL_MODELVIEW로 설정 */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* 출력될 도형을 위한 좌표 설정 */ GLfloat points[] = { -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 }; /* 앞우하 */ /* 12개의 삼각형을 위한 정점의 배열 인덱스 */ GLubyte indices[] = { 0,1,2, 0,2,3, /* 뒤면 */ 4,6,5, 4,7,6, /* 앞면 */ 0,4,5, 0,5,1, /* 좌면 */ 1,5,6, 1,6,2, /* 윗면 */ 2,6,7, 2,7,3, /* 우면 */ 3,7,4, 3,4,0 }; /* 하면 */ /* 정점 배열 사용을 설정 */ glEnableClientState(GL_VERTEX_ARRAY); /* 그래픽 출력을 위한 정점 배열 사용에 대한 설정 */ glVertexPointer(3, GL_FLOAT, 0, points); /* 삼각형 12개를 드로잉(6*2) : 처리할 정점의 수 : 36개 */ glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices); /* 그래픽 출력을 하고 나서 정점 배열 사용에 대한 설정 해제 */ glDisableClientState(GL_VERTEX_ARRAY); eglSwapBuffers(gDisplay, gSurface); /* OpenGL ES의 내용을 EGL로 출력 */ /*~ 중간 생략 ~ */



3차원 공간은 2차원과 달리 깊이를 가지고 있다. OpenGL로 3차원 공간을 표현하려면 버퍼 영역을 glClear() 함수로 지우고 glEnable() 함수에 GL_DEPTH_TEST를 설정해 OpenGL이 입체 모형을 그릴 수 있게 설정해야 한다.

● OpenGL과 행렬(Matrix)
OpenGL은 상태 머신(State Machine)로 현재 상태를 배열에 저장한다. 배열을 이용하면 다음에 이동할 좌표를 계산할 수 있는데, OpenGL에서는 4x4 행렬을 이용한다.



예컨대 4x4 행렬은 x’=M·x로 표현할 수 있는데, M의 값에 따라 좌표계를 바꿀 수 있다. 기존의 값을 2개 키우려면 x’=2·x로 계산하면 되고, 여기에 x축으로 2만큼 이동하고 싶다면 x’2=2·x+2를 하면 된다. OpenGL에서 함수를 수행하면 해당 행렬에 연산을 수행하고 다음에 수행되는 함수들은 현재 저장된 행렬을 바탕으로 계산이 누적돼 수행된다. OpenGL은 기본 좌표계뿐 아니라 앞서 사용한 투영 좌표계도 변화시키기 위해 행렬은 이용한다. OpenGL에서 현재 사용하는 행렬을 설정하려면 glMatrix Mode() 함수를 사용해 <표 1>의 행렬 모드를 값으로 설정하면 된다. 행렬에서 대각선으로 모두 1인 행렬을 단위행렬이라고 부른다. glLoadIdentity() 함수를 사용해 현재 행렬을 단위행렬로 초기화할 수 있다.



● 3차원 좌표와 OpenGL ES의 입체 표시
OpenGL 좌표계는 -1.0~1.0 사이의 실수값을 가지므로 영역 안에서 표시될 수 있도록 -0.5와 0.5 사이의 값을 이용했다. OpenGL ES는 삼각형을 이용해 도형을 표시하는데 2개의 삼각형을 이용하면 사각형을 그릴 수 있다.





사각형을 그릴 때에는 4개의 버텍스가 필요하다. GL-TRIAN GLES 옵션을 사용하면 일반 사각형을 그리는 방법과 비슷하게 그릴 수 있다. 앞에서 정의한 버텍스의 좌표계를 직접 이용해 정육면체나 복잡한 입체 모형을 모델링할 때에는 정점의 수가 많으면 많을수록 각 버텍스의 좌표를 정확하게 입력하기 어렵다. 버텍스의 인덱스를 저장하는 인덱스 버퍼를 이용하면 이를 보다 간단하게 처리할 수 있다. 실제 버텍스 좌표를 (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) 4개의 점이 필요하다. 이 4개의 버텍스로 2개의 사각형이 그려질 수 있도록 점들을 (4, 6, 5)와 (4, 7, 6)과 같이 배치하면 된다. 3차원 객체는 앞면과 뒷면을 모두 가지고 있다. 일반적으로 반시계 방향(Counter-Clock-Wise, CCW)이 앞면이다. 반시계 방향이 되도록 버텍스의 인덱스를 배열로 저장하자.

이렇게 만든 인덱스 배열을 이용해 정육면체를 그리기 위해서는 glDrawElements() 함수를 써야 한다. GL_TRIANGLES을 이용해 면을 그리고 총 36개의 점을 이용해 다각형을 그린다. 버텍스의 인덱스는 indices에서 가져오는데, 각 값은 GL_UNSIGNED_BYTE로 돼 있다. 정육면체의 기본 모델은 2차원 삼각형과 같다. glEnableClient State() 함수를 이용해 GL_VERTEX_ARRAY를 사용할 것을 설정하고, 버텍스를 위한 좌표계는 glVertexPointer() 함수를 이용해 설정한다. glDrawElements()로 정육면체를 모델링한 후 glDisableClientState() 함수를 이용해 GL_VERTEX_ARRAY 설정을 해제한다. 다음 eglSwapBuffers() 함수로 화면에 실제로 출력한다.



● OpenGL 변환
<그림 9>처럼 정육면체가 아니라 흰색 사각형이 그려질 것이다. 정육면체의 정면을 보다보니 그런 것인데, 이를 입체적으로 보여지게 하려면 객체를 회전 또는 이동시켜야 한다. OpenGL은 이동, 회전, 크기 변환 총 3개의 변환을 지원한다.



<리스트 4> 매트릭스 모드 변경 /*~ 중간 생략 ~ */ /* 현재의 매트릭스 모드를 GL_MODELVIEW로 설정 */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, 4.0f); glRotatef(45.0f, 1.0f, 1.0f, 1.0f); /* 출력될 도형을 위한 좌표 설정 */ GLfloat points[] = { /*~ 중간 생략 ~ */



이동은 glTranslate() 함수를, 회전은 glRotate() 함수를, 크기 변환은 glScale() 함수를 각각 이용하면 된다. 앞서 설명한 것처럼 OpenGL은 상태머신으로 기존 상태를 저장한다. 일반적으로 그래픽과 달리 OpenGL에서의 변환은 객체 자체를 변화시키는 것이 아니라 좌표계를 바꾼다는 점을 유념하자.



OpenGL에서 변환을 수행하면 GL_MODELVIEW 행렬에 현재 상태를 누럭해서 기록해 놓는데, 원점을 기준으로 위치나 각도를 계산해야 할 경우 glLoadIdentity() 함수를 이용해 초기화할 수 있다. <그림 11>처럼 glTranslate() 함수를 이용해 좌표계의 원점을 z축 뒤로 보내고 glRoate() 함수로 x, y, z축으로 좌표계의 축을 45도 회전시킬 수 있다. 이 좌표계를 이용해 객체를 모델링하면 이전과 달리 정육면체가 비스듬하게 그려져 입체적으로 보인다.



● OpenGL의 색상
면의 색이 흰색이다보니 각각의 면이 구분되지 않는데, <리스트 5>처럼 각 면에 컬러를 추가하자.



<리스트 5> 면에 색상 추가 /*~ 중간 생략 ~ */ 0.5f, 0.5f, 0.5f, 0.5f,-0.5f, 0.5f }; GLfloat colors[] = { /* 삼각형을 위한 색상을 위한 배열 */ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f}; GLubyte indices[] = { /* 12개의 삼각형을 위한 정점의 배열 인덱스 */ 0,1,2, 0,2,3, 4,6,5, 4,7,6, 0,4,5, 0,5,1, 1,5,6, 1,6,2, 2,6,7, 2,7,3, 3,7,4, 3,4,0}; /* 정점 배열 사용을 설정 */ glEnableClientState(GL_VERTEX_ARRAY); /* 색상 배열 사용을 설정 */ glEnableClientState(GL_COLOR_ARRAY); /* 그래픽 출력을 위한 정점 배열 사용에 대한 설정 */ glVertexPointer(3, GL_FLOAT, 0, points); /* 그래픽 출력을 위한 색상 배열 사용에 대한 설정 */ glColorPointer(4, GL_FLOAT, 0, colors); /* 삼각형 12개를 드로잉(6*2) : 처리할 정점의 수 : 36개 */ glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices); /* 그래픽 출력을 하고 나서 색상 배열 사용에 대한 설정 해제 */ glDisableClientState(GL_COLOR_ARRAY); /* 그래픽 출력을 하고 나서 정점 배열 사용에 대한 설정 해제 */ glDisableClientState(GL_VERTEX_ARRAY); /*~ 중간 생략 ~ */



색상 배열을 만들 때에는 정육면체이므로 8개의 버텍스를 R, G, B, A 4개의 값으로 색상을 설정해야 한다. 정점 배열과 마찬가지로 glEnableClientState() 함수에 GL_COLOR_ARRAY 인자를 이용해 색상 배열을 사용함을 알린다. 그리고 glColorPointer()로 색상 배열과 색상 배열에서의 색상 수와 인자의 타입을 설정한다. glDrawElements() 함수로 드로잉을 수행하면 모델링이 완료된다. 색상 버퍼는 사용이 끝나면 glDisableClientState() 함수에 GL_COLOR_ARRAY 인자를 이용해 해제해야 한다.



<리스트 5>처럼 코드를 수정한 다음 실행하면 각 정점의 색상으로 면의 색상이 혼합된 그라디엔트로 색이 표현된다. 만약 한색으로 면을 채우고 싶으면 glShadeModel(GL_FLAT)로 쉐이드 모델을 GL_FLAT으로 설정하면 된다.

● 정육면체의 애니메이션
정육면체를 애니메이션되도록 하려면 기존 코드에 while 문과 sleep() 함수를 추가하고, glRotate()로 객체를 회전시키면 된다(<리스트 6> 참조).



<리스트 6> 정육면체 회전 /*~ 중간 생략 ~ */ 2,6,7, 2,7,3, 3,7,4, 3,4,0}; float angle = 45.0f; while(1) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, 4.0f); glRotatef(angle++, 1.0f, 1.0f, 1.0f); /* 정점 배열 사용을 설정 */ glEnableClientState(GL_VERTEX_ARRAY); /* 색상 배열 사용을 설정 */ glEnableClientState(GL_COLOR_ARRAY); /* 정점 배열 사용에 대한 설정 */ glVertexPointer(3, GL_FLOAT, 0, points); /* 색상 배열 사용에 대한 설정 */ glColorPointer(4, GL_FLOAT, 0, colors); /* 삼각형 12개를 드로잉(6*2) : 처리할 정점의 수 : 36개 */ glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices); /* 색상 배열 설정 해제 */ glDisableClientState(GL_COLOR_ARRAY); /* 정점 배열 설정 해제 */ glDisableClientState(GL_VERTEX_ARRAY); /* OpenGL ES의 내용을 EGL로 출력 */ eglSwapBuffers(gDisplay, gSurface); usleep(100); }; /*~ 중간 생략 ~ */



애니메이션을 위해 기존 버퍼를 glClear() 함수로 지우고 GL_MODELVIEW로 매트릭스 모드를 설정한 다음 단위 행렬을 초기화했다. 다음 회전과 관련된 glRotate( ) 함수를 하는데, 시간에 따라 각도가 바뀌도록 변수를 하나 사용했다.



이전과 동일하게 정육면체를 모델링하고 eglSwapBuffers() 함수로 화면에 정육면체를 출력했다. 애니메이션 속도는 usleep() 함수로 조정할 수 있다. <리스트 7>을 실행하면 정육면체가 빙글빙글 회전할 것이다.



출처 : 마이크로소프트웨어 5월호

제공 : 데이터전문가 지식포털 DBguide.net