사전 클립 공간
개념

클립 공간

gabury1고친 사람 github-actions[bot]

클립 공간은 3차원 장면을 화면에 옮기다가, 화면 밖으로 나갈 부분을 잘라 내는 단계에서 쓰는 좌표 공간입니다. 이 공간에서는 점을 네 개의 수로 나타냅니다. 앞의 세 수를 넷째 수와 견줘 보이는 범위의 안팎을 가립니다. 잘라 낸 뒤에 넷째 수로 나누면 화면에 찍을 위치가 나옵니다.

쉽고 빠른 이해

클립 공간은 화면에 담을 부분과 버릴 부분을 가르는 단계의 좌표입니다. 3차원 물체는 작은 삼각형을 이어 붙여 나타냅니다. 카메라 옆으로 반쯤 삐져나간 건물이 있으면, 화면 밖으로 나간 반쪽의 삼각형이 여기서 잘려 나갑니다.

이게 없으면 곤란한 일이 둘 생깁니다. 화면 밖의 도형까지 끝까지 계산하게 됩니다. 그리고 카메라 뒤에 있는 물체가 좌우와 위아래가 뒤집힌 채 화면에 나타납니다.

어떻게 도나:

  1. 삼각형의 꼭짓점마다 위치를 네 개의 수로 나타냅니다. 넷째 수에는 카메라에서 떨어진 거리가 담깁니다
  2. 앞의 세 수가 넷째 수로 정한 범위 안에 드는지 봅니다. 경계에 걸친 삼각형은 경계선을 따라 자릅니다
  3. 남은 꼭짓점의 앞 세 수를 넷째 수로 나눠 화면 위치를 얻습니다

3차원 장면을 픽셀로 그릴 때는 언제나 거치는 단계라 쓸지 말지 고를 일은 없습니다. 고르는 것은 멀수록 작게 그릴지, 거리와 상관없이 같은 크기로 그릴지입니다.

대가도 있습니다. 경계에 걸친 삼각형을 자르면 꼭짓점이 새로 생겨서, 삼각형 하나가 여러 개로 늘어납니다. 좌표 값도 아직 나누기 전이라, 숫자만 보고 화면 어디인지 바로 읽기 어렵습니다.

상세

사진을 액자에 넣을 때는 먼저 액자 틀을 사진 위에 대 봅니다. 틀 밖으로 삐져나온 가장자리는 가위로 잘라 냅니다. 틀 안의 부분만 남긴 뒤에야 사진을 액자 크기에 맞춰 끼웁니다.

클립 공간은 3차원 그래픽스에서 틀을 대고 자르는 단계가 일어나는 좌표 공간입니다. 이 절은 점 하나가 이 공간에 들어와 화면 위치로 나가기까지를 차례로 봅니다.

좌표 공간이 이어지는 차례

3차원 물체는 작은 삼각형을 이어 붙여 나타냅니다. 삼각형의 꼭짓점을 그래픽스에서는 정점이라고 부릅니다. 물체를 그리는 일은 정점마다 화면 위치를 계산하는 데서 시작합니다.

같은 점이라도 무엇을 기준으로 재느냐에 따라 좌표 값이 달라집니다. 의자 다리 끝은 의자를 기준으로 재면 늘 같은 좌표입니다. 방을 기준으로 재면 의자를 옮길 때마다 좌표가 바뀝니다. 기준을 하나 정해 둔 좌표의 틀이 좌표 공간입니다.

그래픽스는 점을 한 좌표 공간에서 다음 좌표 공간으로 여러 번 옮겨 가며 화면 위치를 구합니다. 한 번에 옮기지 않는 까닭은 단계마다 하기 쉬운 일이 다르기 때문입니다. 물체끼리 배치하기는 방 기준이 쉽고, 멀고 가까움을 따지기는 카메라 기준이 쉽습니다.

차례는 이렇습니다. 출발점은 모델 좌표계입니다. 물체 자신을 기준으로 잰 좌표라서, 의자 다리 끝처럼 물체를 어디에 두든 값이 바뀌지 않습니다.

물체를 장면 안에 옮기고 돌려 놓으면 월드 좌표계로 넘어갑니다. 장면 전체를 기준으로 잰 좌표입니다. 앞에서 본 방 기준 좌표가 이것입니다.

다음은 카메라를 기준으로 잰 뷰 공간입니다. 카메라를 원점에 두고, 카메라가 바라보는 방향을 한 축으로 삼습니다. 이 축의 값은 점이 카메라에서 얼마나 멀리 있는지, 곧 깊이를 나타냅니다.

뷰 공간의 점에 투영 행렬을 곱하면 클립 공간에 들어옵니다. 투영 행렬은 카메라가 담는 범위를 재기 쉬운 꼴로 바꿔 주는 행렬입니다. 곱한 결과는 x, y, z 에 넷째 수 w 가 붙은 네 개의 수입니다.

이 좌표의 앞 세 수를 w 로 나누면 정규화 장치 좌표가 됩니다. 보이는 범위가 가로 · 세로 모두 -1 부터 1 사이로 모인 좌표입니다. 이것을 화면 크기로 늘리면 픽셀 위치가 됩니다. w 에 무엇이 담기고 왜 나누는지는 아래 소절에서 풉니다.

flowchart TD
    A["모델 좌표계 · 물체 자신 기준"] -->|"옮기고 돌린다"| B["월드 좌표계 · 장면 전체 기준"]
    B -->|"카메라 기준으로 바꾼다"| C["뷰 공간 · 카메라 기준"]
    C -->|"투영 행렬을 곱한다"| D["클립 공간 · 네 성분 좌표"]
    D -->|"w 로 나눈다"| E["정규화 장치 좌표 · -1 부터 1 범위"]
    E -->|"화면 크기로 늘린다"| F["픽셀 위치"]

그림 한가운데의 클립 공간을 경계로 계산을 맡는 쪽이 갈립니다. 앞쪽 계산은 개발자가 작성합니다. 뒤쪽 계산은 GPU(Graphics Processing Unit, 그래픽 처리 장치)가 알아서 합니다. GPU 는 그래픽 계산을 맡는 전용 칩입니다.

정점 셰이더가 내놓는 좌표

앞쪽 계산을 담는 프로그램이 정점 셰이더입니다. GPU 에서 정점마다 한 번씩 도는 작은 프로그램입니다. 그래픽 프로그램을 짜는 개발자가 직접 작성합니다.

정점 셰이더가 반드시 해야 하는 일은 하나입니다. 들어온 정점의 위치를 클립 공간 좌표로 바꿔 내놓는 것입니다. GPU 의 뒤 단계는 이 좌표만 받아서 자르기와 나누기를 이어 갑니다. 클립 공간은 개발자가 작성하는 프로그램과 GPU 가 정해 둔 처리 사이의 약속입니다.

정점 셰이더 뒤에 단계를 더 끼우기도 합니다. 삼각형을 잘게 쪼개는 테셀레이션 평가 셰이더가 그런 단계입니다. 도형을 새로 만들어 내는 지오메트리 셰이더도 있습니다. 이런 단계를 끼우면 그중 마지막 단계가 같은 꼴의 클립 공간 좌표를 내놓습니다.

삼각형을 픽셀로 바꿔 그리는 과정이면 어느 그래픽 라이브러리를 쓰든 이 공간을 거칩니다. 쓸지 말지 고르는 단계가 아닙니다. 개발자가 고르는 것은 이 공간으로 들어오는 투영 방식입니다. 원근 투영과 직교 투영 두 가지를 바로 아래 소절에서 풉니다.

네 성분으로 나타내는 동차 좌표

클립 공간의 점은 (x, y, z, w) 네 개의 수로 나타냅니다. 3차원 점인데 수가 넷인 까닭은 원근 투영 때문입니다.

원근 투영은 멀리 있는 것을 작게 그리는 변환입니다. 점의 가로·세로 위치를 카메라에서 떨어진 거리로 나누면 먼 점일수록 화면 가운데로 모여서 작아 보입니다.

그래픽스는 점을 옮기는 계산을 행렬 곱셈으로 나타냅니다. 행렬 곱셈은 좌표에 정해진 수를 곱해 더하는 계산이라, 점마다 다른 값으로 나누는 일은 담지 못합니다. 그래서 나눌 값을 넷째 성분 w 에 담아 둡니다. 나눗셈은 뒤로 미룹니다.

성분을 하나 늘린 이런 좌표가 동차 좌표입니다. 동차 좌표에는 약속이 하나 붙습니다. 앞의 세 수를 w 로 나눈 값이 진짜 위치라는 약속입니다. (2, 4, 6, 2) 와 (1, 2, 3, 1) 은 나누고 나면 둘 다 (1, 2, 3) 이라 같은 점을 가리킵니다.

뷰 공간의 점을 클립 공간으로 옮기는 행렬이 앞에서 본 투영 행렬입니다. 원근 투영의 투영 행렬은 점의 깊이를 w 칸에 옮겨 담습니다. 클립 공간의 w 는 곧 그 점이 카메라 앞으로 얼마나 떨어져 있는지를 나타냅니다.

먼 것을 줄이지 않는 직교 투영도 있습니다. 설계 도면처럼 거리와 상관없이 크기를 그대로 그리는 투영입니다. 이때는 나눌 필요가 없어서 투영 행렬이 w 를 1 로 둡니다.

보이는 범위를 재는 부등식

카메라가 담는 범위는 꼭대기를 잘라 낸 피라미드 모양입니다. 카메라 쪽이 좁고 먼 쪽이 넓습니다. 이 입체가 뷰 절두체입니다.

뷰 공간에서 점이 이 피라미드 안에 들었는지 따지려면 기울어진 옆면 네 장과 하나하나 견줘야 합니다. 앞뒤를 막는 두 장은 따로 봅니다. 투영 행렬을 곱하고 나면 이 판정이 단순해집니다. 점이 절두체 안에 들었다는 조건이 아래 두 부등식으로 바뀝니다.

-w ≤ x ≤ w
-w ≤ y ≤ w

w 가 0 보다 크면 이 부등식은 x ÷ w 와 y ÷ w 가 -1 부터 1 사이에 든다는 말과 같습니다. w 와 견주기만 하므로 나눗셈 없이 판정이 끝납니다.

아래는 이 판정을 코드로 옮긴 것입니다. 두 점 모두 w 는 2 이고, x 만 다릅니다.

JavaScript
const inside = (x, y, w) =>
  -w <= x && x <= w && -w <= y && y <= w;

inside(1, 0.5, 2);  // true  안에 든다
inside(3, 0.5, 2);  // false 오른쪽 밖

둘째 점은 x 가 3 이라 w 인 2 를 넘습니다. 화면 오른쪽 경계 밖에 있다는 뜻입니다.

깊이 z 도 같은 식으로 견줍니다. 카메라에서 이만큼 떨어진 곳부터 그린다는 앞쪽 경계가 근평면입니다. 이보다 먼 것은 그리지 않는다는 뒤쪽 경계는 원평면입니다. z 가 둘 사이에 드는지를 w 와 견줘 판정합니다.

z 의 범위를 어떻게 잡을지는 그래픽 라이브러리마다 두 가지로 갈립니다. 한쪽은 -w 부터 w 까지로 잡습니다. 다른 쪽은 0 부터 w 까지로 잡습니다. 어느 쪽이든 경계가 w 에 맞춰 정해진다는 점은 같습니다.

이렇게 보이는 범위의 경계는 면 여섯 장이 됩니다. 왼쪽 · 오른쪽 · 아래 · 위 · 근평면 · 원평면입니다. 뷰 공간의 기울어진 면과 달리, 면마다 좌표 하나를 w 와 견주기만 하면 됩니다. w 로 나누고 나면 여섯 장은 축에 나란한 반듯한 상자의 면이 됩니다.

경계에 걸친 삼각형을 자르는 클리핑

경계 밖으로 나간 부분을 잘라 내는 일이 클리핑입니다. 클립 공간이라는 이름도 이 일에서 왔습니다. 클리핑은 점 하나씩이 아니라 도형 하나를 단위로 판정합니다. 3차원 물체는 삼각형으로 나타내므로 아래는 삼각형으로 봅니다.

판정은 세 갈래입니다. 꼭짓점 셋이 모두 범위 안이면 손대지 않고 넘깁니다. 셋이 모두 같은 경계면 밖이면 삼각형을 통째로 버립니다. 그 밖의 경우는 경계에 걸친 것이라 경계면을 따라 자릅니다.

버린 삼각형은 뒤 단계로 가지 않습니다. 화면에 안 나올 삼각형의 픽셀을 뒤 단계가 계산하지 않아도 됩니다.

자를 때는 삼각형의 변이 경계면을 지나는 곳을 구합니다. 경계면이 평평한 면이라, 교점은 변의 두 끝점 사이의 비율 하나만 구하면 나옵니다. 두 끝점의 좌표를 그 비율로 섞은 것이 새 꼭짓점입니다. 두 값 사이를 이렇게 비율로 섞는 계산이 선형 보간입니다.

정점에는 위치 말고도 색 같은 값이 딸려 있습니다. 표면에 입힐 그림에서 어느 점을 가져올지 가리키는 텍스처 좌표도 그런 값입니다. 새 꼭짓점의 이런 값도 같은 비율로 섞어 만듭니다.

삼각형의 한 귀퉁이를 잘라 내면 꼭짓점이 넷인 도형이 남습니다. 여러 경계에 걸치면 꼭짓점이 더 늘어납니다. 뒤 단계는 삼각형을 받으므로, 이 도형을 다시 삼각형 여러 개로 쪼개서 넘깁니다.

카메라 뒤의 점

잘라 내기를 w 로 나누기 전에 하는 데는 까닭이 있습니다. 카메라 뒤에 있는 점 때문입니다.

원근 투영에서 w 는 카메라 앞으로 떨어진 거리입니다. 카메라 앞의 점은 w 가 양수이고, 카메라 뒤의 점은 w 가 음수입니다. 카메라와 같은 깊이에 있는 점은 w 가 0 입니다.

이 점들을 먼저 w 로 나누면 문제가 생깁니다. w 가 음수면 나눈 결과의 부호가 뒤집혀서, 카메라 뒤의 점이 화면 반대편에 나타납니다. w 가 0 이면 0 으로 나누게 됩니다.

JavaScript
const toScreen = (x, w) => x / w;

toScreen(1, 2);   // 0.5   카메라 앞
toScreen(1, -2);  // -0.5  카메라 뒤

두 점은 x 가 같고 w 의 부호만 다릅니다. 나누고 나면 카메라 뒤의 점이 앞의 점과 좌우가 뒤집힌 곳에 찍힙니다. 나눈 값만 보고는 이 점이 뒤에 있었는지 알 수 없습니다.

클립 공간의 부등식은 이 점을 나누기 전에 걸러 냅니다. w 가 음수면 -w 가 w 보다 커집니다. 이러면 -w ≤ x ≤ w 를 만족하는 x 가 하나도 없어서, 카메라 뒤의 점은 언제나 범위 밖으로 판정됩니다.

카메라 앞과 뒤에 걸친 삼각형은 근평면에서 잘립니다. 근평면은 카메라보다 조금 앞에 있으므로, 잘리고 남은 꼭짓점은 전부 w 가 양수입니다. 나눗셈 단계에 닿는 점은 w 가 0 이하일 일이 없습니다.

w 로 나눈 뒤의 좌표

클리핑이 끝나면 GPU 가 남은 정점의 x, y, z 를 w 로 나눕니다. 이 나눗셈이 원근 나눗셈입니다. 개발자가 작성하지 않아도 GPU 가 알아서 하는 단계입니다.

나눈 결과가 앞에서 본 정규화 장치 좌표(NDC, Normalized Device Coordinates)입니다. 피라미드 모양이던 보이는 범위가 가로 · 세로 모두 -1 부터 1 까지인 반듯한 상자로 펴진 좌표입니다. 먼 점일수록 큰 w 로 나뉘어 상자 가운데로 모입니다. 그래서 화면에서 작게 그려집니다.

직교 투영이면 w 가 1 이라 나눠도 값이 바뀌지 않습니다. 이때는 클립 공간 좌표가 곧 정규화 장치 좌표입니다.

그다음 이 상자를 화면 크기에 맞춰 늘립니다. -1 부터 1 까지를 0 부터 화면 너비까지로 옮기는 식입니다. 이 단계가 뷰포트 변환입니다. 결과는 픽셀 단위의 화면 좌표입니다.

클립 공간 좌표를 눈으로 읽을 때는 이 나눗셈을 머릿속에서 해야 합니다. (4, 2, 3, 8) 이라는 좌표는 x 가 4 라서, -1 부터 1 까지인 범위로 보면 한참 밖에 있는 것 같습니다. 하지만 w 인 8 로 나누면 0.5 라서, 화면 가운데와 오른쪽 끝의 중간쯤입니다.

관련 항목

클립 공간이 속하는 상위 분류

그래픽스 · 3차원 그래픽스 · 렌더링 · 그래픽스 파이프라인 · 좌표 변환

한 점이 화면까지 거치는 좌표 공간

모델 좌표계 · 월드 좌표계 · 뷰 공간 · 정규화 장치 좌표 · 화면 좌표 · 윈도 좌표

클립 공간 좌표를 적는 수학 도구

동차 좌표 · 투영 행렬 · 변환 행렬 · 행렬 곱 · 선형 보간 · 사영 기하학

클립 공간 좌표를 내놓는 셰이더

셰이더 · 정점 셰이더 · 테셀레이션 평가 셰이더 · 지오메트리 셰이더 · 메시 셰이더

클립 공간 좌표를 만드는 투영

원근 투영 · 직교 투영 · 뷰 절두체 · 근평면 · 원평면 · 시야각

클립 공간 앞뒤에서 도형을 걸러 내는 방법

클리핑 · 서덜랜드-호지먼 알고리즘 · 가드 밴드 클리핑 · 절두체 컬링 · 후면 컬링 · 컬링

클립 공간 뒤에 이어지는 처리 단계

원근 나눗셈 · 뷰포트 변환 · 뷰포트 · 래스터화 · 원근 보정 보간 · 깊이 테스트 · 깊이 버퍼

클립 공간 좌표를 받아 처리하는 그래픽 라이브러리

OpenGL · WebGL · Vulkan · Direct3D · Metal · WebGPU

다른 이름: clip space · clip coordinates · 클립 좌표 · 클립 좌표계 · 동차 클립 공간