개념

C 카메라가 있는 위치, B를 screen space, A를 3D space라고 할 때, A를 B로 projection하는 방법에 대해서 알아보려합니다.
(그림은 특정 좌표의 단면을 본다고 가정합니다.)
C로 시작해서 B, A를 이어가는 벡터로 볼 수 있으므로, B와 A는 서로에게 linearly dependent한 상태입니다. 따라서 아래와 같은 식으로 나타낼 수 있습니다.
다시 그림을 보면, 좌표를 z축에 투영하면 삼각형이 하나 나오는 것을 상상할 수 있습니다. 또한 해당 삼각형이 서로 비례한다는 것도 상상할 수 있게됩니다. 이를 이용해서 다음과 같은 식을 얻을 수 있습니다.
위의 두 식을 결합하면 최종적으로 B의 좌표를 얻을 수 있게됩니다.
projection 코드
const float scale = distEyeToScreen / (distEyeToScreen + pointWorld.z);
pointProj *= scale;왜곡 보정
perspective projection을 수행하고 나면 한가지 문제가 생기는데, interpolation을 수행하는 것이 왜곡되어 표현된다는 점입니다. 왜곡이 발생하는 이유로는 projection 이전에 interpolation이 필요하지만, projection 이후에, interpolation을 수행하기 때문에 발생합니다.
따라서 왜곡을 보정하기 위해서는 projection 이전인 3D space에서 interpolation한 값이 필요합니다.

해당 그림에서 O를 시작점으로 볼 때, a와 a’, b와 b’, c와 c’, p와 p’은 서로에게 linearly dependent한 것을 알 수 있습니다.
식으로 표현하면 다음과 같습니다.
여기서 p는 interpolation된 값을 나타내므로 다음과 같이 표현할 수 있습니다.
이제 위에서 얻은 식을 섞어서 다음과 같이 표현할 수 있습니다.
위 두식을 연립하여 다시 해당 식을 얻을 수 있습니다.
berycentic coordinates는 합이 1이므로 아래와 같이 나타낼 수 있습니다.
위 식을 정리해서 t 값을 얻어낼 수 있게됩니다.
이제 위에서 구한 식에 t를 대입하면 아래와 같은 최종 값을 얻을 수 있습니다.
이제 해당 식으로 interpolation을 수행하면 왜곡을 보정할 수 있습니다.
correct interpolation 코드
const float z0 = this->vertexBuffer[i0].z + distEyeToScreen;
const float z1 = this->vertexBuffer[i1].z + distEyeToScreen;
const float z2 = this->vertexBuffer[i2].z + distEyeToScreen;
if (this->usePerspectiveProjection &&
this->usePerspectiveCorrectInterpolation) {
const float t = w0 / z0 + w1 / z1 + w2 / z2;
w0 = w0 / z0 / t;
w1 = w1 / z1 / t;
w2 = w2 / z2 / t;
}코드에서는 원점이 sceen space의 중간 지점이므로, distEyeToScreen + this→vertexBuffer[i0].z의 값이 3D space의 z값이 됩니다.