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