Viewport는 3D 그래픽에서 렌더링된 결과가 실제 화면에 표시되는 영역을 말한다.
쉽게 말해, 우리가 만든 3D 세계가 실제로 “어디에”, “어떻게” 보여질지를 결정하는 중요한 개념이다.
3D → 2D 변환의 마지막 단계가 바로 이 Viewport 변환이다.
3D 오브젝트가 화면에 그려지기까지의 변환 과정은 아래 순서로 이루어진다:
로컬(Local)
→ 월드(World)
→ 뷰(View / View Space)
→ 프로젝션(Projection / Clip Space)
→ 정규 디바이스 좌표(NDC)
→ Viewport 변환(Screen Space / 최종 2D 화면 좌표)
우리가 3D 공간에서 마우스로 무언가를 클릭한다고 가정해보자.
마우스는 2D 좌표지만 실제로 선택하고자 하는 대상은 3D 물체다.
즉, 2D → 3D로 변환하는 과정(Unprojection) 이 반드시 필요하다.
이 과정에서 핵심 역할을 하는 게 바로 Viewport다.
예: 화면 중앙을 클릭했을 때,
카메라 위치에서 화면 중앙을 향해 레이저(ray) 를 쏘아
그 레이저가 맞은 오브젝트를 선택하는 방식.
이건 단순한 클릭뿐만 아니라 충돌 판정, AI 시야, 사거리 계산 등에도 응용된다.
다시 말해, Viewport는 2D 좌표를 3D 공간에서 유의미하게 쓰기 위한 게이트웨이 역할을 한다.
D3D11_VIEWPORT _vp;
DirectX가 제공하는 D3D11_VIEWPORT 구조체 하나만으로 필요한 정보를 모두 담을 수 있다.
Project: 3D 좌표 → 2D 스크린 좌표Unproject: 2D 스크린 좌표 + 깊이 → 3D 좌표Vec3 Viewport::Project(const Vec3& pos, const Matrix& W, const Matrix& V, const Matrix& P)
{
Matrix wvp = W * V * P;
Vec3 p = Vec3::Transform(pos, wvp);
p.x = (p.x + 1.0f) * (_vp.Width / 2) + _vp.TopLeftX;
p.y = (-p.y + 1.0f) * (_vp.Height / 2) + _vp.TopLeftY;
p.z = p.z * (_vp.MaxDepth - _vp.MinDepth) + _vp.MinDepth;
return p;
}
Vec3 Viewport::Unproject(const Vec3& pos, const Matrix& W, const Matrix& V, const Matrix& P)
{
Vec3 p = pos;
p.x = 2.f * (p.x - _vp.TopLeftX) / _vp.Width - 1.f;
p.y = -2.f * (p.y - _vp.TopLeftY) / _vp.Height + 1.f;
p.z = (p.z - _vp.MinDepth) / (_vp.MaxDepth - _vp.MinDepth);
Matrix wvp = W * V * P;
Matrix wvpInv = wvp.Invert();
return Vec3::Transform(p, wvpInv);
}
원래 Graphics 클래스에는 D3D11_VIEWPORT가 직접 들어있었지만,
우리는 이를 Viewport 클래스로 교체하고 별도로 관리하도록 했다.
이로써 Viewport의 폭/높이/위치/깊이값을 자유롭게 조작할 수 있게 된다.
Viewport 자체가 단순한 렌더링 옵션이 아니라,
입출력 좌표계의 핵심 매개체라는 점을 명확하게 알 수 있다.
깊이값을 0에 가까이 두면 카메라 가까이
깊이값을 1에 두면 멀리 떨어진 곳이 된다