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
9416 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_and_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(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
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(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
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_and_joint_gizmos_2d(
291
draw_functions: Res<DrawFunctions<Transparent2d>>,
292
line_gizmo_pipeline: Res<LineGizmoPipeline>,
293
line_joint_gizmo_pipeline: Res<LineJointGizmoPipeline>,
294
mut line_gizmo_pipelines: ResMut<SpecializedRenderPipelines<LineGizmoPipeline>>,
295
mut line_joint_gizmo_pipelines: ResMut<SpecializedRenderPipelines<LineJointGizmoPipeline>>,
296
pipeline_cache: Res<PipelineCache>,
297
line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,
298
line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,
299
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
300
mut views: Query<(&ExtractedView, &Msaa, Option<&RenderLayers>)>,
301
) {
302
let draw_function = draw_functions.read().get_id::<DrawLineGizmo2d>().unwrap();
303
let draw_line_function_strip = draw_functions
304
.read()
305
.get_id::<DrawLineGizmo2dStrip>()
306
.unwrap();
307
let draw_line_joint_function = draw_functions
308
.read()
309
.get_id::<DrawLineJointGizmo2d>()
310
.unwrap();
311
312
for (view, msaa, render_layers) in &mut views {
313
let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
314
else {
315
continue;
316
};
317
318
let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples())
319
| Mesh2dPipelineKey::from_hdr(view.hdr);
320
321
let render_layers = render_layers.unwrap_or_default();
322
for (entity, main_entity, config) in &line_gizmos {
323
if !config.render_layers.intersects(render_layers) {
324
continue;
325
}
326
327
let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {
328
continue;
329
};
330
331
// Draw lines
332
if line_gizmo.list_vertex_count > 0 {
333
let pipeline = line_gizmo_pipelines.specialize(
334
&pipeline_cache,
335
&line_gizmo_pipeline,
336
LineGizmoPipelineKey {
337
mesh_key,
338
strip: false,
339
line_style: config.line_style,
340
},
341
);
342
transparent_phase.add(Transparent2d {
343
entity: (entity, *main_entity),
344
draw_function,
345
pipeline,
346
sort_key: FloatOrd(f32::INFINITY),
347
batch_range: 0..1,
348
extra_index: PhaseItemExtraIndex::None,
349
extracted_index: usize::MAX,
350
indexed: false,
351
});
352
}
353
354
if line_gizmo.strip_vertex_count >= 2 {
355
let pipeline = line_gizmo_pipelines.specialize(
356
&pipeline_cache,
357
&line_gizmo_pipeline,
358
LineGizmoPipelineKey {
359
mesh_key,
360
strip: true,
361
line_style: config.line_style,
362
},
363
);
364
transparent_phase.add(Transparent2d {
365
entity: (entity, *main_entity),
366
draw_function: draw_line_function_strip,
367
pipeline,
368
sort_key: FloatOrd(f32::INFINITY),
369
batch_range: 0..1,
370
extra_index: PhaseItemExtraIndex::None,
371
extracted_index: usize::MAX,
372
indexed: false,
373
});
374
}
375
376
// Draw line joints
377
if line_gizmo.strip_vertex_count < 3 || config.line_joints == GizmoLineJoint::None {
378
continue;
379
}
380
381
let pipeline = line_joint_gizmo_pipelines.specialize(
382
&pipeline_cache,
383
&line_joint_gizmo_pipeline,
384
LineJointGizmoPipelineKey {
385
mesh_key,
386
joints: config.line_joints,
387
},
388
);
389
transparent_phase.add(Transparent2d {
390
entity: (entity, *main_entity),
391
draw_function: draw_line_joint_function,
392
pipeline,
393
sort_key: FloatOrd(f32::INFINITY),
394
batch_range: 0..1,
395
extra_index: PhaseItemExtraIndex::None,
396
extracted_index: usize::MAX,
397
indexed: false,
398
});
399
}
400
}
401
}
402
403