Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gizmos_render/src/pipeline_2d.rs
7228 views
1
use crate::{
2
init_line_gizmo_uniform_bind_group_layout, line_gizmo_vertex_buffer_layouts,
3
line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, DrawLineJointGizmo, GizmoRenderSystems,
4
GpuLineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup,
5
};
6
use bevy_app::{App, Plugin};
7
use bevy_asset::{load_embedded_asset, AssetServer, Handle};
8
use bevy_camera::visibility::RenderLayers;
9
use bevy_core_pipeline::core_2d::{Transparent2d, CORE_2D_DEPTH_FORMAT};
10
use bevy_gizmos::config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig};
11
12
use bevy_ecs::{
13
prelude::Entity,
14
resource::Resource,
15
schedule::IntoScheduleConfigs,
16
system::{Commands, Query, Res, ResMut},
17
};
18
use bevy_image::BevyDefault as _;
19
use bevy_math::FloatOrd;
20
use bevy_render::{
21
render_asset::{prepare_assets, RenderAssets},
22
render_phase::{
23
AddRenderCommand, DrawFunctions, PhaseItemExtraIndex, SetItemPipeline,
24
ViewSortedRenderPhases,
25
},
26
render_resource::*,
27
view::{ExtractedView, Msaa, ViewTarget},
28
Render, RenderApp, RenderSystems,
29
};
30
use bevy_render::{sync_world::MainEntity, RenderStartup};
31
use bevy_shader::Shader;
32
use bevy_sprite_render::{
33
init_mesh_2d_pipeline, Mesh2dPipeline, Mesh2dPipelineKey, SetMesh2dViewBindGroup,
34
};
35
use bevy_utils::default;
36
use tracing::error;
37
38
pub struct LineGizmo2dPlugin;
39
40
impl Plugin for LineGizmo2dPlugin {
41
fn build(&self, app: &mut App) {
42
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
43
return;
44
};
45
46
render_app
47
.add_render_command::<Transparent2d, DrawLineGizmo2d>()
48
.add_render_command::<Transparent2d, DrawLineGizmo2dStrip>()
49
.add_render_command::<Transparent2d, DrawLineJointGizmo2d>()
50
.init_resource::<SpecializedRenderPipelines<LineGizmoPipeline>>()
51
.init_resource::<SpecializedRenderPipelines<LineJointGizmoPipeline>>()
52
.configure_sets(
53
Render,
54
GizmoRenderSystems::QueueLineGizmos2d
55
.in_set(RenderSystems::Queue)
56
.ambiguous_with(bevy_sprite_render::queue_sprites)
57
.ambiguous_with(
58
bevy_sprite_render::queue_material2d_meshes::<
59
bevy_sprite_render::ColorMaterial,
60
>,
61
),
62
)
63
.add_systems(
64
RenderStartup,
65
init_line_gizmo_pipelines
66
.after(init_line_gizmo_uniform_bind_group_layout)
67
.after(init_mesh_2d_pipeline),
68
)
69
.add_systems(
70
Render,
71
(queue_line_gizmos_2d, queue_line_joint_gizmos_2d)
72
.in_set(GizmoRenderSystems::QueueLineGizmos2d)
73
.after(prepare_assets::<GpuLineGizmo>),
74
);
75
}
76
}
77
78
#[derive(Clone, Resource)]
79
struct LineGizmoPipeline {
80
mesh_pipeline: Mesh2dPipeline,
81
uniform_layout: BindGroupLayoutDescriptor,
82
shader: Handle<Shader>,
83
}
84
85
fn init_line_gizmo_pipelines(
86
mut commands: Commands,
87
mesh_2d_pipeline: Res<Mesh2dPipeline>,
88
uniform_bind_group_layout: Res<LineGizmoUniformBindgroupLayout>,
89
asset_server: Res<AssetServer>,
90
) {
91
commands.insert_resource(LineGizmoPipeline {
92
mesh_pipeline: mesh_2d_pipeline.clone(),
93
uniform_layout: uniform_bind_group_layout.layout.clone(),
94
shader: load_embedded_asset!(asset_server.as_ref(), "lines.wgsl"),
95
});
96
commands.insert_resource(LineJointGizmoPipeline {
97
mesh_pipeline: mesh_2d_pipeline.clone(),
98
uniform_layout: uniform_bind_group_layout.layout.clone(),
99
shader: load_embedded_asset!(asset_server.as_ref(), "line_joints.wgsl"),
100
});
101
}
102
103
#[derive(PartialEq, Eq, Hash, Clone)]
104
struct LineGizmoPipelineKey {
105
mesh_key: Mesh2dPipelineKey,
106
strip: bool,
107
line_style: GizmoLineStyle,
108
}
109
110
impl SpecializedRenderPipeline for LineGizmoPipeline {
111
type Key = LineGizmoPipelineKey;
112
113
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
114
let format = if key.mesh_key.contains(Mesh2dPipelineKey::HDR) {
115
ViewTarget::TEXTURE_FORMAT_HDR
116
} else {
117
TextureFormat::bevy_default()
118
};
119
120
let shader_defs = vec![
121
#[cfg(feature = "webgl")]
122
"SIXTEEN_BYTE_ALIGNMENT".into(),
123
];
124
125
let layout = vec![
126
self.mesh_pipeline.view_layout.clone(),
127
self.uniform_layout.clone(),
128
];
129
130
let fragment_entry_point = match key.line_style {
131
GizmoLineStyle::Solid => "fragment_solid",
132
GizmoLineStyle::Dotted => "fragment_dotted",
133
GizmoLineStyle::Dashed { .. } => "fragment_dashed",
134
_ => unimplemented!(),
135
};
136
137
RenderPipelineDescriptor {
138
vertex: VertexState {
139
shader: self.shader.clone(),
140
shader_defs: shader_defs.clone(),
141
buffers: line_gizmo_vertex_buffer_layouts(key.strip),
142
..default()
143
},
144
fragment: Some(FragmentState {
145
shader: self.shader.clone(),
146
shader_defs,
147
entry_point: Some(fragment_entry_point.into()),
148
targets: vec![Some(ColorTargetState {
149
format,
150
blend: Some(BlendState::ALPHA_BLENDING),
151
write_mask: ColorWrites::ALL,
152
})],
153
}),
154
layout,
155
depth_stencil: Some(DepthStencilState {
156
format: CORE_2D_DEPTH_FORMAT,
157
depth_write_enabled: false,
158
depth_compare: CompareFunction::Always,
159
stencil: StencilState {
160
front: StencilFaceState::IGNORE,
161
back: StencilFaceState::IGNORE,
162
read_mask: 0,
163
write_mask: 0,
164
},
165
bias: DepthBiasState {
166
constant: 0,
167
slope_scale: 0.0,
168
clamp: 0.0,
169
},
170
}),
171
multisample: MultisampleState {
172
count: key.mesh_key.msaa_samples(),
173
mask: !0,
174
alpha_to_coverage_enabled: false,
175
},
176
label: Some("LineGizmo Pipeline 2D".into()),
177
..default()
178
}
179
}
180
}
181
182
#[derive(Clone, Resource)]
183
struct LineJointGizmoPipeline {
184
mesh_pipeline: Mesh2dPipeline,
185
uniform_layout: BindGroupLayoutDescriptor,
186
shader: Handle<Shader>,
187
}
188
189
#[derive(PartialEq, Eq, Hash, Clone)]
190
struct LineJointGizmoPipelineKey {
191
mesh_key: Mesh2dPipelineKey,
192
joints: GizmoLineJoint,
193
}
194
195
impl SpecializedRenderPipeline for LineJointGizmoPipeline {
196
type Key = LineJointGizmoPipelineKey;
197
198
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
199
let format = if key.mesh_key.contains(Mesh2dPipelineKey::HDR) {
200
ViewTarget::TEXTURE_FORMAT_HDR
201
} else {
202
TextureFormat::bevy_default()
203
};
204
205
let shader_defs = vec![
206
#[cfg(feature = "webgl")]
207
"SIXTEEN_BYTE_ALIGNMENT".into(),
208
];
209
210
let layout = vec![
211
self.mesh_pipeline.view_layout.clone(),
212
self.uniform_layout.clone(),
213
];
214
215
if key.joints == GizmoLineJoint::None {
216
error!("There is no entry point for line joints with GizmoLineJoints::None. Please consider aborting the drawing process before reaching this stage.");
217
};
218
219
let entry_point = match key.joints {
220
GizmoLineJoint::Miter => "vertex_miter",
221
GizmoLineJoint::Round(_) => "vertex_round",
222
GizmoLineJoint::None | GizmoLineJoint::Bevel => "vertex_bevel",
223
};
224
225
RenderPipelineDescriptor {
226
vertex: VertexState {
227
shader: self.shader.clone(),
228
entry_point: Some(entry_point.into()),
229
shader_defs: shader_defs.clone(),
230
buffers: line_joint_gizmo_vertex_buffer_layouts(),
231
},
232
fragment: Some(FragmentState {
233
shader: self.shader.clone(),
234
shader_defs,
235
targets: vec![Some(ColorTargetState {
236
format,
237
blend: Some(BlendState::ALPHA_BLENDING),
238
write_mask: ColorWrites::ALL,
239
})],
240
..default()
241
}),
242
layout,
243
primitive: PrimitiveState::default(),
244
depth_stencil: Some(DepthStencilState {
245
format: CORE_2D_DEPTH_FORMAT,
246
depth_write_enabled: false,
247
depth_compare: CompareFunction::Always,
248
stencil: StencilState {
249
front: StencilFaceState::IGNORE,
250
back: StencilFaceState::IGNORE,
251
read_mask: 0,
252
write_mask: 0,
253
},
254
bias: DepthBiasState {
255
constant: 0,
256
slope_scale: 0.0,
257
clamp: 0.0,
258
},
259
}),
260
multisample: MultisampleState {
261
count: key.mesh_key.msaa_samples(),
262
mask: !0,
263
alpha_to_coverage_enabled: false,
264
},
265
label: Some("LineJointGizmo Pipeline 2D".into()),
266
..default()
267
}
268
}
269
}
270
271
type DrawLineGizmo2d = (
272
SetItemPipeline,
273
SetMesh2dViewBindGroup<0>,
274
SetLineGizmoBindGroup<1>,
275
DrawLineGizmo<false>,
276
);
277
type DrawLineGizmo2dStrip = (
278
SetItemPipeline,
279
SetMesh2dViewBindGroup<0>,
280
SetLineGizmoBindGroup<1>,
281
DrawLineGizmo<true>,
282
);
283
type DrawLineJointGizmo2d = (
284
SetItemPipeline,
285
SetMesh2dViewBindGroup<0>,
286
SetLineGizmoBindGroup<1>,
287
DrawLineJointGizmo,
288
);
289
290
fn queue_line_gizmos_2d(
291
draw_functions: Res<DrawFunctions<Transparent2d>>,
292
pipeline: Res<LineGizmoPipeline>,
293
mut pipelines: ResMut<SpecializedRenderPipelines<LineGizmoPipeline>>,
294
pipeline_cache: Res<PipelineCache>,
295
line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,
296
line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,
297
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
298
mut views: Query<(&ExtractedView, &Msaa, Option<&RenderLayers>)>,
299
) {
300
let draw_function = draw_functions.read().get_id::<DrawLineGizmo2d>().unwrap();
301
let draw_function_strip = draw_functions
302
.read()
303
.get_id::<DrawLineGizmo2dStrip>()
304
.unwrap();
305
306
for (view, msaa, render_layers) in &mut views {
307
let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
308
else {
309
continue;
310
};
311
312
let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples())
313
| Mesh2dPipelineKey::from_hdr(view.hdr);
314
315
let render_layers = render_layers.unwrap_or_default();
316
for (entity, main_entity, config) in &line_gizmos {
317
if !config.render_layers.intersects(render_layers) {
318
continue;
319
}
320
321
let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {
322
continue;
323
};
324
325
if line_gizmo.list_vertex_count > 0 {
326
let pipeline = pipelines.specialize(
327
&pipeline_cache,
328
&pipeline,
329
LineGizmoPipelineKey {
330
mesh_key,
331
strip: false,
332
line_style: config.line_style,
333
},
334
);
335
transparent_phase.add(Transparent2d {
336
entity: (entity, *main_entity),
337
draw_function,
338
pipeline,
339
sort_key: FloatOrd(f32::INFINITY),
340
batch_range: 0..1,
341
extra_index: PhaseItemExtraIndex::None,
342
extracted_index: usize::MAX,
343
indexed: false,
344
});
345
}
346
347
if line_gizmo.strip_vertex_count >= 2 {
348
let pipeline = pipelines.specialize(
349
&pipeline_cache,
350
&pipeline,
351
LineGizmoPipelineKey {
352
mesh_key,
353
strip: true,
354
line_style: config.line_style,
355
},
356
);
357
transparent_phase.add(Transparent2d {
358
entity: (entity, *main_entity),
359
draw_function: draw_function_strip,
360
pipeline,
361
sort_key: FloatOrd(f32::INFINITY),
362
batch_range: 0..1,
363
extra_index: PhaseItemExtraIndex::None,
364
extracted_index: usize::MAX,
365
indexed: false,
366
});
367
}
368
}
369
}
370
}
371
fn queue_line_joint_gizmos_2d(
372
draw_functions: Res<DrawFunctions<Transparent2d>>,
373
pipeline: Res<LineJointGizmoPipeline>,
374
mut pipelines: ResMut<SpecializedRenderPipelines<LineJointGizmoPipeline>>,
375
pipeline_cache: Res<PipelineCache>,
376
line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,
377
line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,
378
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
379
mut views: Query<(&ExtractedView, &Msaa, Option<&RenderLayers>)>,
380
) {
381
let draw_function = draw_functions
382
.read()
383
.get_id::<DrawLineJointGizmo2d>()
384
.unwrap();
385
386
for (view, msaa, render_layers) in &mut views {
387
let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
388
else {
389
continue;
390
};
391
392
let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples())
393
| Mesh2dPipelineKey::from_hdr(view.hdr);
394
395
let render_layers = render_layers.unwrap_or_default();
396
for (entity, main_entity, config) in &line_gizmos {
397
if !config.render_layers.intersects(render_layers) {
398
continue;
399
}
400
401
let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {
402
continue;
403
};
404
405
if line_gizmo.strip_vertex_count < 3 || config.line_joints == GizmoLineJoint::None {
406
continue;
407
}
408
409
let pipeline = pipelines.specialize(
410
&pipeline_cache,
411
&pipeline,
412
LineJointGizmoPipelineKey {
413
mesh_key,
414
joints: config.line_joints,
415
},
416
);
417
transparent_phase.add(Transparent2d {
418
entity: (entity, *main_entity),
419
draw_function,
420
pipeline,
421
sort_key: FloatOrd(f32::INFINITY),
422
batch_range: 0..1,
423
extra_index: PhaseItemExtraIndex::None,
424
extracted_index: usize::MAX,
425
indexed: false,
426
});
427
}
428
}
429
}
430
431