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

Use distance to AABB surface to calculate Mesh LOD instead of using supports #92290

Merged
merged 1 commit into from
Sep 16, 2024

Conversation

clayjohn
Copy link
Member

@clayjohn clayjohn commented May 23, 2024

Fixes: #81995
Fixes: #76436

Supersedes #82000

Builds on #92287 but introduces riskier changes.

This PR simplifies and improves the LOD selection logic by calculating the depth as the distance to the closest point on the surface of the AABB.

The old logic used the camera z direction to calculate the min and max supports. This was flawed as it meant that rotating the camera could drastically change which supports were chosen and (as pointed out in #81995) if the camera looked slightly past an AABB, it could cause the supports to change and then jump LOD levels.

The new code automatically handles being inside the AABB (distance will always be 0 inside the AABB) and gradually increases from 0 at the surface of the AABB so there is no snapping like with the first draft of this PR.

I also moved the entire calculation outside the loop since everything depends on the instance. It doesn't need to be recalculated for each surface.

@Calinou Calinou added this to the 4.x milestone May 23, 2024
@akien-mga akien-mga changed the title Lod fixes Use direction between camera origin and AABB center to calculate minimum support for LOD selection May 29, 2024
@huwpascoe
Copy link
Contributor

Linking the MRP I created for testing LOD since it's quite useful:

multimesh_lod_mrp.zip

image

Copy link
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

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

Tested locally (rebased on top of master 568589c), it doesn't seem to work as expected with @huwpascoe's MRP. I still get sudden unexpected LOD level changes when the camera moves at certain positions (e.g. going from a low LOD level to full resolution LOD instantly).

Also, in general, the LOD level regularly decreases even though my camera is getting closer to the MultiMeshInstance3D's center, which doesn't make sense to me.

master

lod_selection_before.mp4

This PR

lod_selection_after.mp4

This makes me wonder if the full resolution LOD should always be used if the camera's AABB is inside the MultiMeshInstance's AABB. This will be slower, but it ensures one instance from the MultiMeshInstance3D will never look bad if it's right in front of you, no matter how isolated it is from the rest (or whether it's near the edges or at the center of the MultiMeshInstance3D).

A less extreme approach could be to clamp the LOD selection for MultiMeshInstance3Ds when the camera is inside its bounds (e.g. use only the two most detailed LOD levels to avoid too much discrepancy).

@clayjohn
Copy link
Member Author

clayjohn commented Aug 23, 2024

This makes me wonder if the full resolution LOD should always be used if the camera's AABB is inside the MultiMeshInstance's AABB. This will be slower, but it ensures one instance from the MultiMeshInstance3D will never look bad if it's right in front of you, no matter how isolated it is from the rest (or whether it's near the edges or at the center of the MultiMeshInstance3D).

That's how the PR currently works. If the camera is inside the AABB then the most detailed LOD is always used.

Do you know if the AABB in this MRP actually covers all the instances? Depending on how it was created it might not fit the instances very well

e.g. going from a low LOD level to full resolution LOD instantly).

This could be from crossing the AABB threshold.

I think we may need to do distance to the closest point on the surface of the AABB. The old logic computes distance to the nearest corner. But I think to fully resolve all issues unfortunately we may need to do the distance to the nearest point on the surface. That will be a more complex calculation.

@huwpascoe
Copy link
Contributor

Do you know if the AABB in this MRP actually covers all the instances? Depending on how it was created it might not fit the instances very well

Well it's just the automatic AABB that's generated with the multimesh?
image

@huwpascoe
Copy link
Contributor

Found an algorithm:

float aabb_dist(vec3 p_point, vec3 p_min, vec3 p_max) {
    float dist_sq = 0.0;

    for (int i = 0; i < 3; ++i) {
        if (p_point[i] < p_min[i]) {
            float d = p_point[i] - p_min[i];
            dist_sq += d * d;
        }
        else if (p_point[i] > p_max[i]) {
            float d = p_point[i] - p_max[i];
            dist_sq += d * d;
        }
    }

    return sqrt(dist_sq);
}

Can probably replace that entire section, certainly reduces the number of conditionals. Could go one further and store LOD keys as distance squared and avoid the sqrt.

@huwpascoe
Copy link
Contributor

Regarding comments in the meeting:

  • AABB does in fact store coordinates in a min max format. Only it's called position and size respectively.
  • The sqrt is correct because of how vector3.length is calculated length = sqrt(x*x+y*y+z*z), the sqrt can be deferred to the sum of all the lengths
  • The sqrt can be avoided entirely if the LOD keys are also stored in squared form, but that's at @clayjohn's discretion.

Yes the algorithm seems to work as advertised.
https://gist.github.com/huwpascoe/6d8beba40cec02f4967a2aac33eef92a
image

@clayjohn
Copy link
Member Author

Pushed an update with calculation to surface of the AABB instead of using the support.

I didn't use the formula from huwpascoe, but instead used one that does the same thing mathematically but is branchless.

Overall, the number of calculations are significantly reduced from the previous state and the results are much more accurate.

I think this is ready for merging now. I have tested it with a few MRPs from previous issues and it appears to work the same or better in all cases.

@clayjohn clayjohn marked this pull request as ready for review September 11, 2024 21:23
@clayjohn clayjohn requested a review from a team as a code owner September 11, 2024 21:23
@clayjohn clayjohn modified the milestones: 4.x, 4.4 Sep 11, 2024
@huwpascoe
Copy link
Contributor

Can confirm it works, entirely consistent with distance to the AABB!

image
Moved the control to the corner of the multimesh AABB for the distances to match

@clayjohn clayjohn changed the title Use direction between camera origin and AABB center to calculate minimum support for LOD selection Use distance to AABB surface to calculate Mesh LOD instead of using supports Sep 13, 2024
@akien-mga akien-mga merged commit 8c6210a into godotengine:master Sep 16, 2024
20 checks passed
@akien-mga
Copy link
Member

Thanks!

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