Simplify and fix Projection's getter functions

This commit is contained in:
Florent Guiocheau
2024-12-07 15:12:32 +01:00
parent b9437c3938
commit 1d416fc2ba
3 changed files with 234 additions and 102 deletions

View File

@@ -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) {