사전 카메라
개념

카메라

gabury1고친 사람 github-actions[bot]

카메라는 3차원 장면을 화면에 그릴 때 어디서 어느 쪽을 얼마나 넓게 볼지를 정해 줍니다. 컴퓨터 그래픽스의 카메라는 기계가 아니라 몇 개의 값으로 이루어진 가상의 눈입니다. 장면은 손대지 않고 카메라만 옮겨도 화면에 다른 그림이 나옵니다. 컴퓨터 비전에서는 실제 사진기를 수식으로 옮긴 모델도 카메라라고 부릅니다.

쉽고 빠른 이해

카메라는 3차원 장면 가운데 어느 부분을 어느 방향에서 화면에 보여 줄지 정하는 값 묶음입니다. 게임에서 캐릭터 뒤를 따라다니며 장면을 비추는 시점이 카메라입니다.

이게 없으면 장면에는 물체들의 좌표만 있습니다. 그중 무엇을 어디서 볼지 정할 방법이 없습니다. 시점을 바꾸려면 장면의 물체를 전부 손으로 옮겨야 합니다.

어떻게 도나:

  1. 카메라가 선 곳과 향한 쪽을 정합니다
  2. 얼마나 넓게, 얼마나 멀리까지 담을지 정합니다
  3. 두 설정을 행렬 둘로 바꿔 장면의 모든 점에 곱합니다

대가는 담는 범위에서 생깁니다. 넓게 담을수록 물체 하나하나가 작아집니다. 화면 가장자리도 늘어나 보입니다. 아주 가까운 곳부터 아주 먼 곳까지 한꺼번에 담으면 어느 물체가 앞인지 가리는 계산이 흔들립니다.

3차원 장면을 화면에 그릴 때는 늘 카메라를 씁니다. 먼 것을 작게 그릴지, 거리와 상관없이 같은 크기로 그릴지는 용도에 따라 고릅니다. 메뉴와 글자처럼 픽셀 위치로 놓는 그림은 카메라 없이 화면 좌표로 바로 그리기도 합니다.

상세

이 절은 사진기로 한 장을 찍는 순서에서 출발합니다. 거기서 카메라를 이루는 값 두 묶음을 꺼냅니다. 이어서 그 값이 행렬 둘로 바뀌어 장면의 점을 화면으로 옮기는 과정을 따라갑니다.

뒤쪽 소절은 응용 프로그램이 카메라를 움직이는 흔한 방식을 봅니다. 마지막으로 같은 이름을 쓰는 컴퓨터 비전의 카메라가 그래픽스의 카메라와 어떻게 이어지는지 봅니다.

사진 한 장을 찍는 순서

사진을 찍을 때는 먼저 어디에 설지 정합니다. 그다음 어느 쪽을 향할지 정합니다. 마지막으로 렌즈를 당기거나 밀어 얼마나 넓게 담을지 고릅니다.

같은 풍경이라도 선 곳과 렌즈가 바뀌면 전혀 다른 사진이 나옵니다.

가상의 눈

그래픽스의 카메라는 이 순서를 값으로 적어 둔 것입니다. 기계도 물체도 아니어서 장면 안에 그려지지 않습니다. 화면에 무엇이 나올지를 정하는 설정입니다.

카메라가 다루는 장면은 정점들의 모음입니다. 정점은 물체 표면의 꼭짓점 하나이고 3차원 좌표를 가집니다. 정점 셋이 삼각형 하나를 이룹니다. 물체는 이런 삼각형 여럿으로 이루어집니다.

장면의 모든 물체가 함께 쓰는 좌표계를 월드 공간이라고 부릅니다. 바닥의 한 점을 원점으로 정해 둡니다. 모든 물체와 카메라의 위치를 이 좌표계로 적습니다.

카메라를 이루는 두 묶음의 값

카메라의 값은 두 묶음으로 나뉩니다. 첫 묶음은 위치와 방향입니다. 사진기로 치면 선 곳과 향한 쪽입니다. 둘째 묶음은 담는 범위입니다. 사진기로 치면 렌즈입니다.

위치와 방향은 흔히 세 값으로 적습니다.

값 무엇을 정하나 왜 필요한가
위치 월드 공간에서 카메라가 선 점 어디서 보느냐에 따라 가까운 것과 먼 것이 바뀝니다
바라보는 점 카메라가 향하는 곳 위치에서 이 점을 잇는 방향이 시선이 됩니다
위쪽 방향 화면의 위쪽이 월드의 어느 쪽인지 시선만으로는 카메라가 옆으로 기울었는지 알 수 없습니다

위쪽 방향이 따로 있는 까닭은 시선 하나로 회전이 다 정해지지 않기 때문입니다. 같은 곳을 보면서도 고개를 옆으로 갸웃할 수 있습니다. 위쪽 방향이 그 기울기를 정합니다. 대개 월드의 위쪽을 줍니다.

이 셋에는 조심할 경우가 하나 있습니다. 시선이 위쪽 방향과 나란하면 기울기를 정할 수 없습니다. 카메라가 바로 위나 바로 아래를 볼 때 화면이 갑자기 뒤집히거나 계산이 깨지는 까닭이 이것입니다.

위치와 방향을 옮기는 뷰 행렬

이 소절은 카메라를 옮길 때 장면의 좌표가 어떻게 바뀌는지를 봅니다. 물체 한 점은 x = 7 에 그대로 둡니다. 카메라만 x = 5 에서 10 으로 옮기면서 카메라 기준 좌표가 어떻게 바뀌는지 짧은 코드로 따라갑니다.

그래픽 계산은 카메라를 움직이지 않습니다. 대신 장면 전체를 카메라의 반대쪽으로 옮깁니다. 카메라가 오른쪽으로 한 걸음 가는 것과 장면 전체가 왼쪽으로 한 걸음 가는 것은 화면에서 똑같이 보이기 때문입니다.

이렇게 옮기고 나면 카메라가 원점에 서서 정해진 한 방향을 보는 꼴이 됩니다. 이 좌표계를 뷰 공간이라고 부릅니다. 뒤의 계산은 이 꼴 하나만 가정하고 짜면 되므로, 카메라가 어디 있든 같은 식을 씁니다.

좌표를 옮기고 돌리는 계산은 숫자 표 하나로 적을 수 있습니다. 이 표를 행렬이라고 부릅니다. 월드 공간의 좌표를 뷰 공간으로 바꾸는 행렬이 뷰 행렬입니다. 정점마다 이 행렬을 한 번 곱하면 옮기기와 돌리기가 함께 끝납니다.

카메라 값 몇 개만 바꾸면 뷰 행렬이 장면의 모든 정점을 한꺼번에 옮겨 줍니다. 카메라가 없다면 시점을 바꿀 때마다 물체를 하나하나 옮겨야 합니다.

아래 코드는 돌리기를 빼고 옮기기만 봅니다. 월드 좌표에서 카메라 위치를 빼면 카메라 기준 좌표가 됩니다.

JavaScript
const cam = { x: 5, y: 0 };
const toView = (p) => ({ x: p.x - cam.x, y: p.y - cam.y });

toView({ x: 7, y: 2 }); // { x: 2, y: 2 }
cam.x = 10;
toView({ x: 7, y: 2 }); // { x: -3, y: 2 }

물체는 x = 7 에 가만히 있습니다. 카메라가 오른쪽으로 5 만큼 가자 카메라 기준 좌표가 2 에서 -3 으로 바뀌었습니다. 화면에서는 물체가 왼쪽으로 밀려난 것으로 보입니다.

돌리기도 같은 방식입니다. 카메라가 오른쪽으로 고개를 돌리면 장면 전체를 왼쪽으로 같은 각도만큼 돌립니다.

카메라를 원점에 정해진 방향으로 세워 두었다가 월드의 제 위치로 옮기고 제 방향으로 돌리는 변환이 있다고 해 봅시다. 어떤 행렬이 한 일을 그대로 되돌리는 행렬을 그 행렬의 역행렬이라고 합니다. 뷰 행렬은 바로 이 변환의 역행렬입니다.

위치·바라보는 점·위쪽 방향 셋에서 이 행렬을 바로 만드는 함수는 그래픽 라이브러리마다 있습니다. 이 계산을 흔히 룩앳(look-at)이라고 부릅니다.

담는 범위를 정하는 투영 행렬

이 소절은 둘째 묶음을 봅니다. 담는 범위가 어떤 입체를 이루는지 보고, 그 입체를 화면 쪽으로 옮기는 행렬과 두 가지 투영 방식을 봅니다.

원근을 살리는 카메라가 보는 범위는 꼭대기를 잘라 낸 피라미드 모양입니다. 카메라 쪽이 좁고 멀어질수록 넓어집니다. 이 입체를 뷰 절두체라고 부릅니다. 절두체 밖에 있는 물체는 화면에 나오지 않습니다.

피라미드의 모양은 네 값이 정합니다.

값 무엇을 정하나 바꾸면
시야각 위아래로 벌어진 각도 넓히면 더 많이 담기고 물체 하나하나는 작아집니다
종횡비 화면의 가로 대 세로 비율 창 비율과 다르면 물체가 눌리거나 늘어나 보입니다
근평면 카메라에서 이만큼 떨어진 곳부터 그립니다 이보다 가까운 물체는 잘립니다
원평면 카메라에서 이만큼 먼 곳까지 그립니다 이보다 먼 물체는 사라집니다

이 네 값으로 만드는 행렬이 투영 행렬입니다. 뷰 공간의 좌표에 이 행렬을 곱한 결과가 놓이는 좌표계를 클립 공간이라고 부릅니다.

원근을 살리는 카메라는 그다음 점의 가로·세로 값을 카메라에서의 거리로 나눕니다. 먼 점일수록 큰 수로 나뉘어 화면 가운데로 모입니다. 이렇게 하고 나면 절두체 안의 점은 가로와 세로가 -1 부터 1 까지인 작은 상자 안에 들어옵니다.

상자가 정해져 있어서 뒤의 단계는 카메라가 얼마나 넓게 보는지 몰라도 됩니다. 상자 밖으로 나간 부분은 잘라 냅니다. 안에 든 것은 창 크기에 맞춰 늘려 픽셀 위치를 정합니다. 이 마지막 단계를 뷰포트 변환이라고 부릅니다.

투영 방식은 둘입니다. 원근 투영은 앞에서 본 대로 가로·세로 위치를 거리로 나눠서 먼 것을 작게 그립니다. 직교 투영은 이 나눗셈을 하지 않아서 거리와 상관없이 크기가 같습니다.

투영 방식 카메라가 보는 범위 쓰는 예
원근 투영 꼭대기를 잘라 낸 피라미드 3차원 게임 · 건물 둘러보기 · 가상 현실
직교 투영 직육면체 설계 도면 · 2차원 게임 · 화면 위의 메뉴와 버튼

직교 투영 카메라는 시야각 대신 보는 범위인 직육면체의 가로·세로 크기를 값으로 가집니다. 화면 위에 얹는 메뉴와 글자처럼 픽셀 단위로 놓는 그림은 창 크기에 맞춘 직교 투영 카메라로 그리거나, 카메라 없이 화면 좌표로 바로 그립니다.

넓은 시야각과 깊이 범위의 대가

이 소절은 시야각과 거리 범위를 넓히면 무엇이 나빠지는지 하나씩 봅니다.

시야각을 크게 넓히면 화면 가장자리의 물체가 바깥쪽으로 늘어나 보입니다. 넓은 각도를 평평한 화면 하나에 펴서 담기 때문입니다.

어느 물체가 앞인지는 픽셀마다 적어 둔 카메라와의 거리를 견줘 가립니다. 이 거리를 적어 두는 곳을 깊이 버퍼라고 부릅니다. 원근 투영은 이 거리를 가까운 곳은 촘촘하게, 먼 곳은 성기게 적습니다.

그래서 근평면과 원평면 사이를 너무 넓게 잡으면 먼 곳의 두 면이 같은 값으로 적힙니다. 그러면 두 면이 번갈아 비치며 깜박입니다. 이 현상을 Z-파이팅이라고 부릅니다. 근평면을 카메라에서 조금만 멀리 두어도 이 현상이 크게 줄어듭니다.

한 정점이 화면에 닿기까지

이 소절은 앞의 두 행렬이 한 정점이 거치는 변환 가운데 어디에 끼는지를 그림 하나로 봅니다.

물체의 정점은 처음에 물체 자신을 기준으로 적힙니다. 이 좌표계를 모델 공간이라고 부릅니다. 물체를 장면에 놓는 모델 행렬이 이 좌표를 월드 공간으로 옮깁니다. 모델 행렬은 물체마다 따로 있습니다.

카메라가 정하는 것은 그다음 두 단계입니다. 위치와 방향은 뷰 행렬이 됩니다. 담는 범위는 투영 행렬이 됩니다.

flowchart TD
    subgraph 카메라
        P["위치와 방향"]
        R["담는 범위"]
    end
    W["월드 공간의 정점"] --> VM["뷰 행렬"]
    P -.-> VM
    VM --> V["뷰 공간의 정점"]
    V --> PM["투영 행렬"]
    R -.-> PM
    PM --> C["클립 공간의 정점"]

카메라의 두 묶음은 서로 다른 행렬로 들어갑니다. 뷰 행렬과 투영 행렬은 한 장면 안의 모든 정점이 같은 것을 씁니다. 그래서 두 행렬을 미리 곱해 하나로 넘기는 경우가 많습니다.

이 곱셈은 GPU(Graphics Processing Unit, 그래픽 처리 장치)에서 정점마다 도는 작은 프로그램인 정점 셰이더가 맡습니다. 카메라가 움직이면 뷰 행렬을 화면 한 장을 그릴 때마다 다시 만듭니다. 투영 행렬은 창 크기나 시야각이 바뀔 때만 다시 만듭니다.

카메라를 움직이는 흔한 방식

이 소절은 응용 프로그램이 카메라를 다루는 흔한 방식 셋을 봅니다. 셋은 위치·바라보는 점·위쪽 방향 가운데 무엇을 붙잡아 두고 무엇을 움직이느냐로 갈립니다.

방식 붙잡아 두는 값 움직이는 값 쓰는 예
궤도 카메라 바라보는 점 위치가 그 점 둘레를 돕니다 3차원 모델 뷰어 · 설계 프로그램
1인칭 카메라 없음 위치와 시선을 사용자가 직접 움직입니다 1인칭 게임 · 가상 현실
3인칭 카메라 따라갈 대상과의 간격 대상을 따라 위치가 움직입니다 캐릭터 뒤를 따르는 게임

1인칭 카메라는 흔히 시선을 좌우 각도와 위아래 각도 둘로 저장합니다. 이때 위아래 각도가 바로 위나 바로 아래에 닿으면 앞에서 본 문제가 다시 생깁니다. 시선이 위쪽 방향과 나란해지는 문제입니다. 그래서 위아래 각도가 끝까지 가지 않게 막아 둡니다.

화면을 확대하는 방법도 둘입니다. 카메라를 물체 쪽으로 다가가게 하거나, 시야각을 좁히는 것입니다. 둘 다 물체가 커지지만 원근감이 다릅니다.

다가가면 가까운 것과 먼 것의 크기 차이가 커집니다. 시야각을 좁히면 크기 차이는 바뀌지 않습니다. 가운데만 잘라 키운 그림이 됩니다.

영화의 돌리 줌은 이 둘을 반대 방향으로 함께 씁니다. 카메라를 인물 쪽으로 다가가게 하면서 동시에 시야각을 넓힙니다. 다가가서 커질 인물을 넓힌 시야각이 다시 작게 만들어 인물 크기는 그대로 남습니다. 배경만 멀어지는 것처럼 보입니다. 거꾸로 물러나면서 시야각을 좁히면 배경이 다가오는 것처럼 보입니다.

컴퓨터 비전의 카메라

이 소절은 같은 이름을 쓰는 다른 분야를 봅니다. 컴퓨터 비전은 실제 사진기로 찍은 사진에서 장면을 읽어 내는 분야입니다.

컴퓨터 비전도 카메라를 앞과 같은 두 묶음의 값으로 적습니다. 사진기가 선 곳과 향한 쪽을 외부 파라미터라고 부릅니다. 렌즈와 센서가 정하는 담는 범위를 내부 파라미터라고 부릅니다.

두 묶음은 모두 한 가지 단순한 사진기 모델 위에 섭니다. 바늘구멍 하나로 빛이 들어오는 사진기를 본뜬 핀홀 카메라 모델입니다.

두 분야는 방향이 반대입니다. 그래픽스는 값을 정해 두고 그림을 만듭니다. 컴퓨터 비전은 찍힌 사진에서 거꾸로 그 값을 알아냅니다. 실제 사진기의 값을 사진으로 알아내는 일을 카메라 캘리브레이션이라고 부릅니다.

실제 렌즈는 곧은 선을 조금 휘게 찍습니다. 그래서 컴퓨터 비전의 카메라는 이 휨을 적는 값을 더 가집니다. 그래픽스의 카메라에는 이 값이 없어서 곧은 선이 언제나 곧게 그려집니다.

관련 항목

카메라를 이루는 설정값

위쪽 벡터 · 시야각 · 종횡비 · 근평면 · 원평면 · 초점 거리

카메라 값으로 만드는 변환 행렬

뷰 행렬 · 투영 행렬 · 룩앳 행렬 · 모델 행렬 · 변환 행렬 · 역행렬 · 행렬

카메라가 담는 범위를 정하는 투영 방식

원근 투영 · 직교 투영 · 뷰 절두체 · 뷰 볼륨 · 절두체 컬링 · 소실점

정점이 카메라를 거쳐 지나가는 좌표 공간

모델 공간 · 월드 공간 · 뷰 공간 · 클립 공간 · 정규화 장치 좌표 · 뷰포트 · 좌표 변환

담는 범위를 넓힐 때 흔들리는 깊이 계산

깊이 버퍼 · 깊이 정밀도 · 깊이 테스트 · Z-파이팅

카메라를 움직이는 조작 방식

궤도 카메라 · 1인칭 카메라 · 3인칭 카메라 · 돌리 줌

카메라 방향을 담는 회전 표현

오일러 각 · 쿼터니언 · 짐벌 락 · 회전 행렬

카메라 행렬을 받아 쓰는 렌더링 단계

그래픽스 파이프라인 · 정점 셰이더 · 정점 · 래스터화 · GPU · 렌더링

카메라를 장면의 한 요소로 담는 구조와 형식

씬 그래프 · 노드 · glTF · 렌더링 엔진

같은 사진기 모델을 쓰는 컴퓨터 비전 개념

컴퓨터 비전 · 핀홀 카메라 · 외부 파라미터 · 내부 파라미터 · 카메라 캘리브레이션 · 렌즈 왜곡

카메라가 쓰이는 분야와 기법

그래픽스 · 레이 트레이싱 · 3D 재현 · 가상 현실

다른 이름: camera · virtual camera · 가상 카메라