You've already forked godot
							
							
				mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 12:00:25 +00:00 
			
		
		
		
	Merge pull request #100209 from Flarkk/simplify_fix_projection
Simplify and fix `Projection`'s getter functions
This commit is contained in:
		@@ -402,82 +402,35 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
real_t Projection::get_z_far() const {
 | 
			
		||||
	const real_t *matrix = (const real_t *)columns;
 | 
			
		||||
	Plane new_plane = Plane(matrix[3] - matrix[2],
 | 
			
		||||
			matrix[7] - matrix[6],
 | 
			
		||||
			matrix[11] - matrix[10],
 | 
			
		||||
			matrix[15] - matrix[14]);
 | 
			
		||||
 | 
			
		||||
	new_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	return new_plane.d;
 | 
			
		||||
	// NOTE: This assumes z-facing near and far planes, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - near and far planes are z-facing (i.e. columns[0][2] and [1][2] == 0)
 | 
			
		||||
	return (columns[3][3] - columns[3][2]) / (columns[2][3] - columns[2][2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
real_t Projection::get_z_near() const {
 | 
			
		||||
	const real_t *matrix = (const real_t *)columns;
 | 
			
		||||
	Plane new_plane = Plane(matrix[3] + matrix[2],
 | 
			
		||||
			matrix[7] + matrix[6],
 | 
			
		||||
			matrix[11] + matrix[10],
 | 
			
		||||
			-matrix[15] - matrix[14]);
 | 
			
		||||
 | 
			
		||||
	new_plane.normalize();
 | 
			
		||||
	return new_plane.d;
 | 
			
		||||
	// NOTE: This assumes z-facing near and far planes, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - near and far planes are z-facing (i.e. columns[0][2] and [1][2] == 0)
 | 
			
		||||
	return (columns[3][3] + columns[3][2]) / (columns[2][3] + columns[2][2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vector2 Projection::get_viewport_half_extents() const {
 | 
			
		||||
	const real_t *matrix = (const real_t *)columns;
 | 
			
		||||
	///////--- Near Plane ---///////
 | 
			
		||||
	Plane near_plane = Plane(matrix[3] + matrix[2],
 | 
			
		||||
			matrix[7] + matrix[6],
 | 
			
		||||
			matrix[11] + matrix[10],
 | 
			
		||||
			-matrix[15] - matrix[14]);
 | 
			
		||||
	near_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	///////--- Right Plane ---///////
 | 
			
		||||
	Plane right_plane = Plane(matrix[3] - matrix[0],
 | 
			
		||||
			matrix[7] - matrix[4],
 | 
			
		||||
			matrix[11] - matrix[8],
 | 
			
		||||
			-matrix[15] + matrix[12]);
 | 
			
		||||
	right_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	Plane top_plane = Plane(matrix[3] - matrix[1],
 | 
			
		||||
			matrix[7] - matrix[5],
 | 
			
		||||
			matrix[11] - matrix[9],
 | 
			
		||||
			-matrix[15] + matrix[13]);
 | 
			
		||||
	top_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	Vector3 res;
 | 
			
		||||
	near_plane.intersect_3(right_plane, top_plane, &res);
 | 
			
		||||
 | 
			
		||||
	return Vector2(res.x, res.y);
 | 
			
		||||
	// NOTE: This assumes a symmetrical frustum, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0)
 | 
			
		||||
	// - there is no offset / skew (i.e. columns[2][0] == columns[2][1] == 0)
 | 
			
		||||
	real_t w = -get_z_near() * columns[2][3] + columns[3][3];
 | 
			
		||||
	return Vector2(w / columns[0][0], w / columns[1][1]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vector2 Projection::get_far_plane_half_extents() const {
 | 
			
		||||
	const real_t *matrix = (const real_t *)columns;
 | 
			
		||||
	///////--- Far Plane ---///////
 | 
			
		||||
	Plane far_plane = Plane(matrix[3] - matrix[2],
 | 
			
		||||
			matrix[7] - matrix[6],
 | 
			
		||||
			matrix[11] - matrix[10],
 | 
			
		||||
			-matrix[15] + matrix[14]);
 | 
			
		||||
	far_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	///////--- Right Plane ---///////
 | 
			
		||||
	Plane right_plane = Plane(matrix[3] - matrix[0],
 | 
			
		||||
			matrix[7] - matrix[4],
 | 
			
		||||
			matrix[11] - matrix[8],
 | 
			
		||||
			-matrix[15] + matrix[12]);
 | 
			
		||||
	right_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	Plane top_plane = Plane(matrix[3] - matrix[1],
 | 
			
		||||
			matrix[7] - matrix[5],
 | 
			
		||||
			matrix[11] - matrix[9],
 | 
			
		||||
			-matrix[15] + matrix[13]);
 | 
			
		||||
	top_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	Vector3 res;
 | 
			
		||||
	far_plane.intersect_3(right_plane, top_plane, &res);
 | 
			
		||||
 | 
			
		||||
	return Vector2(res.x, res.y);
 | 
			
		||||
	// NOTE: This assumes a symmetrical frustum, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0)
 | 
			
		||||
	// - there is no offset / skew (i.e. columns[2][0] == columns[2][1] == 0)
 | 
			
		||||
	real_t w = -get_z_far() * columns[2][3] + columns[3][3];
 | 
			
		||||
	return Vector2(w / columns[0][0], w / columns[1][1]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const {
 | 
			
		||||
@@ -919,53 +872,45 @@ Projection::operator String() const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
real_t Projection::get_aspect() const {
 | 
			
		||||
	Vector2 vp_he = get_viewport_half_extents();
 | 
			
		||||
	return vp_he.x / vp_he.y;
 | 
			
		||||
	// NOTE: This assumes a rectangular projection plane, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0)
 | 
			
		||||
	return columns[1][1] / columns[0][0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Projection::get_pixels_per_meter(int p_for_pixel_width) const {
 | 
			
		||||
	Vector3 result = xform(Vector3(1, 0, -1));
 | 
			
		||||
 | 
			
		||||
	return int((result.x * 0.5 + 0.5) * p_for_pixel_width);
 | 
			
		||||
	// NOTE: This assumes a rectangular projection plane, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0)
 | 
			
		||||
	real_t width = 2 * (-get_z_near() * columns[2][3] + columns[3][3]) / columns[0][0];
 | 
			
		||||
	return p_for_pixel_width / width; // Note : return type should be real_t (kept as int for compatibility for now).
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Projection::is_orthogonal() const {
 | 
			
		||||
	return columns[3][3] == 1.0;
 | 
			
		||||
	// NOTE: This assumes that the matrix is a projection across z-axis
 | 
			
		||||
	// i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0
 | 
			
		||||
	return columns[2][3] == 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
real_t Projection::get_fov() const {
 | 
			
		||||
	const real_t *matrix = (const real_t *)columns;
 | 
			
		||||
 | 
			
		||||
	Plane right_plane = Plane(matrix[3] - matrix[0],
 | 
			
		||||
			matrix[7] - matrix[4],
 | 
			
		||||
			matrix[11] - matrix[8],
 | 
			
		||||
			-matrix[15] + matrix[12]);
 | 
			
		||||
	right_plane.normalize();
 | 
			
		||||
 | 
			
		||||
	if ((matrix[8] == 0) && (matrix[9] == 0)) {
 | 
			
		||||
		return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
 | 
			
		||||
	// NOTE: This assumes a rectangular projection plane, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0)
 | 
			
		||||
	if (columns[2][0] == 0) {
 | 
			
		||||
		return Math::rad_to_deg(2 * Math::atan2(1, columns[0][0]));
 | 
			
		||||
	} else {
 | 
			
		||||
		// our frustum is asymmetrical need to calculate the left planes angle separately..
 | 
			
		||||
		Plane left_plane = Plane(matrix[3] + matrix[0],
 | 
			
		||||
				matrix[7] + matrix[4],
 | 
			
		||||
				matrix[11] + matrix[8],
 | 
			
		||||
				matrix[15] + matrix[12]);
 | 
			
		||||
		left_plane.normalize();
 | 
			
		||||
 | 
			
		||||
		return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x)));
 | 
			
		||||
		// The frustum is asymmetrical so we need to calculate the left and right angles separately.
 | 
			
		||||
		real_t right = Math::atan2(columns[2][0] + 1, columns[0][0]);
 | 
			
		||||
		real_t left = Math::atan2(columns[2][0] - 1, columns[0][0]);
 | 
			
		||||
		return Math::rad_to_deg(right - left);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
real_t Projection::get_lod_multiplier() const {
 | 
			
		||||
	if (is_orthogonal()) {
 | 
			
		||||
		return get_viewport_half_extents().x;
 | 
			
		||||
	} else {
 | 
			
		||||
		const real_t zn = get_z_near();
 | 
			
		||||
		const real_t width = get_viewport_half_extents().x * 2.0f;
 | 
			
		||||
		return 1.0f / (zn / width);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Usage is lod_size / (lod_distance * multiplier) < threshold
 | 
			
		||||
	// NOTE: This assumes a rectangular projection plane, i.e. that :
 | 
			
		||||
	// - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0)
 | 
			
		||||
	// - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0)
 | 
			
		||||
	return 2 / columns[0][0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Projection::make_scale(const Vector3 &p_scale) {
 | 
			
		||||
 
 | 
			
		||||
@@ -207,7 +207,7 @@
 | 
			
		||||
			<return type="int" />
 | 
			
		||||
			<param index="0" name="for_pixel_width" type="int" />
 | 
			
		||||
			<description>
 | 
			
		||||
				Returns the number of pixels with the given pixel width displayed per meter, after this [Projection] is applied.
 | 
			
		||||
				Returns [param for_pixel_width] divided by the viewport's width measured in meters on the near plane, after this [Projection] is applied.
 | 
			
		||||
			</description>
 | 
			
		||||
		</method>
 | 
			
		||||
		<method name="get_projection_plane" qualifiers="const">
 | 
			
		||||
 
 | 
			
		||||
@@ -449,6 +449,78 @@ TEST_CASE("[Projection] Perspective values extraction") {
 | 
			
		||||
	CHECK(zfar == doctest::Approx(50));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(0.5));
 | 
			
		||||
	CHECK(fov == doctest::Approx(90));
 | 
			
		||||
 | 
			
		||||
	persp.set_perspective(38, 1.3, 0.2, 8, false);
 | 
			
		||||
 | 
			
		||||
	znear = persp.get_z_near();
 | 
			
		||||
	zfar = persp.get_z_far();
 | 
			
		||||
	aspect = persp.get_aspect();
 | 
			
		||||
	fov = persp.get_fov();
 | 
			
		||||
 | 
			
		||||
	CHECK(znear == doctest::Approx(0.2));
 | 
			
		||||
	CHECK(zfar == doctest::Approx(8));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(1.3));
 | 
			
		||||
	CHECK(fov == doctest::Approx(Projection::get_fovy(38, 1.3)));
 | 
			
		||||
 | 
			
		||||
	persp.set_perspective(47, 2.5, 0.9, 14, true);
 | 
			
		||||
 | 
			
		||||
	znear = persp.get_z_near();
 | 
			
		||||
	zfar = persp.get_z_far();
 | 
			
		||||
	aspect = persp.get_aspect();
 | 
			
		||||
	fov = persp.get_fov();
 | 
			
		||||
 | 
			
		||||
	CHECK(znear == doctest::Approx(0.9));
 | 
			
		||||
	CHECK(zfar == doctest::Approx(14));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(2.5));
 | 
			
		||||
	CHECK(fov == doctest::Approx(47));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Frustum values extraction") {
 | 
			
		||||
	Projection frustum = Projection::create_frustum_aspect(1.0, 4.0 / 3.0, Vector2(0.5, -0.25), 0.5, 50, true);
 | 
			
		||||
 | 
			
		||||
	double znear = frustum.get_z_near();
 | 
			
		||||
	double zfar = frustum.get_z_far();
 | 
			
		||||
	double aspect = frustum.get_aspect();
 | 
			
		||||
	double fov = frustum.get_fov();
 | 
			
		||||
 | 
			
		||||
	CHECK(znear == doctest::Approx(0.5));
 | 
			
		||||
	CHECK(zfar == doctest::Approx(50));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(4.0 / 3.0));
 | 
			
		||||
	CHECK(fov == doctest::Approx(Math::rad_to_deg(Math::atan(2.0))));
 | 
			
		||||
 | 
			
		||||
	frustum.set_frustum(2.0, 1.5, Vector2(-0.5, 2), 2, 12, false);
 | 
			
		||||
 | 
			
		||||
	znear = frustum.get_z_near();
 | 
			
		||||
	zfar = frustum.get_z_far();
 | 
			
		||||
	aspect = frustum.get_aspect();
 | 
			
		||||
	fov = frustum.get_fov();
 | 
			
		||||
 | 
			
		||||
	CHECK(znear == doctest::Approx(2));
 | 
			
		||||
	CHECK(zfar == doctest::Approx(12));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(1.5));
 | 
			
		||||
	CHECK(fov == doctest::Approx(Math::rad_to_deg(Math::atan(1.0) + Math::atan(0.5))));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Orthographic values extraction") {
 | 
			
		||||
	Projection ortho = Projection::create_orthogonal(-2, 3, -0.5, 1.5, 1.2, 15);
 | 
			
		||||
 | 
			
		||||
	double znear = ortho.get_z_near();
 | 
			
		||||
	double zfar = ortho.get_z_far();
 | 
			
		||||
	double aspect = ortho.get_aspect();
 | 
			
		||||
 | 
			
		||||
	CHECK(znear == doctest::Approx(1.2));
 | 
			
		||||
	CHECK(zfar == doctest::Approx(15));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(2.5));
 | 
			
		||||
 | 
			
		||||
	ortho.set_orthogonal(-7, 2, 2.5, 5.5, 0.5, 6);
 | 
			
		||||
 | 
			
		||||
	znear = ortho.get_z_near();
 | 
			
		||||
	zfar = ortho.get_z_far();
 | 
			
		||||
	aspect = ortho.get_aspect();
 | 
			
		||||
 | 
			
		||||
	CHECK(znear == doctest::Approx(0.5));
 | 
			
		||||
	CHECK(zfar == doctest::Approx(6));
 | 
			
		||||
	CHECK(aspect == doctest::Approx(3));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Orthographic check") {
 | 
			
		||||
@@ -487,16 +559,48 @@ TEST_CASE("[Projection] Planes extraction") {
 | 
			
		||||
	CHECK(plane_array[Projection::PLANE_BOTTOM].normalized().is_equal_approx(planes[Projection::PLANE_BOTTOM].normalized()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Half extents") {
 | 
			
		||||
TEST_CASE("[Projection] Perspective Half extents") {
 | 
			
		||||
	constexpr real_t sqrt3 = 1.7320508;
 | 
			
		||||
	Projection persp = Projection::create_perspective(90, 1, 1, 40, false);
 | 
			
		||||
	Vector2 ne = persp.get_viewport_half_extents();
 | 
			
		||||
	Vector2 fe = persp.get_far_plane_half_extents();
 | 
			
		||||
 | 
			
		||||
	CHECK(ne.is_equal_approx(Vector2(1, 1) * 1));
 | 
			
		||||
	CHECK(fe.is_equal_approx(Vector2(1, 1) * 40));
 | 
			
		||||
 | 
			
		||||
	persp.set_perspective(120, sqrt3, 0.8, 10, true);
 | 
			
		||||
	ne = persp.get_viewport_half_extents();
 | 
			
		||||
	fe = persp.get_far_plane_half_extents();
 | 
			
		||||
 | 
			
		||||
	CHECK(ne.is_equal_approx(Vector2(sqrt3, 1.0) * 0.8));
 | 
			
		||||
	CHECK(fe.is_equal_approx(Vector2(sqrt3, 1.0) * 10));
 | 
			
		||||
 | 
			
		||||
	persp.set_perspective(60, 1.2, 0.5, 15, false);
 | 
			
		||||
	ne = persp.get_viewport_half_extents();
 | 
			
		||||
	fe = persp.get_far_plane_half_extents();
 | 
			
		||||
 | 
			
		||||
	CHECK(ne.is_equal_approx(Vector2(sqrt3 / 3 * 1.2, sqrt3 / 3) * 0.5));
 | 
			
		||||
	CHECK(fe.is_equal_approx(Vector2(sqrt3 / 3 * 1.2, sqrt3 / 3) * 15));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Orthographic Half extents") {
 | 
			
		||||
	Projection ortho = Projection::create_orthogonal(-3, 3, -1.5, 1.5, 1.2, 15);
 | 
			
		||||
	Vector2 ne = ortho.get_viewport_half_extents();
 | 
			
		||||
	Vector2 fe = ortho.get_far_plane_half_extents();
 | 
			
		||||
 | 
			
		||||
	CHECK(ne.is_equal_approx(Vector2(3, 1.5)));
 | 
			
		||||
	CHECK(fe.is_equal_approx(Vector2(3, 1.5)));
 | 
			
		||||
 | 
			
		||||
	ortho.set_orthogonal(-7, 7, -2.5, 2.5, 0.5, 6);
 | 
			
		||||
	ne = ortho.get_viewport_half_extents();
 | 
			
		||||
	fe = ortho.get_far_plane_half_extents();
 | 
			
		||||
 | 
			
		||||
	CHECK(ne.is_equal_approx(Vector2(7, 2.5)));
 | 
			
		||||
	CHECK(fe.is_equal_approx(Vector2(7, 2.5)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Endpoints") {
 | 
			
		||||
	constexpr real_t sqrt3 = 1.7320508;
 | 
			
		||||
	Projection persp = Projection::create_perspective(90, 1, 1, 40, false);
 | 
			
		||||
	Vector3 ep[8];
 | 
			
		||||
	persp.get_endpoints(Transform3D(), ep);
 | 
			
		||||
@@ -509,8 +613,91 @@ TEST_CASE("[Projection] Endpoints") {
 | 
			
		||||
	CHECK(ep[5].is_equal_approx(Vector3(-1, -1, -1) * 1));
 | 
			
		||||
	CHECK(ep[6].is_equal_approx(Vector3(1, 1, -1) * 1));
 | 
			
		||||
	CHECK(ep[7].is_equal_approx(Vector3(1, -1, -1) * 1));
 | 
			
		||||
 | 
			
		||||
	persp.set_perspective(120, sqrt3, 0.8, 10, true);
 | 
			
		||||
	persp.get_endpoints(Transform3D(), ep);
 | 
			
		||||
 | 
			
		||||
	CHECK(ep[0].is_equal_approx(Vector3(-sqrt3, 1, -1) * 10));
 | 
			
		||||
	CHECK(ep[1].is_equal_approx(Vector3(-sqrt3, -1, -1) * 10));
 | 
			
		||||
	CHECK(ep[2].is_equal_approx(Vector3(sqrt3, 1, -1) * 10));
 | 
			
		||||
	CHECK(ep[3].is_equal_approx(Vector3(sqrt3, -1, -1) * 10));
 | 
			
		||||
	CHECK(ep[4].is_equal_approx(Vector3(-sqrt3, 1, -1) * 0.8));
 | 
			
		||||
	CHECK(ep[5].is_equal_approx(Vector3(-sqrt3, -1, -1) * 0.8));
 | 
			
		||||
	CHECK(ep[6].is_equal_approx(Vector3(sqrt3, 1, -1) * 0.8));
 | 
			
		||||
	CHECK(ep[7].is_equal_approx(Vector3(sqrt3, -1, -1) * 0.8));
 | 
			
		||||
 | 
			
		||||
	persp.set_perspective(60, 1.2, 0.5, 15, false);
 | 
			
		||||
	persp.get_endpoints(Transform3D(), ep);
 | 
			
		||||
 | 
			
		||||
	CHECK(ep[0].is_equal_approx(Vector3(-sqrt3 / 3 * 1.2, sqrt3 / 3, -1) * 15));
 | 
			
		||||
	CHECK(ep[1].is_equal_approx(Vector3(-sqrt3 / 3 * 1.2, -sqrt3 / 3, -1) * 15));
 | 
			
		||||
	CHECK(ep[2].is_equal_approx(Vector3(sqrt3 / 3 * 1.2, sqrt3 / 3, -1) * 15));
 | 
			
		||||
	CHECK(ep[3].is_equal_approx(Vector3(sqrt3 / 3 * 1.2, -sqrt3 / 3, -1) * 15));
 | 
			
		||||
	CHECK(ep[4].is_equal_approx(Vector3(-sqrt3 / 3 * 1.2, sqrt3 / 3, -1) * 0.5));
 | 
			
		||||
	CHECK(ep[5].is_equal_approx(Vector3(-sqrt3 / 3 * 1.2, -sqrt3 / 3, -1) * 0.5));
 | 
			
		||||
	CHECK(ep[6].is_equal_approx(Vector3(sqrt3 / 3 * 1.2, sqrt3 / 3, -1) * 0.5));
 | 
			
		||||
	CHECK(ep[7].is_equal_approx(Vector3(sqrt3 / 3 * 1.2, -sqrt3 / 3, -1) * 0.5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] LOD multiplier") {
 | 
			
		||||
	constexpr real_t sqrt3 = 1.7320508;
 | 
			
		||||
	Projection proj;
 | 
			
		||||
	real_t multiplier;
 | 
			
		||||
 | 
			
		||||
	proj.set_perspective(60, 1, 1, 40, false);
 | 
			
		||||
	multiplier = proj.get_lod_multiplier();
 | 
			
		||||
	CHECK(multiplier == doctest::Approx(2 * sqrt3 / 3));
 | 
			
		||||
 | 
			
		||||
	proj.set_perspective(120, 1.5, 0.5, 20, false);
 | 
			
		||||
	multiplier = proj.get_lod_multiplier();
 | 
			
		||||
	CHECK(multiplier == doctest::Approx(3 * sqrt3));
 | 
			
		||||
 | 
			
		||||
	proj.set_orthogonal(15, 20, 10, 12, 5, 15);
 | 
			
		||||
	multiplier = proj.get_lod_multiplier();
 | 
			
		||||
	CHECK(multiplier == doctest::Approx(5));
 | 
			
		||||
 | 
			
		||||
	proj.set_orthogonal(-5, 15, -8, 10, 1.5, 10);
 | 
			
		||||
	multiplier = proj.get_lod_multiplier();
 | 
			
		||||
	CHECK(multiplier == doctest::Approx(20));
 | 
			
		||||
 | 
			
		||||
	proj.set_frustum(1.0, 4.0 / 3.0, Vector2(0.5, -0.25), 0.5, 50, false);
 | 
			
		||||
	multiplier = proj.get_lod_multiplier();
 | 
			
		||||
	CHECK(multiplier == doctest::Approx(8.0 / 3.0));
 | 
			
		||||
 | 
			
		||||
	proj.set_frustum(2.0, 1.2, Vector2(-0.1, 0.8), 1, 10, true);
 | 
			
		||||
	multiplier = proj.get_lod_multiplier();
 | 
			
		||||
	CHECK(multiplier == doctest::Approx(2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("[Projection] Pixels per meter") {
 | 
			
		||||
	constexpr real_t sqrt3 = 1.7320508;
 | 
			
		||||
	Projection proj;
 | 
			
		||||
	int ppm;
 | 
			
		||||
 | 
			
		||||
	proj.set_perspective(60, 1, 1, 40, false);
 | 
			
		||||
	ppm = proj.get_pixels_per_meter(1024);
 | 
			
		||||
	CHECK(ppm == int(1536.0f / sqrt3));
 | 
			
		||||
 | 
			
		||||
	proj.set_perspective(120, 1.5, 0.5, 20, false);
 | 
			
		||||
	ppm = proj.get_pixels_per_meter(1200);
 | 
			
		||||
	CHECK(ppm == int(800.0f / sqrt3));
 | 
			
		||||
 | 
			
		||||
	proj.set_orthogonal(15, 20, 10, 12, 5, 15);
 | 
			
		||||
	ppm = proj.get_pixels_per_meter(500);
 | 
			
		||||
	CHECK(ppm == 100);
 | 
			
		||||
 | 
			
		||||
	proj.set_orthogonal(-5, 15, -8, 10, 1.5, 10);
 | 
			
		||||
	ppm = proj.get_pixels_per_meter(640);
 | 
			
		||||
	CHECK(ppm == 32);
 | 
			
		||||
 | 
			
		||||
	proj.set_frustum(1.0, 4.0 / 3.0, Vector2(0.5, -0.25), 0.5, 50, false);
 | 
			
		||||
	ppm = proj.get_pixels_per_meter(2048);
 | 
			
		||||
	CHECK(ppm == 1536);
 | 
			
		||||
 | 
			
		||||
	proj.set_frustum(2.0, 1.2, Vector2(-0.1, 0.8), 1, 10, true);
 | 
			
		||||
	ppm = proj.get_pixels_per_meter(800);
 | 
			
		||||
	CHECK(ppm == 400);
 | 
			
		||||
}
 | 
			
		||||
} //namespace TestProjection
 | 
			
		||||
 | 
			
		||||
#endif // TEST_PROJECTION_H
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user