Path: blob/main/crates/bevy_gizmos/src/skinned_mesh_bounds.rs
9445 views
//! A module adding debug visualization of [`DynamicSkinnedMeshBounds`].12use bevy_app::{Plugin, PostUpdate};3use bevy_asset::Assets;4use bevy_camera::visibility::DynamicSkinnedMeshBounds;5use bevy_color::Color;6use bevy_ecs::{7component::Component,8query::{With, Without},9reflect::ReflectComponent,10schedule::IntoScheduleConfigs,11system::{Query, Res},12};13use bevy_math::Affine3A;14use bevy_mesh::{15mark_3d_meshes_as_changed_if_their_assets_changed,16skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},17Mesh, Mesh3d,18};19use bevy_reflect::{std_traits::ReflectDefault, Reflect};20use bevy_transform::{components::GlobalTransform, TransformSystems};2122use crate::{23config::{GizmoConfigGroup, GizmoConfigStore},24gizmos::Gizmos,25AppGizmoBuilder,26};2728/// A [`Plugin`] that provides visualization of entities with [`DynamicSkinnedMeshBounds`].29pub struct SkinnedMeshBoundsGizmoPlugin;3031impl Plugin for SkinnedMeshBoundsGizmoPlugin {32fn build(&self, app: &mut bevy_app::App) {33app.init_gizmo_group::<SkinnedMeshBoundsGizmoConfigGroup>()34.add_systems(35PostUpdate,36(37draw_skinned_mesh_bounds,38draw_all_skinned_mesh_bounds.run_if(|config: Res<GizmoConfigStore>| {39config40.config::<SkinnedMeshBoundsGizmoConfigGroup>()41.142.draw_all43}),44)45.after(TransformSystems::Propagate)46.ambiguous_with(mark_3d_meshes_as_changed_if_their_assets_changed),47);48}49}50/// The [`GizmoConfigGroup`] used for debug visualizations of entities with [`DynamicSkinnedMeshBounds`]51#[derive(Clone, Reflect, GizmoConfigGroup)]52#[reflect(Clone, Default)]53pub struct SkinnedMeshBoundsGizmoConfigGroup {54/// When set to `true`, draws all the bounds that contribute to skinned mesh55/// bounds.56///57/// To draw a specific entity's skinned mesh bounds, you can add the [`ShowSkinnedMeshBoundsGizmo`] component.58///59/// Defaults to `false`.60pub draw_all: bool,61/// The default color for skinned mesh bounds gizmos.62pub default_color: Color,63}6465impl Default for SkinnedMeshBoundsGizmoConfigGroup {66fn default() -> Self {67Self {68draw_all: false,69default_color: Color::WHITE,70}71}72}7374/// Add this [`Component`] to an entity to draw its [`DynamicSkinnedMeshBounds`] component.75#[derive(Component, Reflect, Default, Debug)]76#[reflect(Component, Default, Debug)]77pub struct ShowSkinnedMeshBoundsGizmo {78/// The color of the bounds.79///80/// The default color from the [`SkinnedMeshBoundsGizmoConfigGroup`] config is used if `None`,81pub color: Option<Color>,82}8384fn draw(85color: Color,86mesh: &Mesh3d,87mesh_assets: &Res<Assets<Mesh>>,88skinned_mesh: &SkinnedMesh,89joint_entities: &Query<&GlobalTransform>,90inverse_bindposes_assets: &Res<Assets<SkinnedMeshInverseBindposes>>,91gizmos: &mut Gizmos<SkinnedMeshBoundsGizmoConfigGroup>,92) {93if let Some(mesh_asset) = mesh_assets.get(mesh)94&& let Some(bounds) = mesh_asset.skinned_mesh_bounds()95&& let Some(inverse_bindposes_asset) =96inverse_bindposes_assets.get(&skinned_mesh.inverse_bindposes)97{98for (&joint_index, &joint_aabb) in bounds.iter() {99let joint_index = joint_index.0 as usize;100101if let Some(&joint_entity) = skinned_mesh.joints.get(joint_index)102&& let Ok(&world_from_joint) = joint_entities.get(joint_entity)103&& let Some(&joint_from_mesh) = inverse_bindposes_asset.get(joint_index)104{105let world_from_mesh =106world_from_joint.affine() * Affine3A::from_mat4(joint_from_mesh);107108gizmos.aabb_3d(joint_aabb, world_from_mesh, color);109}110}111}112}113114fn draw_skinned_mesh_bounds(115mesh_entities: Query<116(&Mesh3d, &SkinnedMesh, &ShowSkinnedMeshBoundsGizmo),117With<DynamicSkinnedMeshBounds>,118>,119joint_entities: Query<&GlobalTransform>,120mesh_assets: Res<Assets<Mesh>>,121inverse_bindposes_assets: Res<Assets<SkinnedMeshInverseBindposes>>,122mut gizmos: Gizmos<SkinnedMeshBoundsGizmoConfigGroup>,123) {124for (mesh, skinned_mesh, gizmo) in mesh_entities {125let color = gizmo.color.unwrap_or(gizmos.config_ext.default_color);126127draw(128color,129mesh,130&mesh_assets,131skinned_mesh,132&joint_entities,133&inverse_bindposes_assets,134&mut gizmos,135);136}137}138139fn draw_all_skinned_mesh_bounds(140mesh_entities: Query<141(&Mesh3d, &SkinnedMesh),142(143With<DynamicSkinnedMeshBounds>,144Without<ShowSkinnedMeshBoundsGizmo>,145),146>,147joint_entities: Query<&GlobalTransform>,148mesh_assets: Res<Assets<Mesh>>,149inverse_bindposes_assets: Res<Assets<SkinnedMeshInverseBindposes>>,150mut gizmos: Gizmos<SkinnedMeshBoundsGizmoConfigGroup>,151) {152for (mesh, skinned_mesh) in mesh_entities {153draw(154gizmos.config_ext.default_color,155mesh,156&mesh_assets,157skinned_mesh,158&joint_entities,159&inverse_bindposes_assets,160&mut gizmos,161);162}163}164165166