Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify and fix Projection's getter functions #100209

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 45 additions & 100 deletions core/math/projection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.0f * (-get_z_near() * columns[2][3] + columns[3][3]) / columns[0][0];
return int(p_for_pixel_width / width); // The cast to int should be removed at some point (kept 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.0f / columns[0][0];
}

void Projection::make_scale(const Vector3 &p_scale) {
Expand Down
2 changes: 1 addition & 1 deletion doc/classes/Projection.xml
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,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">
Expand Down
Loading