Skip to content

Feature/custom ndc z range#177

Merged
orange-cpp merged 3 commits intomainfrom
feature/custom_ndc_z_range
Mar 24, 2026
Merged

Feature/custom ndc z range#177
orange-cpp merged 3 commits intomainfrom
feature/custom_ndc_z_range

Conversation

@orange-cpp
Copy link
Owner

No description provided.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds configurable NDC depth range support ([-1, 1] vs [0, 1]) across matrix constructors, the generic projection::Camera, and all engine camera traits, with expanded unit tests to validate Z mapping for both conventions.

Changes:

  • Introduce NDCDepthRange and extend perspective/ortho matrix builders to support [0, 1] depth.
  • Propagate the depth-range choice through projection::Camera (template parameter) and engine CameraTrait / calc_perspective_projection_matrix APIs.
  • Add/extend unit tests to validate near/far/mid Z mapping for both depth conventions across engines.

Reviewed changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/general/unit_test_mat.cpp Adds unit tests covering [0,1] and [-1,1] Z mapping for perspective/ortho matrices.
tests/engines/unit_test_traits_engines.cpp Extends trait tests to validate both depth ranges across engines and verifies Z mapping behavior.
source/engines/unreal_engine/traits/camera_trait.cpp Threads NDCDepthRange through Unreal camera trait projection computation.
source/engines/unreal_engine/formulas.cpp Adds [0,1]-depth option to Unreal projection matrix formula.
source/engines/unity_engine/traits/camera_trait.cpp Threads NDCDepthRange through Unity camera trait projection computation.
source/engines/unity_engine/formulas.cpp Adds [0,1]-depth option to Unity projection matrix formula.
source/engines/source_engine/traits/camera_trait.cpp Threads NDCDepthRange through Source camera trait projection computation.
source/engines/source_engine/formulas.cpp Adds [0,1]-depth option to Source projection matrix formula.
source/engines/opengl_engine/traits/camera_trait.cpp Threads NDCDepthRange through OpenGL camera trait projection computation.
source/engines/opengl_engine/formulas.cpp Adds [0,1]-depth option to OpenGL projection matrix formula.
source/engines/iw_engine/traits/camera_trait.cpp Threads NDCDepthRange through IW camera trait projection computation.
source/engines/iw_engine/formulas.cpp Adds [0,1]-depth option to IW projection matrix formula.
source/engines/frostbite_engine/traits/camera_trait.cpp Threads NDCDepthRange through Frostbite camera trait projection computation.
source/engines/frostbite_engine/formulas.cpp Adds [0,1]-depth option to Frostbite projection matrix formula.
source/engines/cry_engine/traits/camera_trait.cpp Threads NDCDepthRange through CryEngine camera trait projection computation.
source/engines/cry_engine/formulas.cpp Adds [0,1]-depth option to CryEngine projection matrix formula.
include/omath/projection/camera.hpp Adds depth-range template param; updates clipping/frustum checks to respect Z convention.
include/omath/linear_algebra/mat.hpp Introduces NDCDepthRange; updates mat perspective/ortho builders for depth-range selection.
include/omath/engines/unreal_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/unreal_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/unreal_engine/camera.hpp Sets Unreal Camera alias to use [0,1] depth by default.
include/omath/engines/unity_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/unity_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/unity_engine/camera.hpp Sets Unity Camera alias to use [0,1] depth by default.
include/omath/engines/source_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/source_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/source_engine/camera.hpp Sets Source Camera alias to use [0,1] depth by default.
include/omath/engines/opengl_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/opengl_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/opengl_engine/camera.hpp Keeps OpenGL Camera alias at [-1,1] depth explicitly.
include/omath/engines/iw_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/iw_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/iw_engine/camera.hpp Sets IW Camera alias to use [0,1] depth by default.
include/omath/engines/frostbite_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/frostbite_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/frostbite_engine/camera.hpp Sets Frostbite Camera alias to use [0,1] depth by default.
include/omath/engines/cry_engine/traits/camera_trait.hpp Updates trait signature to accept NDCDepthRange.
include/omath/engines/cry_engine/formulas.hpp Updates projection formula signature to accept NDCDepthRange with a default.
include/omath/engines/cry_engine/camera.hpp Sets CryEngine Camera alias to use [0,1] depth by default.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far,
ndc_depth_range);
}
} // namespace omath::unity_engine No newline at end of file
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing namespace comment is incorrect (it says omath::unity_engine but the file namespace is omath::cry_engine). Update the comment to match the actual namespace to avoid confusion during maintenance/searching.

Suggested change
} // namespace omath::unity_engine
} // namespace omath::cry_engine

Copilot uses AI. Check for mistakes.

return mat_perspective_left_handed(field_of_view, aspect_ratio, near, far);
}
} // namespace omath::unity_engine
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing namespace comment is incorrect (it says omath::unity_engine but the file namespace is omath::frostbite_engine). Please update it so it matches the actual namespace.

Suggested change
} // namespace omath::unity_engine
} // namespace omath::frostbite_engine

Copilot uses AI. Check for mistakes.
float near, float far, NDCDepthRange ndc_depth_range) noexcept;
};

} // namespace omath::unreal_engine No newline at end of file
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing namespace comment is incorrect (it says omath::unreal_engine but the header declares namespace omath::frostbite_engine). Please update the comment to match the actual namespace.

Suggested change
} // namespace omath::unreal_engine
} // namespace omath::frostbite_engine

Copilot uses AI. Check for mistakes.
namespace omath::unreal_engine
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the default NDC depth convention for omath::unreal_engine::Camera to ZERO_TO_ONE. Since this is a public alias, it’s a behavioral/API change for any existing users relying on the previous default depth range; if both conventions are supported now, consider providing separate aliases (e.g. CameraZO/CameraNO) or documenting the change prominently.

Suggested change
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
// Unreal Engine uses a [0, 1] depth range in NDC. Provide explicit camera aliases
// for both supported conventions to avoid ambiguity:
//
// - CameraZO : NDCDepthRange::ZERO_TO_ONE (Unreal-style depth range)
// - CameraNO : NDCDepthRange::NEGATIVE_ONE_TO_ONE (OpenGL-style depth range)
//
// NOTE: The generic `Camera` alias below currently maps to `CameraZO`, i.e. it uses
// NDCDepthRange::ZERO_TO_ONE. In earlier versions, `Camera` used a different default
// depth range (typically NEGATIVE_ONE_TO_ONE). Prefer using `CameraZO` or `CameraNO`
// explicitly if your code depends on a particular NDC depth convention.
using CameraZO = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
using CameraNO = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::NEGATIVE_ONE_TO_ONE>;
// Backward-compatible alias: keep `Camera` pointing to the ZERO_TO_ONE variant.
using Camera = CameraZO;

Copilot uses AI. Check for mistakes.
return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far,
ndc_depth_range);
}
} // namespace omath::unity_engine No newline at end of file
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing namespace comment is incorrect (it says omath::unity_engine but the file namespace is omath::frostbite_engine). Update the comment to match the actual namespace to avoid confusion during maintenance/searching.

Suggested change
} // namespace omath::unity_engine
} // namespace omath::frostbite_engine

Copilot uses AI. Check for mistakes.

return mat_perspective_left_handed(field_of_view, aspect_ratio, near, far);
}
} // namespace omath::unity_engine
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing namespace comment is incorrect (it says omath::unity_engine but the file namespace is omath::cry_engine). Please update it so it matches the actual namespace.

Suggested change
} // namespace omath::unity_engine
} // namespace omath::cry_engine

Copilot uses AI. Check for mistakes.
{
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
} // namespace omath::unity_engine No newline at end of file
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closing namespace comment is incorrect (it says omath::unity_engine but the header declares namespace omath::frostbite_engine). Please update the comment to match the actual namespace.

Suggested change
} // namespace omath::unity_engine
} // namespace omath::frostbite_engine

Copilot uses AI. Check for mistakes.
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-3f);
}

TEST(UnitTestMatStandalone, MatPerspectiveZeroToOneEquanity)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the test name: "Equanity" should be "Equality" (this affects test discovery/filtering readability).

Copilot uses AI. Check for mistakes.
Comment on lines 44 to +57
template<class T, class MatType, class ViewAnglesType>
concept CameraEngineConcept =
requires(const Vector3<float>& cam_origin, const Vector3<float>& look_at, const ViewAnglesType& angles,
const FieldOfView& fov, const ViewPort& viewport, float znear, float zfar) {
const FieldOfView& fov, const ViewPort& viewport, float znear, float zfar,
NDCDepthRange ndc_depth_range) {
// Presence + return types
{ T::calc_look_at_angle(cam_origin, look_at) } -> std::same_as<ViewAnglesType>;
{ T::calc_view_matrix(angles, cam_origin) } -> std::same_as<MatType>;
{ T::calc_projection_matrix(fov, viewport, znear, zfar) } -> std::same_as<MatType>;
{ T::calc_projection_matrix(fov, viewport, znear, zfar, ndc_depth_range) } -> std::same_as<MatType>;

// Enforce noexcept as in the trait declaration
requires noexcept(T::calc_look_at_angle(cam_origin, look_at));
requires noexcept(T::calc_view_matrix(angles, cam_origin));
requires noexcept(T::calc_projection_matrix(fov, viewport, znear, zfar));
requires noexcept(T::calc_projection_matrix(fov, viewport, znear, zfar, ndc_depth_range));
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requiring ndc_depth_range in the concept forces all CameraTrait::calc_projection_matrix call sites (including user code) to add an extra argument. If backward compatibility is a goal, consider giving ndc_depth_range a default value (e.g. NEGATIVE_ONE_TO_ONE) in the trait declarations so existing 4-arg calls still compile while Camera can continue passing depth_range explicitly.

Copilot uses AI. Check for mistakes.
@orange-cpp orange-cpp merged commit 29b7ac6 into main Mar 24, 2026
24 checks passed
@orange-cpp orange-cpp deleted the feature/custom_ndc_z_range branch March 24, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants