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

데이터 기술 자료

데이터 기술 자료 상세보기
제목 오픈 하드웨어의 그래픽 탐구 : OpenGL ES 2.0과 쉐이딩 언어 프로그래밍
등록일 조회수 8444
첨부파일  

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

OpenGL ES 2.0과 쉐이딩 언어 프로그래밍



3회에 걸쳐 진행된 오픈 하드웨어 그래픽 탐구의 마지막 시간에는 OpenGL의 파이프라인과 OpenGL ES 2.0이 지원하는 쉐이더(Shader) 언어, OpenGL ES 2.0에서 3차원 객체를 모델링하고 회전하는 방법을 살펴본다.



OpenGL이나 다이렉트3D로 모델링한 3차원 그래픽을 표시하려면 3D TV나 홀로그램과 같은 3차원 디스플레이 기기나 3D프린터가 필요하다. 이러한 기기 굳이 사용하지 않아도 3차원 모델링을 2차원 데이터로 변환하면 2차원 모니터나 프린터로 출력할 수 있다.



OpenGL과 파이프라인

지난 시간에 다룬 3차원 객체 모델링과 시각화 방법을 다시 되짚어보자. 3차원 객체 모델링은 정점(버텍스)과 각 면(프레그먼트)을 표현하는 일이다. OpenGL로 모델링한 3D 객체를 디스플레이에 출력하려면 모델링과는 정반대 작업을 해야 한다. 먼저 OpenGL로 모델링된 각 점들을 이어 면을 만들고 각 면에 색(픽셀)을 채운다. 색을 채울 때에는 면의 색상, 조명의 위치와 세기, 관찰자의 시점 등을 고려해야 한다. 이러한 변환 과정에는 그래픽 또는 렌더링 파이프라인이 쓰인다. 그러므로 OpenGL로 3차원 그래픽을 표현하기 위해서는 파이프라인에 대해 알아야 한다. 위키피디아는 렌더링을 컴퓨터 프로그램으로 모델 등을 모아둔 장면인 씬(scene)으로부터 영상을 만드는 과정이라고 정의한다. 이에 대해서는 지난 시간에 자세히 다룬 만큼 이 글에서는 생략한다.





● OpenGL ES와 파이프라인
OpenGL ES 1.0/1.1(이하 1.x)과 OpenGL ES 2.0/3.0은 누누이 강조하지만 서로 호환되지 않는다. GPU 기반의 프로그래밍 언어인 쉐이딩 언어와 파이프라인에 차이가 있어서다. OpenGL ES 1.x는 기본적으로 고정된 파이프라인(fixed function pipeline)을 제공한다. 즉 OpenGL ES 명령어로 고정된 기능만 사용 가능하다. 반면 OpenGL ES 2.0/3.0은 프로그래밍 가능한 파이프라인(Pro grammable Pipeline)을 제공한다. 쉐이딩 언어를 통해 파이프라인을 동적으로 자유롭게 조정하는 것이 가능하다.



쉐이딩 언어

쉐이드(Shade)를 직역하면 그늘이나 음영을 넣거나 색조를 천천히 변화시키는 것을 뜻한다. 이를 구현하기 위한 언어가 쉐이딩 언어다. 3차원 그래픽에서 쉐이딩 또는 그림자 처리는 렌더링 과정에서 빛의 각도에 따라 물체 표면의 조도를 변화시키는 기법이다.

● 쉐이딩 언어와 OpenCL(Open Clustering Language)
일반적인 프로그래밍 언어는 CPU(Central Processing Unit)에 의해 빌드되고 실행된다. 반면 쉐이딩 언어는 그래픽 카드의 GPU를 통해 실시간으로 빌드된다. 이것이 GPU가 그래픽 처리 중간에 동적으로 작업을 수행할 수 있게 해준다.



초기 쉐이딩 언어는 OpenGL이나 다이렉트3D와 같은 3D 그래픽 구현에 사용됐다. 그러나 최근에는 GPU가 CPU보다 행렬 처리에 강점이 있어 유전자나 의료 등 다양한 분야에서 활용이 모색됐다. 오늘에 이르러서는 OpenCL이나 쿠다(Compute Unified Device Architecture, CUDA)와 같은 GPGPU(General-Purpose computing on Graphics Processing Units) 기술로까지 발전했다. 쿠다는 엔비디아의 GPU에서만 동작되기에 라즈베리 파이에서는 이용할 수 없다. 개방형 기술인 OpenCL도 라즈베리 파이를 지원하지 않는다. 이에 브로드컴은 라즈베리 파이의 VideoCore IV 기반 GPU를 활용하는 대안을 제공하고 있다.

● 쉐이딩 언어
쉐이딩 언어는 흔히 쉐이더라고도 부른다. GPU의 프로그래밍 가능한 렌더링 파이프라인을 프로그래밍하는 데 쓰인다. OpenGL ES 2.0 이상부터 쉐이딩 언어를 지원하며, 이를 통해 동적인 파이프라인을 생성할 수 있다. OpenGL의 렌더링 과정은 3D 객체의 각 점 구성, 각 점의 배치, 이 점을 이용한 면 구하기 총 세 가지 과정으로 나뉜다.



쉐이딩 언어 또한 각 정점에 대한 버텍스 쉐이더(Vertex Shader), 위치와 관련 있는 지오메트리 쉐이더(Geometry Shader), 화면에 출력된 면의 픽셀 처리를 위한 프래그먼트 쉐이더(Fragment Shader) 총 세 가지로 구분된다. 이 중 버텍스 쉐이더와 프래그먼트 쉐이더가 주로 사용된다.



각각의 쉐이더는 다른 특징을 가지고 있다. 예컨대 책장 넘기는 효과(page folding)를 주고 싶은 경우 종이 이미지가 접히록 각 픽셀의 위치를 계산해야 한다. 이러한 점의 위치를 계산하는 데 버텍스 쉐이더가 쓰인다.



접힌 책장의 면에 그림자나 뒷면이 비치는 효과를 주려면 각 픽셀의 색상값을 계산해야 한다. 이러한 연산은 프래그먼트 쉐이더로 할 수 있다. 쉐이딩 언어는 C 언어와 비슷한데 문법이 비교적 간단하다. 쉐이딩 언어의 주요 예약어를 간단히 살펴보자(<표 1> 참조). 쉐이딩 언어는 OpenGL과 함께 사용된다. 이러한 고급 쉐이딩 언어를 GLSL(OpenGL Shading Language)이라고도 부른다. 쉐이딩 언어는 OpenGL처럼 버텍스를 정의할 수 있도록 실수형의 4×4 행렬이나 2D 벡터 등의 타입을 제공한다. 쉐이딩 언어의 변수는 총 세 가지다. 변하지 않는 값, 쉐이더 외부에서 내부로 전달하기 위한 값, 버텍스 쉐이더나 프래그먼트 쉐이더간의 전달을 위한 값이 그것이다. 때론 쉐이더처럼 값을 공유해야 할 때가 있다. 책장 넘기기처럼 버텍스 위치에 따라 음영 효과를 주는 경우가 여기에 해당한다. 쉐이더도 C 언어처럼 main() 함수를 가지고 있다. 버텍스 쉐이더의 연산 결과는 gl_Position 변수에, 프래그먼트 쉐이더의 연산 결과는 gl_FragColor 변수에 각각 저장한다.





라즈베리 파이와 OpenGL ES 2.0

지금부터는 지난 시간에 OpenGL ES 1.x로 모델링한 정육면체를 OpenGL ES 2.0으로 만들어보자.

● 셰이딩 언어를 이용한 3차원 객체 표시
OpenGL ES 2.0의 쉐이더는 기본적으로 GLSL 문법을 사용한다. <리스트 1>은 버텍스 쉐이더와 프래그먼트 쉐이더는 사용하기 위한 코드다.



<리스트 1> drawopengl2.c #include < stdio.h> #include < unistd.h> #include < math.h> #include < GLES/gl.h> /* OpenGL ES 사용 */ #include < GLES2/gl2.h> #include < EGL/egl.h> /* EGL 사용 */ #include < EGL/eglext.h> #include "bcm_host.h" /* 브로드컴의 VideoCor 사용 */ /* 쉐이더 객체를 생성하고 쉐이더 소스를 로드한 후 쉐이더 컴파일 */ GLuint LoadShader(GLenum type, const char *shaderSrc) { GLuint shaderId; /* 쉐이더의 ID */ GLint compiled; /* 쉐이더 객체의 생성 */ shaderId = glCreateShader(type); if(shaderId == 0) return 0; /* 쉐이더 소스 로드 */ glShaderSource(shaderId, 1, &shaderSrc, NULL); /* 쉐이더 컴파일 */ glCompileShader(shaderId); /* 컴파일 상태 검사 */ glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compiled); if(!compiled) { GLint infoLen = 0; glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &infoLen); if(infoLen > 1) { char* infoLog = malloc(sizeof(char) * infoLen); glGetShaderInfoLog(shaderId, infoLen, NULL, infoLog); free(infoLog); } /* 에러 시 쉐이더 삭제 */ glDeleteShader(shaderId); return 0; } return shaderId; }



쉐이더는 쉐이더 객체를 생성한 다음 소스 코드를 불러오고, 이를 컴파일하면 사용할 수 있다. 쉐이더 컴파일 시 발생할 수 있는 에러 메시지는 glGetShaderiv()나 glGetShaderInfoLog() 함수를 통해 얻을 수 있다. 이제 <리스트 1>에 메인 함수를 추가하자(<리스트 2> 참조). OpenGL ES 2.0 표시에 사용되는 코드는 이전 연재에서 살펴본 라즈베리 파이의 VideoCore 코드, EGL(Embedded System Graphics Library), OpenGL ES 1.x와 비슷하다.



<리스트 2> main 함수 int main(int argc, const char **argv) { /* 해상도 초기값으로 1920x1080 지정 */ uint32_t GScreenWidth = 1920; uint32_t GScreenHeight = 1080; int32_t success = 0; /* EGL 사용을 위한 변수들 */ EGLDisplay GDisplay; EGLSurface GSurface; EGLContext GContext; EGLConfig config; EGLBoolean result; EGLint num_config; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, /* 깊이 버퍼링을 위한 코드 */ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, /* OpenGL ES 2.0 버전 설정 */ EGL_NONE }; /* 정육면체를 위한 8개의 버텍스 정의 */ GLfloat g_vertex_data[] = { -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, }; /* 정육면체의 6개 면(face) 인덱스 설정(방향성) */ static GLubyte front[] = {2, 1, 3, 0}; /* 앞면 */ static GLubyte back[] = {5, 6, 4, 7}; /* 뒷면 */ static GLubyte top[] = {6, 2, 7, 3}; /* 윗면 */ static GLubyte bottom[] = {1, 5, 0 ,4}; /* 바닥면 */ static GLubyte left[] = {3, 0, 7, 4}; /* 왼쪽면 */ static GLubyte right[] = {6, 5, 2, 1}; /* 오른쪽면 */



<리스트 2>의 첫 코드들은 OpenGL ES와 EGL, 브로드컴의 VideoCore를 사용하기 위한 변수들이다. 다음 3차원 정육면체를 모델링하기 위해 버텍스의 위치와 각 면의 인덱스를 배열로 설정했다.



<리스트 3> 버텍스 쉐이더와 프래그먼트 쉐이더 소스 /* 버텍스 쉐이터 코드 */ GLbyte vShaderStr[] = "attribute vec4 vPosition; " "void main() " "{ " " gl_Position = vPosition; " "} "; /* 프래그먼트 쉐이터 코드 */ GLbyte fShaderStr[] = "precision mediump float; " "void main() " "{ " " gl_FragColor = vec4(0.5, 0.5, 0.0, 1.0); " "} ";



이제 쉐이더를 사용하기 위한 코드를 main() 함수에 추가하자. 버텍스 쉐이더와 프래그먼트 쉐이더 코드를 각각 작성하면 된다. 버텍스 쉐이더는 정점의 좌표를 의미한다.

계산된 좌표 위치는 gl_Position 변수에 저장하면 된다. 버텍스 쉐이더에서 사용한 vPosition 변수는 attribute로 설정했는데, 4x4 행렬값을 저장할 수 있다.

이 변수는 glBindAttribLocation() 함수를 이용해 쉐이더 밖에서 값을 설정할 수 있다. 프래그먼트 쉐이더의 경우 면의 픽셀값을 뜻한다.

계산된 픽셀의 색상은 gl_FragColor 변수에 저장하면 되며, 색상의 값은 vec4() 함수로 빨강(R), 녹색(G), 파랑(B), 투명도(A) 값을 입력한다. 이때 빨강과 녹색을 0.5로 설정하면 면은 50%의 노란색으로 채워진다.



<리스트 4> 쉐이더 객체와 프로그램 객체 연결 GLuint vertexShader; GLuint fragmentShader; GLuint programID; GLint linked; bcm_host_init( ); /* 브로드컴의 VideoCore 초기화 */ /* EGL 디스플레이 연결을 위한 객체 획득 */ GDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); /* EGL 디스플레이 연결을 위한 객체 초기화 */ result = eglInitialize(GDisplay, NULL, NULL); /* EGL 프레임버퍼 설정을 위한 객체 획득 */ result = eglChooseConfig(GDisplay, attribute_list, &config, 1, &num_config); /* EGL과 OpenGL ES 연결 */ result = eglBindAPI(EGL_OPENGL_ES_API); /* EGL 렌더링 콘텍스트 생성 */ GContext = eglCreateContext(GDisplay, config, EGL_NO_CONTEXT, context_attributes); /* EGL 윈도우 표면 생성 */ success = graphics_get_display_size(0 /* LCD */, &GScreenWidth, &GScreenHeight); /* 객체를 화면 중앙에 표시 */ dst_rect.x = (GScreenWidth-GScreenHeight) / 2; /* dst_rect.x = 0; */ dst_rect.y = 0; dst_rect.width = GScreenHeight; /* dst_rect.width = GScreenWidth; */ dst_rect.height = GScreenHeight; src_rect.x = 0; src_rect.y = 0; src_rect.width = GScreenWidth < < 16; src_rect.height = GScreenHeight < < 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); dispman_update = vc_dispmanx_update_start(0); dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, 0/*layer*/, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, (DISPMANX_TRANSFORM_T)0/*transform*/); nativewindow.element = dispman_element; nativewindow.width = GScreenWidth; nativewindow.height = GScreenHeight; vc_dispmanx_update_submit_sync(dispman_update); /* 화면 출력을 위한 EGL 윈도우 표면 생성 */ GSurface = eglCreateWindowSurface(GDisplay, config, &nativewindow, NULL); /* 콘덱스트를 표면과 연결 */ result = eglMakeCurrent(GDisplay, GSurface, GSurface, GContext); /* 배경색 설정 */ glClearColor(0.15f, 0.25f, 0.35f, 1.0f); glViewport(0, 0, GScreenWidth, GScreenHeight); /* 뷰포트 설정 */ /* 버텍스 쉐이더와 프래그먼트 쉐이더 로드 */ vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr); fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr); /* 프로그램 객체 생성 */ programID = glCreateProgram(); if(programID == 0) { printf("Error : glCreateProgram "); return 0; } /* 버텍스 쉐이더와 프래그먼트 쉐이더 프로그램 객체와 연결 */ glAttachShader(programID, vertexShader); glAttachShader(programID, fragmentShader); /* 버택스 쉐이더에서 사용하고 있는 vPosition 변수에 인덱스(0) 대입 */ glBindAttribLocation(programID, 0, "vPosition"); /* 프로그램 링크 */ glLinkProgram(programID); /* 링크 상태 검사 */ glGetProgramiv(programID, GL_LINK_STATUS, &linked); /* 프로그램에 연결한 쉐이더 사용 */ glUseProgram(programID);



먼저 브로드컴의 VideoCore를 초기화한다. 다음 화면 출력을 위한 EGL 객체를 설정하고 OpenGL ES를 초기화한다. 앞에서 작성한 쉐이더 언어는 GPU를 통해 컴파일되고 실행된다. 이때 프로그램 객체가 사용된다. 먼저 쉐이더 객체를 생성하고, 쉐이더의 소스 코드를 불러와 쉐이더를 컴파일한다. 이렇게 컴파일된 쉐이더 객체의 ID를 이용하면 이 프로그램 객체와 연결(attach)할 수 있다. 마지막으로 각각 컴파일된 두 쉐이더를 링크하고 프로그램 객체를 사용하면 된다.



쉐이더 설정이 끝나면 OpenGL ES 2.0 코드를 이용해 정육면체를 화면에 표시하자.



<리스트 5> OpenGL ES 2.0 이용한 정육면체 출력 glMatrixMode(GL_PROJECTION); /* OpenGL ES의 모드 투영으로 설정 */ glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 화면 지우기 */ glEnable(GL_DEPTH_TEST); /* 3차원을 위한 GL_DEPTH_TEST 프래그 설정 */ /* OpenGL ES 2.0을 위한 좌표계 설정 : 원근 투영 */ float nearp = 1.0f; float farp = 500.0f; float hht; float hwd; hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI); hwd = hht * (float)GScreenWidth / (float)GScreenHeight; glFrustumf(-hwd, hwd, -hht, hht, nearp, farp);



<리스트 5>의 glFrustum()는 원근 투영에 필요한 함수다. glFrustum() 함수에서 절단 좌표로 사용되는 잘라지는(clipping) 영역은 ‘(left, bottom) - (right, top)’에 의해 결정된다. void glFrustum(GLdouble left /*왼쪽*/, GLdouble right /*오른쪽*/, GLdouble bottom /*아래*/, GLdouble top /*윗쪽*/, GLdouble near /*근거리*/, GLdouble far /*원거리*/); OpenGL ES 2.0은 glOrtho() 함수를 지원하지 않는다. 만약 직교 좌표계를 사용하고 싶으면 버텍스 쉐이더 등의 방법을 통해 설정할 수 있다.



<리스트 6> 정육면체의 면에 색상 채우기 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glVertexAttribPointer( 0, /* 인덱스(Index) */ 3, /* 요소의 수(x, y, z) */ GL_FLOAT, /* 데이터의 형 */ GL_FALSE, /* 정규화 */ 0, /* 간격(stride) */ g_vertex_data /* 버텍스의 좌표를 가지고 있는 배열 */ ); /* 쉐이더의 인덱스 0에 정육면체의 좌표값 설정 */ glEnableVertexAttribArray(0); /* 6개의 면을 다른 색으로 표시 */ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, front); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, back); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, top); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, bottom); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, left); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, right); /* EGL로 화면 표시 */ eglSwapBuffers(GDisplay, GSurface); getchar(); return 0; }



마지막으로 버텍스 좌표를 저장한 배열과 각 면의 버텍스 인덱스를 이용해 직육면체를 모델링하고 화면에 출력한다. <리스트 6>를 빌드하기 위해서는 해당 라이브러리를 링크해야 한다. 실행에 앞서 clear 명령어로 화면을 지운 후 실행한다. <리스트 7>처럼 리눅스에서 && 명령을 중간에 사용하면 앞의 명령 실행에 성공했을 때에만 뒤에 있는 명령이 실행된다.



<리스트 7> 정육면체 출력 pi@raspberrypi ~ $ gcc -c drawopengl2.c -I/opt/vc/include -I /opt/vc/include/interface/vcos/pthreads/ -I/opt/vc/include/interface/vmcs_host/linux pi@raspberrypi ~ $ gcc -o drawopengl2 drawopengl2.o -lGLESv2 -lEGL -lbcm_host -L/opt/vc/lib pi@raspberrypi ~ $ clear && ./ drawopengl2



<리스트 7>을 실행하면 화면 중앙에 노란색 정육면체가 출력된다. 정면만 보이기에 입체인지 구분되지 않는다. OpenGL 1.x의 glRatate() 함수처럼 OpenGL ES 2.0에서는 객체의 회전에 버텍스 쉐이더를 이용하면 된다.



● 쉐이딩 언어를 이용한 정육면체 회전
마지막으로 버텍스 쉐이더를 이용해 정육면체에 입체감을 더해보자. 정육면체를 회전시킨 후 프래그먼트 쉐이더로 면의 색상을 변경하면 된다(<리스트 8> 참조).



<리스트 8> 정육면체 회전 /*~ 중간 생략 ~ */ /* 버텍스 셰이터 코드 */ GLbyte vShaderStr[] = "attribute vec4 vPosition; " "varying vec4 vColor; " "void main() { " "float rad = 0.5; " "mat4 xRotMat = mat4(1.0, 0.0, 0.0, 0.0, " "0.0, cos(rad), -sin(rad), 0.0, " "0.0, sin(rad), cos(rad), 0.0, " "0.0, 0.1, 0.0, 1.0); " "mat4 zRotMat = mat4(cos(rad), -sin(rad), 0.0, 0.0, " "sin(rad), cos(rad), 0.0, 0.0, " "0.0, 0.0, 1.0, 0.0, " "0.0, 0.0, 0.0, 1.0); " "gl_Position = xRotMat * zRotMat * vPosition; " "vColor = 0.5 * (vPosition + vec4(1.0, 1.0, 1.0, 0.0)); " "} "; /* 프래그먼트 셰이터 코드 */ GLbyte fShaderStr[] = "varying vec4 vColor; " "precision mediump float; " "void main() " "{ " "gl_FragColor = vColor; " "} "; /*~ 중간 생략 ~ */



버텍스 쉐이더에서 프래그먼트 쉐이더와 함께 사용할 변수(색상), 즉 vColor 변수는 varying으로 선언했다.



OpenGL은 일반적인 수학과 다르게 열 우선(column major order) 행렬을 사용하기 때문에 행과 열의 순서를 바꿔줘야 한다.



버텍스 쉐이더에서는 x 축과 z 축에 대한 회전값을 sin()과 cos() 함수로 구하고, 기존 위치값과 연산하고, 계산 결과를 gl_Position에 저장한다. 버텍스 쉐이더로 현재 좌표값을 이용해 색상을 계산한다. 저장된 결과는 프래그먼트 쉐이더와 공유되는 vColor에 저장하면 된다. 다음 프래그먼트 쉐이더로는 vColor에서 가져온 색상을 그대로 표시하면 된다. 완성된 코드를 실행하면 x 축과 y 축으로 기울어진 정육면체를 확인할 수 있다.





마치며

3달에 걸쳐 라즈베리 파이에서 OpenGL ES를 사용하는 법에 대해 살펴봤다. 라즈베리 파이는 OpenGL 1.1, 2.0을 모두 지원하지만 OpenGL 1.x와 2.0/3.0은 서로 호환되지 않는다. OpenGL ES 2.0 이상 버전부터는 쉐이딩 언어를 이용해야 하는데, 이 쉐이더 언어를 통해 동적인 파이프라인을 생성할 수 있다. GPU는 CPU보다 그래픽이나 형렬 연산에 있어 많은 이점을 제공한다. 라즈베리 파이는 아직 OpenCL을 지원하지 않지만 브로드컴에서 제공하는 VideoCore IV 매뉴얼을 참고하면 원하는 기능을 구현할 수 있다. 간단하게나마 OpenGL ES에 대해 살펴봤지만, 쉐이딩 언어에 대해서는 더 깊이 학습할 필요가 있다. 오큘러스 리프트, 3D TV, 기어VR이나 마이크로소프트의 홀로렌즈 같은 가상현실, 증강현실 장비와 3D 프린터의 발전하다보면 3D에 대한 수요도 많아질 것이다. 이 글이 보다 많은 개발자들이 3D의 세계에 빠져드는 계기가 되길 바라며 연재를 마친다.



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

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