-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Animated meshes disapear if their original position is not within the field of view #4971
Comments
A simple starting point might be to use a conservative bounding sphere of the longest bone chain to generate an AABB: |
This also causes raycast to work incorrectly for animated meshes (because actual mesh could be in a different location). |
The problem with raycasting is double:
If you content yourself with CPU-side raycasting, you'll have to accept either ridiculous performance loss or inaccurate (too broad) collision detection. But there is a way! This is where GPU picking is useful. GPU picking constructs a buffer with individual ID per entity, you can then read that buffer for the pixel under the cursor, and you have the picked entity! Issue is I don't think someone has yet made a GPU picking implementation in bevy. |
As a note, I had a GPU picking impl that worked with skinned meshes as well a while ago: #6991 it is superseded by @IceSentry 's PR here: #8784 I see the most recent comment there by @mtsr is to consider having GPU picking as a pre-pass. |
Workaround snippet, for convenience: use bevy::{
prelude::*,
render::{mesh::skinning::SkinnedMesh, view::NoFrustumCulling},
};
/// System that automatically disables frustum culling for
/// all skinned meshes, as soon as they are added to the world.
fn disable_culling_for_skinned_meshes(
mut commands: Commands,
skinned: Query<Entity, Added<SkinnedMesh>>,
) {
for entity in &skinned {
commands.entity(entity).insert(NoFrustumCulling);
}
} Then just add it as a system: fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Update, disable_culling_for_skinned_meshes);
} |
This issue doesn't occur solely with animations. It occurs with any type of entity that has a skeleton animation. In my case scenario, I have a player following camera. And if i stop looking at the mesh boom, no rendering. Or shift the orbit in y boom half rendering. |
This took me a while to figure out today. Until a proper solution is landed on, it would be nice to disable frustum culling for skinned meshes by default. This seems like it would affect almost every 3d game, and can be a bit of a head scratcher. |
I've made a standalone plugin that mostly works around this issue but has some drawbacks. I think the plugin could be the foundation of an engine fix, but my path to a PR is unclear. I'm going to lay out some notes below and see if there's any feedback. SummaryThe plugin finds entities with skinned meshes, adds a new component+asset with per-joint AABBs, then uses them to re-calculate the mesh's AABB every frame. This approach is robust - as in the mesh is guaranteed to be within the AABB - as long as the mesh's vertices are only driven by linear blend skinning (no blend shapes or vertex shader shenanigans). skinned_aabb.mp4So, why not just add this plugin to the engine's default plugins? There's two key issues:
There's a few other smaller concerns but I'll skip them for now. Issue 1: Per-Frame PerformanceI've benchmarked the plugin on many_foxes, and my hand-wavey conclusion is "enabling skinned AABBs multiplies the main app CPU cost of a mesh playing a single animation by 1.04x". Alternatively, "on a mid-range desktop CPU, each skinned joint costs an extra 8ns". More detailed notes are here. Is 1.04x is a fair price for fixing a common problem users have with skinned meshes? I'd say yes. There's also ways to optimise:
Also worth noting that some people are working around the original issue by disabling frustum culling. This increases renderer and GPU costs, so they might find switching to skinned AABBs is a performance win. Issue 2: Asset PipelineThe plugin calculates the per-joint AABBs from the mesh vertices at runtime - also requiring the mesh vertex data to be kept in the main world asset - and has to continually check for new meshes. A real fix should allow all this to be done at asset import time. In the long-term my guess is that the Bevy mesh pipeline will become more modular and extensible, so adding a skinned AABB calculation in the right place will be easy. But in the short-term, my guess is that most Bevy projects are instantiating scenes directly from GLTF files. We'd need a temporary solution that modifies the GLTF importer. Solution 1: Add a GLTF extension to store the skinned AABB data and create a tool for users to pre-process their GLTFs. Annoying for users and the solution is likely to be thrown away at some point. Solution 2: Extend the GLTF importer to calculate the skinned AABB data while loading. Has a small load time performance cost and will require some moderate refactoring of the importer. But is simple for users, and the refactoring might align with other proposals to modularise the pipeline (#13681). Eventually the code would migrate out of the GLTF importer and into a pipeline module. What Do Other Engines Do?Most game engines have a "fixed size AABB attached to the root bone" path for skinned meshes. Some have approximations that look at other joints, but none are robust.
What Next?Right now I'm considering two paths:
If there's positive vibes around changing the GLTF importer then I'd likely choose that path. |
Bevy version
cdb62af (main as of 2022-06-09)
What you did
I've a giraffe where the eyes are a different mesh from the rest of the body, and when the neck moves enough, it's possible that the eyes after application of animations are so far away from their initial position that the engine thinks it's outside of frustum, while they should be within view, and doesn't render them.
Video demonstrating the bug:
giraffe-model-disapear.mp4
As you can observe, the blue eyes disappear if the original eye position are not within the field of view.
The rest of the mesh (skin) also disappear when the camera view doesn't include the original mesh's position.
Additional information
This is because entity mesh AABBs are not computed based on the animation. The animation shader runs on the GPUs, while AABB filtering runs on CPU before anything is sent to the GPU. There is no way for bevy to filter meshes based on the animation position.
This seems to be something barely possible if not impossible to fix within bevy. Suggestions include:
Workaround
There are two options if you hit this issue:
NoFrustrumCulling
component to the entities which mesh disappear because of animation.Aabb
manually so that it can cover the full range of possible visible position for the model. (note that this workaround might break when [Merged by Bors] - Recalculate entity aabbs when meshes change #4944 lands)The text was updated successfully, but these errors were encountered: