clip space와 화면 좌표
CSS와 Canvas 2D에서는 왼쪽 위가 (0, 0)이고 오른쪽 아래로 갈수록 x, y가 커집니다. WebGL은 바로 그 좌표를 받지 않습니다.
WebGL vertex shader가 최종적으로 내보내는 좌표는 clip space입니다.
x: -1 .. 1
y: -1 .. 1
screen 좌표를 clip 좌표로 바꾸는 코드
처음에는 matrix 없이 CPU에서 직접 변환해도 됩니다. CSS pixel 좌표 (x, y)를 WebGL clip space로 바꾸면 이렇게 됩니다.
function screenToClip(x, y, width, height) {
return [
(x / width) * 2 - 1,
1 - (y / height) * 2
];
}
const [clipX, clipY] = screenToClip(120, 80, canvas.width, canvas.height);
rectangle 네 모서리를 screen 좌표로 만든 뒤 clip 좌표로 바꿔 buffer에 넣을 수도 있습니다.
function rectToClipVertices(rect, canvas) {
const x0 = rect.x;
const y0 = rect.y;
const x1 = rect.x + rect.width;
const y1 = rect.y + rect.height;
return new Float32Array([
...screenToClip(x0, y0, canvas.width, canvas.height),
...screenToClip(x1, y0, canvas.width, canvas.height),
...screenToClip(x0, y1, canvas.width, canvas.height),
...screenToClip(x0, y1, canvas.width, canvas.height),
...screenToClip(x1, y0, canvas.width, canvas.height),
...screenToClip(x1, y1, canvas.width, canvas.height)
]);
}
나중에는 이 변환을 CPU에서 매번 하지 않고 projection matrix로 만들어 shader에 보냅니다. 하지만 처음에는 이 함수가 좌표계 차이를 가장 명확하게 보여줍니다.
clip space는 화면에 붙은 정규화 좌표다
clip space에서 왼쪽은 x = -1, 오른쪽은 x = 1입니다. 아래는 y = -1, 위는 y = 1입니다.
브라우저 화면 좌표와 방향이 다릅니다.
screen: 왼쪽 위 원점, y 아래로 증가
clip: 중앙 기준, y 위로 증가
그래서 editor의 screen 좌표를 그대로 vertex shader에 넣으면 원하는 위치에 그려지지 않습니다.
screen을 clip으로 바꾸는 projection이 필요하다
2D renderer에서는 화면 픽셀 좌표를 clip space로 바꾸는 행렬을 둡니다.
clipX = screenX / width * 2 - 1
clipY = 1 - screenY / height * 2
이 변환은 CSS에서 좌표계를 바꾸던 일과 같습니다. 기준점과 축 방향, 단위 범위를 바꾸는 것입니다.
world까지 연결한다
편집기에서는 도형이 world 좌표에 있습니다. 따라서 최종 흐름은 이렇게 됩니다.
local -> world -> screen -> clip
처음에는 CPU에서 screen 좌표를 계산해서 넣어도 됩니다. 하지만 곧 matrix uniform을 shader에 보내서 GPU가 변환하도록 만들 겁니다.
오늘의 핵심
WebGL이 낯선 이유 중 하나는 좌표계가 CSS와 다르기 때문입니다. 하지만 본질은 같습니다.
지금 숫자가 어느 좌표계인지 붙잡는다.
필요한 좌표계로 변환한다.
clip space는 WebGL 화면의 마지막 좌표계입니다. editor 좌표계를 여기까지 보내는 길이 renderer의 뼈대입니다.