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

Add support for infinite projection matrices #10515

Open
Flarkk opened this issue Aug 21, 2024 · 2 comments · May be fixed by godotengine/godot#99986
Open

Add support for infinite projection matrices #10515

Flarkk opened this issue Aug 21, 2024 · 2 comments · May be fixed by godotengine/godot#99986

Comments

@Flarkk
Copy link

Flarkk commented Aug 21, 2024

Describe the project you are working on

A space settled 3D game where both very far away celestial bodies and closer objects (terrains, spaceships ...) are rendered at the same time.

Describe the problem or limitation you are having in your project

I need both a normal near plane distance (say 5e-2) and a far plane very far away (say 1e18, or even INF).
When near and far planes are apart from each other of an order of magnitude greater than ~1e7, an error is raised at culling and the scene doesn't render.

Worth noting that now Reverse z-buffer is a reality, it opens the door in theory to rendering such deep scenes without z-fighting (especially when objects are spaced and sized exponentially, like stars, planets and ground objects), and without having to rely on heavier solutions like rendering in multiple passes or multiple cameras.

In detail, when near and far places are set very far apart, the projection matrix generated rounds to an infinite projection matrix (see slide 7) due to numerical precision effects.
At scene culling stage, the 6 clipping plans are extracted from the matrix following the popular Ggribb's method (see Projection::get_projection_planes(). This yields by construction a zero vector for the far plane normal when the projection matrix is infinite.
This zero vector raises an error later during the light culling preparation.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Support infinite far planes on Camera3D in PROJECTION_PERSPECTIVE, PROJECTION_FRUSTUM and PROJECTION_ORTHOGONAL modes.
This should be supported for both scene culling and geometry projection.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Because the near and far distances are used for both scene culling and geometry projection, they are 2 potential changes to consider :

  1. Default to infinite projection matrix for geometry projection
    There is some litterature on the fact that combining infinite projection with reverse-z doesn't degrade numerical error rates, even with scenes where geometry is not far away (see this one : https://developer.nvidia.com/content/depth-precision-visualized and that one : https://www.reedbeta.com/blog/depth-precision-visualized/).
    In practice, this would mean that for PROJECTION_PERSPECTIVE, PROJECTION_FRUSTUM and PROJECTION_ORTHOGONAL, the far distance value provided by the user is ignored and an infinite projection matrix is generated regardless.

  2. Allow ignoring far distance for scene culling
    There could be a new boolean attribute on Camera3D to allow the user to toggle it on/off.
    When toggled on, Projection::get_projection_planes() could branch and generate an adequate normal and distance-to-origin for the far plane.
    I tested this scrappy implementation and at first sight it seems to work :

///////--- Far Plane ---///////
if (ignore_far_plane_for_culling) {
	/* Take the opposite of the near plane's normal.
	    Assumption is made they're parallel.
	    As godot currently doesn't allow the user to build the projection matrix from scratch,
	    there shouldn't be any edge case */
	new_plane.normal = -planes[0].normal;
	new_plane.d = INFINITY; // distance is infinity
} else {
	new_plane = Plane(matrix[3] - matrix[2],
		matrix[7] - matrix[6],
		matrix[11] - matrix[10],
		matrix[15] - matrix[14]);

	new_plane.normal = -new_plane.normal;
	new_plane.normalize();
}

planes.write[1] = p_transform.xform(new_plane);

Alternatively, if we don't want to go down the route of defaulting to infinite projection, there could be additional projection modes added to Camera3D, say PROJECTION_PERSPECTIVE_INFINITE, PROJECTION_FRUSTUM_INFINITE and PROJECTION_ORTHOGONAL_INFINITE, that would trigger both changes above.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No, it's core

Is there a reason why this should be core and not an add-on in the asset library?

Culling and projection are core.

@Flarkk Flarkk changed the title Infinite projection matrices support Infinite projection matrix support Aug 21, 2024
@Calinou Calinou changed the title Infinite projection matrix support Add support for infinite projection matrices Aug 21, 2024
@Calinou
Copy link
Member

Calinou commented Aug 21, 2024

Alternatively, if we don't want to go down the route of defaulting to infinite projection, there could be an additional projection mode added to Camera3D, say PROJECTION_PERSPECTIVE_INFINITE, that would trigger both changes above.

What about the Orthogonal and Frustum modes? It seems these could support an infinite far distance too.

@Flarkk
Copy link
Author

Flarkk commented Aug 22, 2024

Correct. Just updated my proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants