Skip to content

Perspective and Orthographic projections

Dandielo edited this page Feb 20, 2025 · 9 revisions

Because this IceShard targets newer graphics API's, like Vulkan and DX11/DX12, the perspective and orthographic projections are prepared to handle these cases.

We work in a right-handed coordinate system with column-major matrices. The resulting NDC volume is defined by the following ranges:

  • For X: -1 <= x' <= 1
  • For Y: -1 <= y' <= 1
  • For Z: 0 <= z' <= 1

Perspective projection

The below calculations represent the math that should be applied to components of a point P to get a projected point P'. The comments provide additional information, where the part of the equation should be stored in a matrix representation.

The z component results negative, this is achieved by subtracting the far_plane from near_plane.

x' = 
    x * 2 * near_plane / (right - left) + // stored in column 0, row 0 (x axis, x component)
    z * (right + left) / (right - left)   // stored in column 2, row 0 (z axis, x component)

y' = 
    y * 2 * near_plane / (top - bottom) + // stored in column 1, row 1 (y axis, y component)
    z * (top + bottom) / (top - bottom)   // stored in column 2, row 1 (z axis, y component)

z' = 
    z * far_plane / (near_plane - far_plane) +              // stored in column 2, row 2 (z axis, z component)
    w * (near_plane * far_plane) / (near_plane - far_plane) // stored in column 3, row 2 (w axis, z component)

w' = z * -1.f   // stored in column 2, row 3 (z axis, w component)

The current implementation in IceShard:

ice::math::mat<4, 4, f32> result{ };
result.v[0][0] = 2.f * near_plane / (right - left);
result.v[1][1] = 2.f * near_plane / (top - bottom);
result.v[2][0] = (right + left) / (right - left);
result.v[2][1] = (top + bottom) / (top - bottom);
result.v[2][2] = far_plane / (near_plane - far_plane);
result.v[2][3] = -1.f;
result.v[3][2] = (near_plane * far_plane) / (near_plane - far_plane);

Orthographic projection

The below calculations represent the math that should be applied to components of a point P to get a projected point P'. The comments provide additional information, where the part of the equation should be stored in a matrix representation.

The z component results negative, this is achieved by subtracting the far_plane from near_plane.

x' = 
    x * 2 * (right - left) +             // stored in column 0, row 0 (x axis, x component)
    w * -(right + left) / (right - left) // stored in column 3, row 0 (w axis, x component)

y' = 
    y * 2 / (top - bottom) +             // stored in column 1, row 1 (y axis, y component)
    w * -(top + bottom) / (top - bottom) // stored in column 3, row 1 (w axis, y component)

z' = 
    z * 1 / (near_plane - far_plane) +        // stored in column 2, row 2 (z axis, z component)
    w * near_plane / (near_plane - far_plane) // stored in column 3, row 2 (w axis, z component)

w' = w     // stored in column 3, row 3 (w axis, w component)

The current implementation in IceShard:

ice::math::mat<4, 4, f32> result{ };
result.v[0][0] = 2.f / (right - left);
result.v[1][1] = 2.f / (bottom - top);
result.v[2][2] = 1.f / (near_plane - far_plane);
result.v[3][0] = -(right + left) / (right - left);
result.v[3][1] = -(bottom + top) / (bottom - top);
result.v[3][2] = near_plane / (near_plane - far_plane);
result.v[3][3] = 1.f;

Clone this wiki locally