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