-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Don't automatically compute Aabb components for skinned meshes.
#21787
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
Conversation
Currently, Bevy automatically computes AABBs for all meshes, even those that have skins or morph targets. This is incorrect, as each skin and/or morph target can deform the mesh arbitrarily. This is not a theoretical problem, as Maya relies on rest poses to position and rotate meshes that are children of skins. Right now, the only way to disable this Bevy feature is to add the `NoFrustumCulling` component, or to overwrite the generated `Aabb` with a different one. Neither are a particularly good experience: 1. Adding `NoFrustumCulling` is impossible when loading a glTF scene, and it's also not obvious that `NoFrustumCulling` is needed to correctly render skinned meshes sometimes. 2. Overwriting the `Aabb` is cumbersome. This commit changes Bevy's behavior to not generate `Aabb` components for skinned meshes, fixing the issue. Note that, to keep this patch small, morph targets aren't handled yet. The documentation has been updated to inform developers that they may wish to add `Aabb` components manually to skinned meshes in order to opt in to frustum culling.
|
Some open questions:
I'm not against this PR, don't get me wrong. Our default behavior is blatantly wrong and needs to go. I remember how confused I was when I first ran into disappearing meshes due to it. Also requesting reviews from Greeble, as they wrote the crate linked above, and James, who I remember wanted to change the skinned mesh AABB behavior at some point too and has some thoughts on what to replace it with |
|
Ok, so looking at what Unity does more closely, it seems that Unity can do something similar to My inclination is:
I don’t have time to implement the Unity thing, but I can scale this patch back to be an opt in “don’t compute AABBs for skinned meshes” option on the glTF loader if we feel that’d be the right thing. |
|
Good assessment. I'm not sure if it's better to
I'll leave that decision to the maintainers. PR looks good other than that decision :) |
tychedelia
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm agnostic about the follow up but this is fine as unbreaking the status quo.
|
From a glance, Godot seems to do what I'm persuaded that this patch should be pared down to be an opt-in (or opt-out?) option on the glTF loader that disables automatic AABB generation for skinned meshes and inserts This patch should wait to land until I can make that change. |
|
I checked the UE source and it uses a If no |
|
Gonna add a few notes although they're kinda tangential to this PR. I think that this PR is the practical choice right now - either the current version or the pared down alternative.
(EDIT: Oops, I didn't see NicoZweifel's comment before posting this, but I'll leave my notes for reference) Unreal defaults to creating collision shapes for joints during mesh import. These are used to calculate the culling bounds, even if they're not instantiated in the physics system. So it's like
My hot take on this is that the juice isn't worth the squeeze - as you mentioned there's a bunch of reasons it's awkward and unreliable. Side note in case it's useful: for most humanoid character rigs - i.e. rigs where joints below the pelvis usually only rotate - there's a simple approximation. For each leaf joint, sum its length and the lengths of all its ancestors, then take the maximum of this value across all leaf joints, and attach an AABB/sphere of that size to the pelvis. In practice this is a bit bigger than an AABB calculated from animations, but way simpler.
I would be mildly negative on upstreaming bevy_mod_skinned_aabb in its current form. It's a bit too hacky and unreliable (e.g. breaks if meshes are not I would also like to do an in-engine version that's reliable and more performant. But it's kinda awkward to do right now. The main issues are:
This situation could change. Maybe the render world gets removed, maybe the culling system gets redesigned, maybe WebGL is dropped and GPU culling is the default. And after the dust has settled my job could be easier. But for now I'm waiting to see what happens. I can expand on these reasons if any render folks want to chew it over.
I understand the hesitation, but I would advocate for it to be the default - so static AABBs would be an optional optimisation for sophisticated users. I think per-joint bounds are cheaper than many people expect, and the value of making (non-morph) skinned meshes reliable is very high. There's also some hybrid approaches that trade off reliability for performance, like approximating faces and hands with a single bound. If upstreaming moves forward then I'll provide more details and concrete performance numbers. |
|
@greeble-dev regarding upstreaming: certainly these limitations are better than the status quo? Especially since e.g. not using the right world simply defaults to not generating an AABB, which is not worse than what we have now. |
I would agree, but I think there's a decent chance that maintainers might disagree, or the PR would stall over performance doubts. Particularly if this PR lands and things (kinda sorta) work by default. So for now the cost/benefit isn't there for me. But I can change my mind if there's an indication that maintainers will be ok with an unreliable/inefficient version. |
|
I'm fine WRT almost any solution here, and would prefer to merge a fix. Off-screen performance issues are less bad than meshes suddenly vanishing.
This is my preferred long-term solution, but I won't block on it in this PR and would prefer to land a simple fix first. |
|
So @janhohenheim's comment kinda guilted me into taking another look at upstreaming options for bevy_mod_skinned_aabb, and I think I have a compromise with a reasonable chance of landing. It's a bit simpler and more reliable, but less accurate. I expect to file a PR later this week - sneak preview here: 11b3a8d. I don't think my PR will necessarily conflict with this PR or other alternatives. I would advocate for my PR to be the default behaviour, but that's not a requirement, and either way the alternatives should still be available as an option. |
|
@greeble-dev I'm quite happy to close this in favor of your solution, and review your solution, if you submit the PR. Honestly, I just want some solution here--I have no strong opinions as to what in particular we do. What I'm working on is a band-aid solution that simply takes the rest pose into account when computing the AABB at import time and nothing else. This is still wrong, but better than what we do, and should be uncontroversial as more or less a strict improvement on what we currently do. However, if you're going to submit a better solution I'm happy to hold off. |
|
@greeble-dev oh no, I certainly didn't want to guilt you ❤️ |
|
@pcwalton, please bother me when you're happy with a bandaid solution :) I'll be happy to take a final look and likely merge it in. |
|
I've filed my PR: #21837. It's only a draft and doesn't require a detailed review right now, but does need feedback like "is this the right approach?" and "should it be enabled by default?". My PR supercedes this PR in its current state. But if @pcwalton adds the rest pose option then I'd expect to incorporate that into the options I've added. /// Controls the bounds related components that are assigned to skinned mesh
/// entities. These components are used by systems like frustum culling.
pub enum GltfSkinnedMeshBoundsPolicy {
/// Skinned meshes are assigned an `Aabb` component calculated from the bind
/// pose `Mesh`.
BindPose,
/// Skinned meshes are assigned a `SkinnedMeshBounds` component, which will
/// be used by the `bevy_camera` plugin to update the `Aabb` component
/// based on joint positions.
Dynamic,
/// Same as `BindPose`, but also assign a `NoFrustumCulling` component. That
/// component tells the `bevy_camera` plugin to avoid frustum culling the
/// skinned mesh.
NoFrustumCulling,
}
|
meshes in glTF files. In glTF, the joints of a skinned mesh aren't required to have identity transforms for the rest pose. In particular, Maya likes to place skinned meshes at the origin and then uses joint transforms to move them into place. At present, the Bevy glTF loader naively assumes that the minimum and maximum values of the `POSITION` accessor suffice to determine the bounding box of a mesh, but for skinned meshes with non-identity joint transforms this is not true. This could cause Bevy to apply incorrect `Aabb` components to skinned meshes, which would in turn cause those meshes to be incorrectly frustum culled and disappear. This PR fixes the issue by constructing the AABBs manually for skinned meshes in glTF files. When computing these AABBs, this patch takes the rest pose into account, fixing the issue. For non-skinned meshes, this patch makes Bevy continue to use the precomputed minimum and maximum values of the `POSITION` accessor, as this is safe. Note that this patch *doesn't* fix all possible causes of incorrect AABBs. In particular, animation of skins and morph targets can still cause meshes to extend outside their AABBs and be incorrectly culled. The [`bevy_mod_skinned_aabb`] plugin can compute per-joint AABBs that remain correct in the presence of animation, at some CPU cost. Alternately, developers may wish to manually extend AABBs for skinned meshes as necessary to include all possible animations by modifying the automatically-generated `Aabb` component, or even remove the `Aabb` component altogether. Additionally, this patch doesn't handle the case in which a mesh and joints are manually constructed outside of glTF. In this case, the `bevy_camera::visibility::calculate_bounds` system will generate an incorrect AABB for the mesh. I intentionally left that out of this patch, because regenerating AABBs on CPU whenever a joint is updated would be slow; [`bevy_mod_skinned_aabb`] would be a better approach. Besides, constructing skinned meshes programmatically is rare, and glTF is much more commonly used in practice. For comparison, Unreal and Godot use a technique similar to [`bevy_mod_skinned_aabb`] to generate AABBs. Unity can either use that technique or, by default, simply widens the AABB to encompass not only the rest pose but also all animations in the imported FBX file. We could implement that if desired in a follow-up. This PR obsoletes bevyengine#21787, which removed `Aabb` components entirely for skinned meshes. The current patch is a more aggressive approach that, while not foolproof, strictly improves the situation in common cases while maintaining automatic frustum culling support for skinned meshes in general. [`bevy_mod_skinned_aabb`]: https://github.com/greeble-dev/bevy_mod_skinned_aabb
|
Closed in favor of #21845. |
Currently, Bevy automatically computes AABBs for all meshes, even those that have skins or morph targets. This is incorrect, as each skin and/or morph target can deform the mesh arbitrarily. This is not a theoretical problem, as Maya relies on rest poses to position and rotate meshes that are children of skins.
Right now, the only way to disable this Bevy feature is to add the
NoFrustumCullingcomponent, or to overwrite the generatedAabbwith a different one. Neither are a particularly good experience:Adding
NoFrustumCullingis impossible when loading a glTF scene, and it's also not obvious thatNoFrustumCullingis needed to correctly render skinned meshes sometimes.Overwriting the
Aabbis cumbersome.This commit changes Bevy's behavior to not generate
Aabbcomponents for skinned meshes, fixing the issue. Note that, to keep this patch small, morph targets aren't handled yet. The documentation has been updated to inform developers that they may wish to addAabbcomponents manually to skinned meshes in order to opt in to frustum culling.Fixes #4971.