※ 본 포스팅은 learnopengl.com을 번역 및 가감한 포스팅이며, learnopengl에서는 번역 작업 참여를 적극 장려하고 있습니다!
아래 링크에서 원문을 확인할 수 있습니다.
Camera
이전에 view matrix를 통해 scene에서 뒤로 translation 했었습니다(사용자의 방향으로). view의 시점을 조작하지는 않았고 object를 반대 방향(z축 음의 방향)으로 translation시켜서 카메라가 뒤로 이동한 것 처럼 표현했습니다.
이번에는 camera를 설정하는 방법을 다룹니다. 3D 장면에서 자유롭게 이동하는 fly style camera를 공부해봅시다. 또 키보드 및 마우스 입력을 처리하고, 이후에 custom camera class도 만들어봅시다.
Camera/View space
camera/view space는 camera이 시점에서 vertex coordinates를 정의하는 것입니다. 여기서 view matrix는 world coordinate를 camera에 상대적인 view coordinate로 transform 합니다. camera를 정의하기 위해서는 world space에서의 위치, camera의 방향, camera의 right vector, up vector가 필요합니다. 우리는 사실 camera의 위치를 원점으로 하고 단위 축으로 구성된 coordinate system을 구성하려고 하고 있는 겁니다.
1. Camera position
camera position을 얻는 것은 world 공간에서 camera의 position vector를 설정하면 됩니다. 저번에는 view matrix를 z축 음의 방향으로 translate했지만 이번에 같은 위치 옮기는 상황에서는 camera가 기준이므로 반대방향입니다.
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
z축 양의 방향이 우리를 향하는 방향이므로 camera를 뒤로 이동하려면 z축 양의 방향으로 이동시켜야합니다.
2. Camera direction
다음으로 camera의 direction vector가 필요합니다. 일단 camera가 원점을 가리키도록 합시다. direction vector를 구하기 위해서는 target인 원점에서 camera의 position vector를 빼면 됩니다. view matrix의 coordinate system에서는 z축이 양수여야하지만, opengl에서 camera가 z축 음의 방향으로 향하고 있었기에 direction vector 부호를 반전해야합니다. 그래서 반대로 target에서 position vector를 빼는 것으로 camera의 z축 양의 방향 vector를 구할 수 있습니다.
glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
이름은 direction vector라고 부르고 있지만 사실은 목표 방향의 반대를 가리키고 있습니다.
3. Right axis
다음으로 camera의 right vector가 필요한데, 이는 양의 x축을 나타냅니다. right vector를 얻으려면 먼저 up vector (0,1,0)를 지정한 후 up vector와 direction vector를 가지고 cross product(외적)을 해서 구합니다. 여기서 up vector는 좌표계에서 위를 향하는 y축 vector입니다. 이제 up vector에 수직인 right vector를 얻어낼 수 있습니다. (외적 순서를 반대로하면 음의 x 방향이겠죠)
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
4. Up axis
지금까지 camera의 local z축 vector(direction vector)와 local x축 vector(right vector)를 얻었으니 이 두개를 순서대로 외적하면 camera의 local up vector를 구할 수 있죠.
(right vector를 구할 때 사용한 up vector와 헷갈리면 안됩니다. right vector를 구할 때 쓴 건 world 좌표계의 up vector이고 방금은 camera의 up vector를 구했습니다)
glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);
이렇게 외적으로 view/camera 공간을 구성하는 모든 vector를 구했습니다. 지금까지 과정은 사실 선형대수에서 Gram-Schmidt process이라는 개념으로 알려져있는 겁니다. 이제 이 camera vector들로 look at matrix라는 것을 만들 수 있습니다.
Look At
서로 수직을 이루는(직교) 3개의 축으로 coordinate space를 정의하고, 이 세 축과 translation matrix를 사용해서 vector를 해당 좌표 공간으로 transform할 수가 있습니다. 이걸 LookAt matrix라고 하는데, camera space를 정의하는 3개의 직교축(R,U,D)과 camera position vector P를 이용해서 look at matrix를 표현하면 다음과 같습니다.
$$LookAt = \left[\begin{array}{cccc} R_x & R_y & R_z & 0 \\ U_x & U_y & U_z & 0 \\ D_x & D_y & D_z & 0 \\ 0 & 0 & 0 & 1 \end{array}\right] * \left[\begin{array}{cccc} 1 & 0 & 0 & -P_x \\ 0 & 1 & 0 & -P_y \\ 0 & 0 & 1 & -P_z \\ 0 & 0 & 0 & 1 \end{array}\right]$$
R은 right, U는 up, D는 direction, P는 position of camera vector를 말합니다. 식의 왼쪽 각 축에 대한 rotation matrix는 원래 세로로 같은 vector이어야하는데 transpose되어서 가로로 축이 나열되어 있습니다(가로로 나열된 변수가 같다는 뜻입니다). 또 오른쪽 translation matrix는 부호가 마이너스이죠. 이는 camera가 이동하는 방향의 반대로 world를 transform해야하기 때문입니다.
look at matrix를 view matrix로 사용하면 world coordinate를 우리의 view space로 변활할 수 있습니다. look at matrix는 모표를 바라보는 matrix인 겁니다.
그래도 GLM에서 이런 작업들을 처리해니까 다행이죠. 우리가 할 것은 camera position, target position, world space up vector를 지정해주면 됩니다. 그러면 look at matrix를 생성해주고 이걸 view matrix로 사용하면 됩니다.
glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
gl::lookAt 함수는 position, target, up vector를 넣으면 됩니다. 이렇게 look at을 사용해서 이전에 만든 view matrix와 동일한 matrix를 만든 거에요.
이번에는 카메라를 scene 주의로 회전시켜봅시다. target을 (0,0,0)에 고정시키고 삼각함수로 매 프레임마다 동그랗게 회전하도록 카메라 위치를 업데이트합니다. 이때 삼각함수로 x,z 값을 시간에 따라 계산해서 넣으면 카메라가 실시간으로 회전합니다. 원의 반지름을 정해서 반영하고 glfwGetTime 함수를 사용해서 프레임마다 view matrix를 새로 만들면 됩니다.
const float radius = 10.0f;
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
결과는 다음과 같아요.
카메라가 시간에 따라 공간의 중심을 회전하네요. look at matrix의 동작이 좀 감이 잡히셨나요? 코드에서 값들을 바꿔가면서 테스트해보세요.
'개발 · 컴퓨터공학 > LearnOpenGL' 카테고리의 다른 글
OpenGL Camera Euler Angle 카메라 오일러각 [Learn OpenGL 쉬운 번역] (6) | 2024.09.04 |
---|---|
OpenGL Camera Movement 카메라 이동 [Learn OpenGL 쉬운 번역] (8) | 2024.09.03 |
OpenGL Coordinate Systems 코드 구현 cube 큐브 그리기 [Learn OpenGL 쉬운 번역] (8) | 2024.09.01 |
OpenGL Coordinate Systems (view, projection) 좌표계 (뷰, 투영) [Learn OpenGL 쉬운 번역] (1) | 2024.08.31 |
OpenGL Transform library GLM 변환 라이브러리 적용 [Learn OpenGL 쉬운 번역] (1) | 2024.08.30 |