카메라의 좌표계인 View Frame은 World Frame의 원점에 일치
-z 방향을 바라봄
z좌표의 -1.0 ~ 1.0 내의 물체 촬영

View Transform: World Frame 전체를 View Frame으로 변환
카메라의 이동 가능
M_view: View Transform 행렬
q_view = M_view q_world
q_world = M_model q_model
M_model: Model Transform 행렬
즉, q_view = M_view M_model q_model
Model Frame의 좌표는 Model Transform과 View Transform을 거쳐 View Frame의 좌표로 변환됨
조건식 추출
아래 네 행렬식을 만족하는 View Transform 행렬을 구해야 함

Viewing Transform은 Affine Transformation의 일종
카메라 세팅 시 Rotation과 Translation은 가능
Sclaing은 불가능
Affine Transformation의 특성 상 Rotation과 Translation은 별도로 계산 가능
World Frame 상의 카메라의 위치를 View Frame 상 원점으로 이동 변환
행렬 분해
View Transform 행렬은 회전/이동 행렬로 분해할 수 있음
카메라 위치
View Plane Normal
View Up Vector
u = v x n
디폴트 세팅 상태의 카메라를 View Transform 변환
View Transform 행렬은 아무런 변화가 없는 단위행렬로 나타남
zx평면 상에서 원점을 기준으로 카메라가 원궤도를 돌게 함
카메라의 y축 좌표는 고정
세팅
View Transform 행렬에 대입
#version 330 core
in vec4 aPos; // vertex position: attribute
in vec4 aColor; // vertex color: attribute
out vec4 vColor; // varying color: varying
uniform mat4 uModel; // model matrix: uniform
uniform mat4 uView; // view matrix: uniform
void main(void) {
gl_Position = uView * uModel * aPos; // transformation
gl_Position.z *= -1.0F; // negation
vColor = aColor;
}
#version 330 core
in vec4 vColor; // varying color: varing
out vec4 FragColor; // fragment color: framebuffer
void main(void) {
FragColor = vColor;
}
glm::mat4 matView = glm::mat4(1.0F);
void updateFunc(void) {
...
// viewing transform
GLfloat radius = 0.1F;
matView[0][0] = cosf(theta); matView[0][2] = sinf(theta);
matView[2][0] = -sinf(theta); matView[2][2] = cosf(theta);
matView[3][2] = -radius;
}
void drawFunc(void) {
...
// matrix settings
GLuint locView = glGetUniformLocation(prog, "uView");
glUniformMatrix4fv(locView, 1, GL_FALSE, glm::value_ptr(matView));
// 이후 피라미드, 큐브 draw
...
}
y축을 기준으로 카메라가 반시계방향으로 회전하는 것을 확인

어떻게 n, v 벡터가 단위 벡터여야 하며 서로 직교하게 만들어야 함
3차원 공간 상에서 어떻게 설정하고 계산해야할 지 문제
서로 직교하는 x,y,z basis vector를 변환 후 u,v,n basis vector의 직교 좌표계로 만들어야 함
u, v, n을 직접 계산하지 않고 직관적인 방법이 필요
이 때 카메라의 윗방향은 다시 계산할거라 대강 결정해도 괜찮음
이렇게 u,v,n 벡터가 직교 좌표계를 이룸
아까의 카메라가 원궤도를 돌게 하는 프로그램
단 u,v,n 벡터를 직접 계산하지 않음
// eye, at, up을 순서대로 전달
void updateFunc(void) {
...
// viewing transform
GLfloat radius = 0.1F;
matView = glm::lookAtRH(
glm::vec3( radius * sinf(theta), 0.0F, radius * cosf(theta) ),
glm::vec3( 0.0F, 0.0F, 0.0F ),
glm::vec3( 0.0F, 1.0F, 0.0F )
);
}
// 코드
std::cout << glm::to_string( matView ) << std::endl;
// 출력 결과 (column-major)
mat4x4(
(0.964142, 0.000000, 0.265388, 0.000000),
(0.000000, 1.000000, -0.000000, 0.000000),
(-0.265388, 0.000000, 0.964142, 0.000000),
(-0.000000, -0.000000, -0.100000, 1.000000)
)
void updateFunc(void) {
...
const GLfloat radius = 0.1F;
glm::vec3 eye( radius * sinf(theta), 0.05F, radius * cosf(theta) );
glm::vec3 at( 0.02F, 0.0F, 0.0F );
glm::vec3 up( 0.0F, 1.0F, 0.0F );
glm::vec3 p = eye;
glm::vec3 n = -glm::normalize(at - eye);
glm::vec3 u = glm::normalize( glm::cross(up, n) );
glm::vec3 v = glm::cross( n, u );
matView[0][0] = u.x; matView[1][0] = u.y; matView[2][0] = u.z; matView[3][0] = -glm::dot(u, p);
matView[0][1] = v.x; matView[1][1] = v.y; matView[2][1] = v.z; matView[3][1] = -glm::dot(v, p);
matView[0][2] = n.x; matView[1][2] = n.y; matView[2][2] = n.z; matView[3][2] = -glm::dot(n, p);
matView[0][3] = 0.0F; matView[1][3] = 0.0F; matView[2][3] = 0.0F; matView[3][3] = 1.0F;
}
살짝 비스듬하게 내려다보며 카메라가 회전하는 것을 확인

2개의 회전 행렬로 구현 가능