1
- use crate :: MeshPipeline ;
2
- use crate :: { DrawMesh , MeshPipelineKey , MeshUniform , SetMeshBindGroup , SetMeshViewBindGroup } ;
1
+ use crate :: { Material , MaterialPipeline , MaterialPipelineKey , MaterialPlugin } ;
3
2
use bevy_app:: Plugin ;
4
- use bevy_asset:: { load_internal_asset, Handle , HandleUntyped } ;
5
- use bevy_core_pipeline:: core_3d:: Opaque3d ;
6
- use bevy_ecs:: { prelude:: * , reflect:: ReflectComponent } ;
7
- use bevy_reflect:: std_traits:: ReflectDefault ;
8
- use bevy_reflect:: { Reflect , TypeUuid } ;
9
- use bevy_render:: Extract ;
3
+ use bevy_asset:: { load_internal_asset, Assets , Handle , HandleUntyped } ;
4
+ use bevy_ecs:: prelude:: * ;
5
+ use bevy_reflect:: { std_traits:: ReflectDefault , Reflect , TypeUuid } ;
10
6
use bevy_render:: {
11
- extract_resource:: { ExtractResource , ExtractResourcePlugin } ,
7
+ extract_resource:: ExtractResource ,
12
8
mesh:: { Mesh , MeshVertexBufferLayout } ,
13
- render_asset:: RenderAssets ,
14
- render_phase:: { AddRenderCommand , DrawFunctions , RenderPhase , SetItemPipeline } ,
9
+ prelude:: Shader ,
15
10
render_resource:: {
16
- PipelineCache , PolygonMode , RenderPipelineDescriptor , Shader , SpecializedMeshPipeline ,
17
- SpecializedMeshPipelineError , SpecializedMeshPipelines ,
11
+ AsBindGroup , PolygonMode , RenderPipelineDescriptor , ShaderRef , SpecializedMeshPipelineError ,
18
12
} ,
19
- view:: { ExtractedView , Msaa , VisibleEntities } ,
20
- RenderApp , RenderStage ,
21
13
} ;
22
- use bevy_utils:: tracing:: error;
23
14
24
15
pub const WIREFRAME_SHADER_HANDLE : HandleUntyped =
25
16
HandleUntyped :: weak_from_u64 ( Shader :: TYPE_UUID , 192598014480025766 ) ;
26
17
18
+ /// A [`Plugin`] that draws wireframes.
27
19
#[ derive( Debug , Default ) ]
28
20
pub struct WireframePlugin ;
29
21
@@ -39,137 +31,101 @@ impl Plugin for WireframePlugin {
39
31
app. register_type :: < Wireframe > ( )
40
32
. register_type :: < WireframeConfig > ( )
41
33
. init_resource :: < WireframeConfig > ( )
42
- . add_plugin ( ExtractResourcePlugin :: < WireframeConfig > :: default ( ) ) ;
43
-
44
- if let Ok ( render_app) = app. get_sub_app_mut ( RenderApp ) {
45
- render_app
46
- . add_render_command :: < Opaque3d , DrawWireframes > ( )
47
- . init_resource :: < WireframePipeline > ( )
48
- . init_resource :: < SpecializedMeshPipelines < WireframePipeline > > ( )
49
- . add_system_to_stage ( RenderStage :: Extract , extract_wireframes)
50
- . add_system_to_stage ( RenderStage :: Queue , queue_wireframes) ;
51
- }
52
- }
53
- }
54
-
55
- fn extract_wireframes ( mut commands : Commands , query : Extract < Query < Entity , With < Wireframe > > > ) {
56
- for entity in & query {
57
- commands. get_or_spawn ( entity) . insert ( Wireframe ) ;
34
+ . add_plugin ( MaterialPlugin :: < WireframeMaterial > :: default ( ) )
35
+ . add_system ( apply_global)
36
+ . add_system ( apply_material) ;
58
37
}
59
38
}
60
39
61
- /// Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled
40
+ /// Toggles wireframe rendering for any entity it is attached to.
41
+ ///
42
+ /// This requires the [`WireframePlugin`] to be enabled.
62
43
#[ derive( Component , Debug , Clone , Default , Reflect ) ]
63
44
#[ reflect( Component , Default ) ]
64
45
pub struct Wireframe ;
65
46
47
+ /// Configuration resource for [`WireframePlugin`].
66
48
#[ derive( Resource , Debug , Clone , Default , ExtractResource , Reflect ) ]
67
49
#[ reflect( Resource ) ]
68
50
pub struct WireframeConfig {
69
- /// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered.
51
+ /// Whether to show wireframes for all meshes.
52
+ /// If `false`, only meshes with a [`Wireframe`] component will be rendered.
70
53
pub global : bool ,
71
54
}
72
55
73
- #[ derive( Resource , Clone ) ]
74
- pub struct WireframePipeline {
75
- mesh_pipeline : MeshPipeline ,
76
- shader : Handle < Shader > ,
77
- }
78
- impl FromWorld for WireframePipeline {
79
- fn from_world ( render_world : & mut World ) -> Self {
80
- WireframePipeline {
81
- mesh_pipeline : render_world. resource :: < MeshPipeline > ( ) . clone ( ) ,
82
- shader : WIREFRAME_SHADER_HANDLE . typed ( ) ,
83
- }
56
+ /// Applies the wireframe material to any mesh with a [`Wireframe`] component.
57
+ fn apply_material (
58
+ mut commands : Commands ,
59
+ mut materials : ResMut < Assets < WireframeMaterial > > ,
60
+ wireframes : Query < Entity , ( With < Wireframe > , Without < Handle < WireframeMaterial > > ) > ,
61
+ ) {
62
+ for e in & wireframes {
63
+ commands
64
+ . entity ( e)
65
+ . insert ( materials. add ( WireframeMaterial { } ) ) ;
84
66
}
85
67
}
86
68
87
- impl SpecializedMeshPipeline for WireframePipeline {
88
- type Key = MeshPipelineKey ;
69
+ /// Applies or removes a wireframe material on any mesh without a [`Wireframe`] component.
70
+ #[ allow( clippy:: type_complexity) ]
71
+ fn apply_global (
72
+ mut commands : Commands ,
73
+ config : Res < WireframeConfig > ,
74
+ mut materials : ResMut < Assets < WireframeMaterial > > ,
75
+ meshes_without_material : Query <
76
+ Entity ,
77
+ (
78
+ With < Handle < Mesh > > ,
79
+ Without < Wireframe > ,
80
+ Without < Handle < WireframeMaterial > > ,
81
+ ) ,
82
+ > ,
83
+ meshes_with_material : Query <
84
+ Entity ,
85
+ (
86
+ With < Handle < Mesh > > ,
87
+ Without < Wireframe > ,
88
+ With < Handle < WireframeMaterial > > ,
89
+ ) ,
90
+ > ,
91
+ ) {
92
+ if !config. is_changed ( ) {
93
+ return ;
94
+ }
89
95
90
- fn specialize (
91
- & self ,
92
- key : Self :: Key ,
93
- layout : & MeshVertexBufferLayout ,
94
- ) -> Result < RenderPipelineDescriptor , SpecializedMeshPipelineError > {
95
- let mut descriptor = self . mesh_pipeline . specialize ( key, layout) ?;
96
- descriptor. vertex . shader = self . shader . clone_weak ( ) ;
97
- descriptor. fragment . as_mut ( ) . unwrap ( ) . shader = self . shader . clone_weak ( ) ;
98
- descriptor. primitive . polygon_mode = PolygonMode :: Line ;
99
- descriptor. depth_stencil . as_mut ( ) . unwrap ( ) . bias . slope_scale = 1.0 ;
100
- Ok ( descriptor)
96
+ if config. global {
97
+ let global_material = materials. add ( WireframeMaterial { } ) ;
98
+ for e in & meshes_without_material {
99
+ commands. entity ( e) . insert ( global_material. clone ( ) ) ;
100
+ }
101
+ } else if !config. global {
102
+ for e in & meshes_with_material {
103
+ commands. entity ( e) . remove :: < Handle < WireframeMaterial > > ( ) ;
104
+ }
101
105
}
102
106
}
103
107
104
- #[ allow( clippy:: too_many_arguments) ]
105
- fn queue_wireframes (
106
- opaque_3d_draw_functions : Res < DrawFunctions < Opaque3d > > ,
107
- render_meshes : Res < RenderAssets < Mesh > > ,
108
- wireframe_config : Res < WireframeConfig > ,
109
- wireframe_pipeline : Res < WireframePipeline > ,
110
- mut pipelines : ResMut < SpecializedMeshPipelines < WireframePipeline > > ,
111
- mut pipeline_cache : ResMut < PipelineCache > ,
112
- msaa : Res < Msaa > ,
113
- mut material_meshes : ParamSet < (
114
- Query < ( Entity , & Handle < Mesh > , & MeshUniform ) > ,
115
- Query < ( Entity , & Handle < Mesh > , & MeshUniform ) , With < Wireframe > > ,
116
- ) > ,
117
- mut views : Query < ( & ExtractedView , & VisibleEntities , & mut RenderPhase < Opaque3d > ) > ,
118
- ) {
119
- let draw_custom = opaque_3d_draw_functions. read ( ) . id :: < DrawWireframes > ( ) ;
120
- let msaa_key = MeshPipelineKey :: from_msaa_samples ( msaa. samples ) ;
121
- for ( view, visible_entities, mut opaque_phase) in & mut views {
122
- let rangefinder = view. rangefinder3d ( ) ;
108
+ #[ derive( Default , AsBindGroup , TypeUuid , Debug , Clone ) ]
109
+ #[ uuid = "9e694f70-9963-4418-8bc1-3474c66b13b8" ]
110
+ struct WireframeMaterial { }
123
111
124
- let view_key = msaa_key | MeshPipelineKey :: from_hdr ( view. hdr ) ;
125
- let add_render_phase =
126
- |( entity, mesh_handle, mesh_uniform) : ( Entity , & Handle < Mesh > , & MeshUniform ) | {
127
- if let Some ( mesh) = render_meshes. get ( mesh_handle) {
128
- let key = view_key
129
- | MeshPipelineKey :: from_primitive_topology ( mesh. primitive_topology ) ;
130
- let pipeline_id = pipelines. specialize (
131
- & mut pipeline_cache,
132
- & wireframe_pipeline,
133
- key,
134
- & mesh. layout ,
135
- ) ;
136
- let pipeline_id = match pipeline_id {
137
- Ok ( id) => id,
138
- Err ( err) => {
139
- error ! ( "{}" , err) ;
140
- return ;
141
- }
142
- } ;
143
- opaque_phase. add ( Opaque3d {
144
- entity,
145
- pipeline : pipeline_id,
146
- draw_function : draw_custom,
147
- distance : rangefinder. distance ( & mesh_uniform. transform ) ,
148
- } ) ;
149
- }
150
- } ;
112
+ impl Material for WireframeMaterial {
113
+ fn vertex_shader ( ) -> ShaderRef {
114
+ WIREFRAME_SHADER_HANDLE . typed ( ) . into ( )
115
+ }
151
116
152
- if wireframe_config. global {
153
- let query = material_meshes. p0 ( ) ;
154
- visible_entities
155
- . entities
156
- . iter ( )
157
- . filter_map ( |visible_entity| query. get ( * visible_entity) . ok ( ) )
158
- . for_each ( add_render_phase) ;
159
- } else {
160
- let query = material_meshes. p1 ( ) ;
161
- visible_entities
162
- . entities
163
- . iter ( )
164
- . filter_map ( |visible_entity| query. get ( * visible_entity) . ok ( ) )
165
- . for_each ( add_render_phase) ;
166
- }
117
+ fn fragment_shader ( ) -> ShaderRef {
118
+ WIREFRAME_SHADER_HANDLE . typed ( ) . into ( )
167
119
}
168
- }
169
120
170
- type DrawWireframes = (
171
- SetItemPipeline ,
172
- SetMeshViewBindGroup < 0 > ,
173
- SetMeshBindGroup < 1 > ,
174
- DrawMesh ,
175
- ) ;
121
+ fn specialize (
122
+ _pipeline : & MaterialPipeline < Self > ,
123
+ descriptor : & mut RenderPipelineDescriptor ,
124
+ _layout : & MeshVertexBufferLayout ,
125
+ _key : MaterialPipelineKey < Self > ,
126
+ ) -> Result < ( ) , SpecializedMeshPipelineError > {
127
+ descriptor. primitive . polygon_mode = PolygonMode :: Line ;
128
+ descriptor. depth_stencil . as_mut ( ) . unwrap ( ) . bias . slope_scale = 1.0 ;
129
+ Ok ( ( ) )
130
+ }
131
+ }
0 commit comments