Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gizmos/src/pipeline_3d.rs
6595 views
1
use crate::{
2
config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig},
3
init_line_gizmo_uniform_bind_group_layout, line_gizmo_vertex_buffer_layouts,
4
line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, DrawLineJointGizmo, GizmoRenderSystems,
5
GpuLineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup,
6
};
7
use bevy_app::{App, Plugin};
8
use bevy_asset::{load_embedded_asset, AssetServer, Handle};
9
use bevy_camera::visibility::RenderLayers;
10
use bevy_core_pipeline::{
11
core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT},
12
oit::OrderIndependentTransparencySettings,
13
prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},
14
};
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: BindGroupLayout,
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
};
133
134
RenderPipelineDescriptor {
135
vertex: VertexState {
136
shader: self.shader.clone(),
137
shader_defs: shader_defs.clone(),
138
buffers: line_gizmo_vertex_buffer_layouts(key.strip),
139
..default()
140
},
141
fragment: Some(FragmentState {
142
shader: self.shader.clone(),
143
shader_defs,
144
entry_point: Some(fragment_entry_point.into()),
145
targets: vec![Some(ColorTargetState {
146
format,
147
blend: Some(BlendState::ALPHA_BLENDING),
148
write_mask: ColorWrites::ALL,
149
})],
150
}),
151
layout,
152
depth_stencil: Some(DepthStencilState {
153
format: CORE_3D_DEPTH_FORMAT,
154
depth_write_enabled: true,
155
depth_compare: CompareFunction::Greater,
156
stencil: StencilState::default(),
157
bias: DepthBiasState::default(),
158
}),
159
multisample: MultisampleState {
160
count: key.view_key.msaa_samples(),
161
mask: !0,
162
alpha_to_coverage_enabled: false,
163
},
164
label: Some("LineGizmo 3d Pipeline".into()),
165
..default()
166
}
167
}
168
}
169
170
#[derive(Clone, Resource)]
171
struct LineJointGizmoPipeline {
172
mesh_pipeline: MeshPipeline,
173
uniform_layout: BindGroupLayout,
174
shader: Handle<Shader>,
175
}
176
177
#[derive(PartialEq, Eq, Hash, Clone)]
178
struct LineJointGizmoPipelineKey {
179
view_key: MeshPipelineKey,
180
perspective: bool,
181
joints: GizmoLineJoint,
182
}
183
184
impl SpecializedRenderPipeline for LineJointGizmoPipeline {
185
type Key = LineJointGizmoPipelineKey;
186
187
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
188
let mut shader_defs = vec![
189
#[cfg(feature = "webgl")]
190
"SIXTEEN_BYTE_ALIGNMENT".into(),
191
];
192
193
if key.perspective {
194
shader_defs.push("PERSPECTIVE".into());
195
}
196
197
let format = if key.view_key.contains(MeshPipelineKey::HDR) {
198
ViewTarget::TEXTURE_FORMAT_HDR
199
} else {
200
TextureFormat::bevy_default()
201
};
202
203
let view_layout = self
204
.mesh_pipeline
205
.get_view_layout(key.view_key.into())
206
.clone();
207
let layout = vec![view_layout.main_layout.clone(), self.uniform_layout.clone()];
208
209
if key.joints == GizmoLineJoint::None {
210
error!("There is no entry point for line joints with GizmoLineJoints::None. Please consider aborting the drawing process before reaching this stage.");
211
};
212
213
let entry_point = match key.joints {
214
GizmoLineJoint::Miter => "vertex_miter",
215
GizmoLineJoint::Round(_) => "vertex_round",
216
GizmoLineJoint::None | GizmoLineJoint::Bevel => "vertex_bevel",
217
};
218
219
RenderPipelineDescriptor {
220
vertex: VertexState {
221
shader: self.shader.clone(),
222
entry_point: Some(entry_point.into()),
223
shader_defs: shader_defs.clone(),
224
buffers: line_joint_gizmo_vertex_buffer_layouts(),
225
},
226
fragment: Some(FragmentState {
227
shader: self.shader.clone(),
228
shader_defs,
229
targets: vec![Some(ColorTargetState {
230
format,
231
blend: Some(BlendState::ALPHA_BLENDING),
232
write_mask: ColorWrites::ALL,
233
})],
234
..default()
235
}),
236
layout,
237
depth_stencil: Some(DepthStencilState {
238
format: CORE_3D_DEPTH_FORMAT,
239
depth_write_enabled: true,
240
depth_compare: CompareFunction::Greater,
241
stencil: StencilState::default(),
242
bias: DepthBiasState::default(),
243
}),
244
multisample: MultisampleState {
245
count: key.view_key.msaa_samples(),
246
mask: !0,
247
alpha_to_coverage_enabled: false,
248
},
249
label: Some("LineJointGizmo 3d Pipeline".into()),
250
..default()
251
}
252
}
253
}
254
255
type DrawLineGizmo3d = (
256
SetItemPipeline,
257
SetMeshViewBindGroup<0>,
258
SetLineGizmoBindGroup<1>,
259
DrawLineGizmo<false>,
260
);
261
type DrawLineGizmo3dStrip = (
262
SetItemPipeline,
263
SetMeshViewBindGroup<0>,
264
SetLineGizmoBindGroup<1>,
265
DrawLineGizmo<true>,
266
);
267
type DrawLineJointGizmo3d = (
268
SetItemPipeline,
269
SetMeshViewBindGroup<0>,
270
SetLineGizmoBindGroup<1>,
271
DrawLineJointGizmo,
272
);
273
274
fn queue_line_gizmos_3d(
275
draw_functions: Res<DrawFunctions<Transparent3d>>,
276
pipeline: Res<LineGizmoPipeline>,
277
mut pipelines: ResMut<SpecializedRenderPipelines<LineGizmoPipeline>>,
278
pipeline_cache: Res<PipelineCache>,
279
line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,
280
line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,
281
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
282
views: Query<(
283
&ExtractedView,
284
&Msaa,
285
Option<&RenderLayers>,
286
(
287
Has<NormalPrepass>,
288
Has<DepthPrepass>,
289
Has<MotionVectorPrepass>,
290
Has<DeferredPrepass>,
291
Has<OrderIndependentTransparencySettings>,
292
),
293
)>,
294
) {
295
let draw_function = draw_functions.read().get_id::<DrawLineGizmo3d>().unwrap();
296
let draw_function_strip = draw_functions
297
.read()
298
.get_id::<DrawLineGizmo3dStrip>()
299
.unwrap();
300
301
for (
302
view,
303
msaa,
304
render_layers,
305
(normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass, oit),
306
) in &views
307
{
308
let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
309
else {
310
continue;
311
};
312
313
let render_layers = render_layers.unwrap_or_default();
314
315
let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
316
| MeshPipelineKey::from_hdr(view.hdr);
317
318
if normal_prepass {
319
view_key |= MeshPipelineKey::NORMAL_PREPASS;
320
}
321
322
if depth_prepass {
323
view_key |= MeshPipelineKey::DEPTH_PREPASS;
324
}
325
326
if motion_vector_prepass {
327
view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
328
}
329
330
if deferred_prepass {
331
view_key |= MeshPipelineKey::DEFERRED_PREPASS;
332
}
333
334
if oit {
335
view_key |= MeshPipelineKey::OIT_ENABLED;
336
}
337
338
for (entity, main_entity, config) in &line_gizmos {
339
if !config.render_layers.intersects(render_layers) {
340
continue;
341
}
342
343
let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {
344
continue;
345
};
346
347
if line_gizmo.list_vertex_count > 0 {
348
let pipeline = pipelines.specialize(
349
&pipeline_cache,
350
&pipeline,
351
LineGizmoPipelineKey {
352
view_key,
353
strip: false,
354
perspective: config.line_perspective,
355
line_style: config.line_style,
356
},
357
);
358
transparent_phase.add(Transparent3d {
359
entity: (entity, *main_entity),
360
draw_function,
361
pipeline,
362
distance: 0.,
363
batch_range: 0..1,
364
extra_index: PhaseItemExtraIndex::None,
365
indexed: true,
366
});
367
}
368
369
if line_gizmo.strip_vertex_count >= 2 {
370
let pipeline = pipelines.specialize(
371
&pipeline_cache,
372
&pipeline,
373
LineGizmoPipelineKey {
374
view_key,
375
strip: true,
376
perspective: config.line_perspective,
377
line_style: config.line_style,
378
},
379
);
380
transparent_phase.add(Transparent3d {
381
entity: (entity, *main_entity),
382
draw_function: draw_function_strip,
383
pipeline,
384
distance: 0.,
385
batch_range: 0..1,
386
extra_index: PhaseItemExtraIndex::None,
387
indexed: true,
388
});
389
}
390
}
391
}
392
}
393
394
fn queue_line_joint_gizmos_3d(
395
draw_functions: Res<DrawFunctions<Transparent3d>>,
396
pipeline: Res<LineJointGizmoPipeline>,
397
mut pipelines: ResMut<SpecializedRenderPipelines<LineJointGizmoPipeline>>,
398
pipeline_cache: Res<PipelineCache>,
399
line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,
400
line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,
401
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
402
views: Query<(
403
&ExtractedView,
404
&Msaa,
405
Option<&RenderLayers>,
406
(
407
Has<NormalPrepass>,
408
Has<DepthPrepass>,
409
Has<MotionVectorPrepass>,
410
Has<DeferredPrepass>,
411
),
412
)>,
413
) {
414
let draw_function = draw_functions
415
.read()
416
.get_id::<DrawLineJointGizmo3d>()
417
.unwrap();
418
419
for (
420
view,
421
msaa,
422
render_layers,
423
(normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),
424
) in &views
425
{
426
let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
427
else {
428
continue;
429
};
430
431
let render_layers = render_layers.unwrap_or_default();
432
433
let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
434
| MeshPipelineKey::from_hdr(view.hdr);
435
436
if normal_prepass {
437
view_key |= MeshPipelineKey::NORMAL_PREPASS;
438
}
439
440
if depth_prepass {
441
view_key |= MeshPipelineKey::DEPTH_PREPASS;
442
}
443
444
if motion_vector_prepass {
445
view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
446
}
447
448
if deferred_prepass {
449
view_key |= MeshPipelineKey::DEFERRED_PREPASS;
450
}
451
452
for (entity, main_entity, config) in &line_gizmos {
453
if !config.render_layers.intersects(render_layers) {
454
continue;
455
}
456
457
let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {
458
continue;
459
};
460
461
if line_gizmo.strip_vertex_count < 3 || config.line_joints == GizmoLineJoint::None {
462
continue;
463
}
464
465
let pipeline = pipelines.specialize(
466
&pipeline_cache,
467
&pipeline,
468
LineJointGizmoPipelineKey {
469
view_key,
470
perspective: config.line_perspective,
471
joints: config.line_joints,
472
},
473
);
474
475
transparent_phase.add(Transparent3d {
476
entity: (entity, *main_entity),
477
draw_function,
478
pipeline,
479
distance: 0.,
480
batch_range: 0..1,
481
extra_index: PhaseItemExtraIndex::None,
482
indexed: true,
483
});
484
}
485
}
486
}
487
488