diff --git a/source/engines/iw_engine/formulas.cpp b/source/engines/iw_engine/formulas.cpp index e7ab4b8..4a24d0b 100644 --- a/source/engines/iw_engine/formulas.cpp +++ b/source/engines/iw_engine/formulas.cpp @@ -38,25 +38,24 @@ namespace omath::iw_engine Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near, const float far, const NDCDepthRange ndc_depth_range) noexcept { - // NOTE: Need magic number to fix fov calculation, since IW engine inherit Quake proj matrix calculation - constexpr auto k_multiply_factor = 0.75f; - - const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f) * k_multiply_factor; + // InfinityWard Engine (inherited from Quake) stores FOV as horizontal FOV at a 4:3 + // reference aspect. Convert to true vertical FOV, then delegate to the + // standard vertical-FOV left-handed builder with the caller's actual + // aspect ratio. + // vfov = 2 ยท atan( tan(hfov_4:3 / 2) / (4/3) ) + constexpr float k_source_reference_aspect = 4.f / 3.f; + const float half_hfov_4_3 = angles::degrees_to_radians(field_of_view) / 2.f; + const float vfov_deg = angles::radians_to_degrees( + 2.f * std::atan(std::tan(half_hfov_4_3) / k_source_reference_aspect)); if (ndc_depth_range == NDCDepthRange::ZERO_TO_ONE) - return { - {1.f / (aspect_ratio * fov_half_tan), 0, 0, 0}, - {0, 1.f / (fov_half_tan), 0, 0}, - {0, 0, far / (far - near), -(near * far) / (far - near)}, - {0, 0, 1, 0}, - }; + return mat_perspective_left_handed< + float, MatStoreType::ROW_MAJOR, NDCDepthRange::ZERO_TO_ONE>( + vfov_deg, aspect_ratio, near, far); if (ndc_depth_range == NDCDepthRange::NEGATIVE_ONE_TO_ONE) - return { - {1.f / (aspect_ratio * fov_half_tan), 0, 0, 0}, - {0, 1.f / (fov_half_tan), 0, 0}, - {0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)}, - {0, 0, 1, 0}, - }; + return mat_perspective_left_handed< + float, MatStoreType::ROW_MAJOR, NDCDepthRange::NEGATIVE_ONE_TO_ONE>( + vfov_deg, aspect_ratio, near, far); std::unreachable(); }; } // namespace omath::iw_engine