-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix panic when a mesh has skinning attributes but no SkinnedMesh component
#18074
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
base: main
Are you sure you want to change the base?
Fix panic when a mesh has skinning attributes but no SkinnedMesh component
#18074
Conversation
…fixed forward mode missing passes required for motion blur.
- Removed render mode cycling and motion blur toggling - all renderer paths can be tested just by enabling motion blur. - Added a text overlay documenting each mesh. - Various tidy ups.
…h for whether a mesh is skinned. This meant adding `MeshPipelineKey::SKINNED`. - Fixed warning spam by making `extract_skins` check if the mesh has skinning attributes. - Fixed panic when using uniform buffers for skinning. If `SkinUniforms::current_buffer` is grown the `SkinUniforms::prev_buffer` should grow too.
| size: new_size, | ||
| mapped_at_creation: false, | ||
| }); | ||
| // TODO: This is wrong. We should be using last frame's data for prev_buffer. |
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.
Awkward TODO - see "Previous Buffers Too Small" section.
Let's drop that; the rest of this is a clear improvement that we shouldn't let get bogged down. |
… but no skinning attributes.
|
I've reverted the attribute checks in I'll investigate using |
|
I've changed the specialize systems to take a Note that the struct is |
|
I've pulled one of the fixes out to #18715. Also put this PR into draft mode - once the other PR shakes out I'll need to update the description and fix conflicts. |
## Objective Fix motion blur not working on skinned meshes. ## Solution `set_mesh_motion_vector_flags` can set `RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN` after specialization has already cached the material. This can lead to `MeshPipelineKey::HAS_PREVIOUS_SKIN` never getting set, disabling motion blur. The fix is to make sure `set_mesh_motion_vector_flags` happens before specialization. Note that the bug is fixed in a different way by #18074, which includes other fixes but is a much larger change. ## Testing Open the `animated_mesh` example and add these components to the `Camera3d` entity: ```rust MotionBlur { shutter_angle: 5.0, samples: 2, #[cfg(all(feature = "webgl2", target_arch = "wasm32", not(feature = "webgpu")))] _webgl2_padding: Default::default(), }, #[cfg(all(feature = "webgl2", target_arch = "wasm32", not(feature = "webgpu")))] Msaa::Off, ``` Tested on `animated_mesh`, `many_foxes`, `custom_skinned_mesh`, Win10/Nvidia with Vulkan, WebGL/Chrome, WebGPU/Chrome. Note that testing `many_foxes` WebGL requires #18715.
## Objective Fix motion blur not working on skinned meshes. ## Solution `set_mesh_motion_vector_flags` can set `RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN` after specialization has already cached the material. This can lead to `MeshPipelineKey::HAS_PREVIOUS_SKIN` never getting set, disabling motion blur. The fix is to make sure `set_mesh_motion_vector_flags` happens before specialization. Note that the bug is fixed in a different way by #18074, which includes other fixes but is a much larger change. ## Testing Open the `animated_mesh` example and add these components to the `Camera3d` entity: ```rust MotionBlur { shutter_angle: 5.0, samples: 2, #[cfg(all(feature = "webgl2", target_arch = "wasm32", not(feature = "webgpu")))] _webgl2_padding: Default::default(), }, #[cfg(all(feature = "webgl2", target_arch = "wasm32", not(feature = "webgpu")))] Msaa::Off, ``` Tested on `animated_mesh`, `many_foxes`, `custom_skinned_mesh`, Win10/Nvidia with Vulkan, WebGL/Chrome, WebGPU/Chrome. Note that testing `many_foxes` WebGL requires #18715.
## Objective Fix #18714. ## Solution Make sure `SkinUniforms::prev_buffer` is resized at the same time as `current_buffer`. There will be a one frame visual glitch when the buffers are resized, since `prev_buffer` is incorrectly initialised with the current joint transforms. Note that #18074 includes the same fix. I'm assuming this smaller PR will land first. ## Testing See repro instructions in #18714. Tested on `animated_mesh`, `many_foxes`, `custom_skinned_mesh`, Win10/Nvidia with Vulkan, WebGL/Chrome, WebGPU/Chrome.
## Objective Fix #18714. ## Solution Make sure `SkinUniforms::prev_buffer` is resized at the same time as `current_buffer`. There will be a one frame visual glitch when the buffers are resized, since `prev_buffer` is incorrectly initialised with the current joint transforms. Note that #18074 includes the same fix. I'm assuming this smaller PR will land first. ## Testing See repro instructions in #18714. Tested on `animated_mesh`, `many_foxes`, `custom_skinned_mesh`, Win10/Nvidia with Vulkan, WebGL/Chrome, WebGPU/Chrome.
## Objective Add a test that would have caught #16929 and #18712. ## Solution The PR adds a `test_invalid_skinned_mesh` example that creates various valid and invalid skinned meshes. This is designed to catch panics via CI, and can be inspected visually. It also tests skinned meshes + motion blur.  The screenshot shows all the tests, but two are currently disabled as they cause panics. #18074 will re-enable them. ### Concerns - The test is not currently suitable for screenshot comparison. - I didn't add the test to CI. I'm a bit unsure if this should be part of the PR or a follow up discussion. - Visual inspection requires understanding why some meshes are deliberately broken and what that looks like. - I wasn't sure about naming conventions. I put `test` in the name so it's not confused with a real example. ## Testing ``` cargo run --example test_invalid_skinned_mesh ``` Tested on Win10/Nvidia, across Vulkan, WebGL/Chrome, WebGPU/Chrome.
PR is in draft mode as it needs to be redone following other changes. Currently waiting on #18762 to land.
Objective
SkinnedMeshcomponent.SkinnedMeshcomponent but mesh has no skinning attributes).many_foxes).Summary
My goal was to fix #16929 - a wgpu panic when a mesh with skinning attributes is instantiated as a
Mesh3dbut without aSkinnedMeshcomponent.The problem was:
setup_morph_and_skinning_defschooses a skinning bind group layout if the mesh has skinning attributes.SetMeshBindGroup::renderchooses a skinning bind group if the mesh is inskin_uniforms.skin_uniforms(because it doesn't have aSkinnedMeshcomponent).The fix is to make
skin_uniformsthe source of truth.This was mostly the case already - the exception was
setup_morph_and_skinning_defs. So I changed the pipeline specialization functions to checkskin_uniforms, set a newMeshPipelineKey::SKINNED, and then pick that up insetup_morph_and_skinning_defs.While working this through I noticed a few more issues.
Incorrect Pipeline Caches
The pipeline specialization used
RenderMeshInstanceFlags::HAS_PREVIOUS_SKINto decide if the mesh needed motion blur. But that flag is set by theset_mesh_motion_vector_flagssystem, which can run after specialization. So in some cases the wrong pipeline was cached and skinned meshes had no motion blur.This is fixed as a side effect of using
skin_uniformsas the source of truth. It also meansRenderMeshInstanceFlags::HAS_PREVIOUS_SKINcan be removed, andset_mesh_motion_vector_flagsno longer has to iterate over all skinned entities.The bad news is that
HAS_PREVIOUS_MORPHfollows a similar pattern, so I suspect motion blur is broken on morph targets in some cases.Previous Buffers Too Small
When testing with
skins_use_uniform_buffersforced on I got a panic aboutSkinUniforms::prev_bufferbeing too small for the mapped range. I think the problem is thatprepare_skinsgrowscurrent_bufferwithout also growingprev_buffer, so it's too small for one frame.I've changed
prepare_skinsto grow both buffers. However, this will cause a single frame visual glitch as the newprev_bufferis initialised with the current frame's joints. For now I think reducing a panic to a glitch is sufficient.I suspect there's also a bug where
prev_bufferhas wrong transforms the first frame after a skin is added. And at the last minute I realisedMeshPipelineKey::HAS_PREVIOUS_SKINis probably obsolete, since all skins now have a previous. I might chase these down in a follow-up PR.System Parameter Limits
When adding a
skin_uniformsparameter to systems likespecialize_material_meshesI hit a limit on the number of parameters. I fixed this by moving some parameters into aSystemParamshared between specialize systems (85d1a00).New Test
The PR adds a test that repros most of the issues. It's designed to be run on CI to detect panics, but can be visually inspected as well. I haven't actually added it to the CI - I wasn't sure whether to do that in this PR or a follow-up.
The test currently spams warnings as it repros a bug not addressed by this PR (
SkinnedMeshwithout skinning attributes - the inverse of #16929).Follow Ups
#9360 made the glTF importer try to skip any meshes that would triggered the bug. Arguably this is no longer necessary, but that's best handled in a separate PR as it may be contentious.
Performance
Tested with
many_foxes. The cost ofset_mesh_motion_vector_flagsis much reduced (8.97us -> 0.3us).Testing
Tested on Win10/Vulkan/Nvidia, Wasm/Chrome/WebGL2/Nvidia.