WebGL을... 배우면서 글을 쓰다보니 오류도 있고, 소스와 함께 설명을 하니 갈수록 복잡해지는 느낌이 있어, 소스를 떠나 3D에 대한 이야기를 해보려 한다.
용어설명만으로 충분할 거라 생각했지만, 그렇지 않았던 관계로 WebGL을 이용해 모니터에 3D이미지가 뜨는것 까지의 과정을 최대한 쉽게 풀어보겠다. 나름 많은 시간을 들였지만, 아직 안다고 이야기할 정도는 아니다. 잘 아시는 분이 보고 오류가 있다면 코멘트 좀. (굽신)
(그리고 이미지들은 이해를 도울 목적으로 어디서 모두 집어왔다. )
2D와 3D의 차이.
당신이 광고회사 다니는데, 애플에서 아이폰5 지면 광고 디자인요청을 받았다. (와우!)
멋드러지게 보이도록 아이폰5 의 전면 이미지를 쓰기로 했다면 어떤 방법이 있을까?
- 포토샵으로 이쁘게 그리거나,
- 아이폰5 하나 달라고 해서 찰칵! 찍는다.
이렇게 가져갔더니 잡스옹이 맘에 안드신단다. 이번에 MBA처럼 얇은게 핵심이라며, 측면 이미지를 쓰자고 하신다면? 어떻게 해야 할까?
- 그렸다면? 측면이미지를 다시 그려야 한다. 이것도 맘에 안들면? 큰일이다.
- 찍었다면? 아이폰 눕혀놓고 다시 찰칵! 맘에 안드실지 모르니 1mm씩 움직이며 사진을 한 100장 가져간다.
이 어설픈 예시의 핵심은 우리에게 실제 3D물체가 있다면 2D이미지는 원하는 만큼 얼마든지 만들 수 있다는 거다. (동영상도.)
어떤 입체 느낌이 나는 이미지가 필요할때 그 피사체를 그리면 2D이지만 그 피사체를 만들어서 찍으면 3D이다.
3D는 그저 위치만 바꿔가면서 찍기만 하면 얼마든지 이미지를 만들 수 있지만, 2D는 매번 그려내야 한다.
사진촬영 과정정리과 투영의 의미
사진촬영 과정을 다시 보자. 사진촬영 단계를 두단계로 나누어 보자.
피사체와 카메라를 원하는 곳에 위치시키기
피사체는 배경 좋은 곳에, 카메라는 피사체가 잘보이는 곳에 위치한다. 물론 잘보인다는 것은 원하는 형태로 보이는 곳이다. 아래 사진처럼 멋드러진 풍경을 잡을 위치.

원하는 사진이 나오도록 카메라 설정.
위치를 잡았다면 어떻게 찍을 건지를 정해야 한다. 배경을 날릴건지 줌을 땡길건지 등 말이다. 줌을 사용하면 카메라가 피사체에 다가가지 않아도 클로즈업된 촬영이 가능하고, (위치를 바꾸지 않아도 된다. )
셔터를 누르면 렌즈로 들어온 피사체 이미지가 필름에 상이 맺힌다. 이 상이 우리가 원하는 사진이다.

3D 물체 그리기와 투영하기
그럼 사진이야기를 이제 OpenGL의 용어로 바꾸어서 이야기해보자.
모델(model)과 촬영(view) 위치를 정하기
피사체는 모델(model), 촬영위치를 뷰(view)라 하자. 모델을 가상의 공간에 위치시키고, 바라 볼 뷰의 위치를 정한다. 이렇게 위치시킨 모델과 뷰는 위치만 바꾸면 얼마든지 재사용이 가능하다.

투영법(projection) 결정. 랜더링(rendering)
뷰위치에서 모델을 볼려면 일단 뷰포트(viewport)를 정의해야 하는데 카메라의 CCD(필름)을 생각하면 된다. 3차원 공간을 들여다볼 사각형의 창이라 상상하면 정확하다. 뷰 위치에 뷰포트를 위치시키면(찍을 위치에 카메라를 놓면) 준비가 끝났다. 아, 하나를 더 정해야 하는데, 어떻게 찍을 것인가를 정해야 한다.
뷰 위치에서 모델이 뷰포트에 어떻게 맺힐것인가를 정해야 하는데 이를 투영(projection)이라 한다.
투영법은 크게 정사영법과 원근법이 있는데, 우린 '실감'나는 2d를 원하므로 원근법(perspective projection)를 사용하겠다.
원근법의 설정값을 조절하면 카메라의 렌즈를 조인다던가, 줌을 땡기는 등과 같은 효과가 난다. 이제 셔터에 해당하는 렌더링(rendering)를 하면 모든 조건을 만족하는 2d가 만들어지고, 뷰포트를 통해 화면이 보인다. (이미지는 좌측 원근법, 우측 정사영)
![]() | ![]() |
그래서 3D를 만든다는 건...
만약 3D로 움직이는 애니메인션을 만든다면, 이 모든 작업이 매 프레임마다 일어난다. 60fps이면 초당 60번 모델과 뷰의 위치, 광원, 텍스처등을 바꾸어 가면 랜더링이 일어나는 것이다. 모든 3D게임이 이과정으로 매 프레임을 만들면 바로 그래픽카드의 GPU가 이와 관련된 계산을 한다.
3D Max가 이런 작업을 위해 있는 툴이며, OpenGL은 이걸 프로그래밍 할 수 있게 하는 API중 하나다.(DirectX도 같은 종류) OpenGL의 embeded system용이 OpenGL ES인데, WebGL은 OpenGL ES를 브라우저안에서 Javascript로 컨트롤 할 수 있도록 javascript에 바인딩한 놈이다. 태생적으로 95%이상 같다.
그러므로 WebGL은 OpenGL를 모르면 이야기가 되지 않고, 기본적인 3D를 다루는 것에 대한 이해가 없으면 어렵다. 기존 웹개발자들이 Javascript로 모든게 가능함에도 WebGL이 넘사벽으로 보이는 이유가 바로 이거다. 웹개발자들은 그래픽을 프로그램 해본적이 없다는 것. 앞으론 웹개발자도 이쪽을 알아야 한다고 생각하기에...
각 단계별로 조금만 더 설명해보겠다. 대부분의 내용이 OpenGL의 개념 그대로이므로 특별한 언급이 없으면 OpenGL에서도 같은 내용이라고 생각하면 된다. 전반적인 흐름을 설명하려는 글이므로 더 상세한건 관련 자습서들을 참고하자.
3D물체 그리기
WebGL에선 쉐이더(Shader)를 이용해 모델을 만든다. 쉐이더는 전용언어인 쉐이더 랭기지(GLSL)를 이용해 짜는데 형태는 C 언어이며, 브라우저가 해석가능한 랭귀지는 아니다.
GLSL 소스를 WebGL에서 컴파일하면 쉐이더 (WebGL)클래스가 생기며, 이걸 이용해 모델을 만든다.
모델링 변환 (Modeing Transformation)
모델을 만들었으면 어디다 놔야겠지? 우리가 수학책에서 흔히 보던 x, y, z축의 3차원 좌표계. 이 가상의 절대 공간에 모델을 위치시키는데 이를 시계좌표계(eye coordinate)라 한다. 시계좌표계에서 우린 모델을 이동(transition), 회전(rotation), 크기변환(scaling)을 할 수 있다.

뷰 변환 (View Transformation)
바라볼 위치를 정하는데 기본값은 -Z 축을 바라보는 위치이다. +z에 있는건 보이지 않으며, 모델을 -z로 움직여야 보인다. 아니면 뷰를+z로 움직이던가.
모델과 뷰의 변환은 상대적인 감이 있다. 관측점인 뷰입장에선 모델이 움직이든 뷰가 움직이든 동일한 상만 볼 수 있으면 되기때문이다. 별도지정이 의미가 없어 Model-View Transformation이라 하여 한번에 지정한다.
일반적으로 모델에 뷰모델 행렬(view-model Matrix)를 곱하여 좌표를 얻는다.

투영변환 (Projection Transformation)
모델과 뷰의 위치가 정해지면 3D원 모델을 2D평면에 투영하여 투영면에 2차원 좌표(z=0)로 바꿔야 한다. 이때 투영하는 방법을 정해야 하는데, 정사영(orthographic Projection)와 원근법(perspective Proejction)이 있다. 투영방법과 옵션에 따라 적절한 행열(projection matrix) 곱하여 좌표를 얻는다.
원근법(Perspective Projection)
원근법은 아래 그림을 참고하자. 일단 관측점 기준으로 화각 fovy과 거리인 near, far를 정의해서 관측 볼륨(perspective viewing volume)을 정한다. 관측볼륨 밖의 모델은 뷰포트에 투영되지 않는다. 원근법을 적용하면 이런 관측볼륨 안에 있는 피사채의 좌표를 2D좌표로 바꿔 줄 수 있는 행열(Matrix)이 projection matrix가 된다.
이 행열을 만들기 위해선 fovy, near, far, 투영면의 width, height이 필요하다. 정사영은 패스.


WebGL and Canvas
위에서 뷰포트 가 나왔었는데, 원근법으로 투영하고자 하는 투영면을 뷰포트로 이해하면 쉽다. (100% 같은 말은 아니지만) 그리고 이 뷰포트가 곧 HTML의 canvas Element가 된다. canvas의 width, height를 뷰포트의 width, height로 설정하면 1:1이지만 이를 변경하면 확대,축소나 래더박스 형태로 보이게 할 수 도 있다.
![]() | ![]() |
vertex나 fragment등의 설명을 일부러 하지 않았다. 한 겹 더 파고 들어가는건 자습서를 참고하자.











Comments List