bevy/crates/bevy_gizmos/src/pipeline_2d.rs
ira e29981dcbd
Add option to disable gizmo rendering for specific cameras (#8952)
Added `GizmoConfig::render_layers`, which will ensure Gizmos are only
rendered on cameras that can see those `RenderLayers`.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 00:56:31 +00:00

175 lines
5.4 KiB
Rust

use crate::{
line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, LineGizmo,
LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE,
};
use bevy_app::{App, Plugin};
use bevy_asset::Handle;
use bevy_core_pipeline::core_2d::Transparent2d;
use bevy_ecs::{
prelude::Entity,
schedule::IntoSystemConfigs,
system::{Query, Res, ResMut, Resource},
world::{FromWorld, World},
};
use bevy_render::{
render_asset::RenderAssets,
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
render_resource::*,
texture::BevyDefault,
view::{ExtractedView, Msaa, RenderLayers, ViewTarget},
Render, RenderApp, RenderSet,
};
use bevy_sprite::{Mesh2dPipeline, Mesh2dPipelineKey, SetMesh2dViewBindGroup};
use bevy_utils::FloatOrd;
pub struct LineGizmo2dPlugin;
impl Plugin for LineGizmo2dPlugin {
fn build(&self, app: &mut App) {
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { return };
render_app
.add_render_command::<Transparent2d, DrawLineGizmo2d>()
.init_resource::<SpecializedRenderPipelines<LineGizmoPipeline>>()
.add_systems(Render, queue_line_gizmos_2d.in_set(RenderSet::Queue));
}
fn finish(&self, app: &mut App) {
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { return };
render_app.init_resource::<LineGizmoPipeline>();
}
}
#[derive(Clone, Resource)]
struct LineGizmoPipeline {
mesh_pipeline: Mesh2dPipeline,
uniform_layout: BindGroupLayout,
}
impl FromWorld for LineGizmoPipeline {
fn from_world(render_world: &mut World) -> Self {
LineGizmoPipeline {
mesh_pipeline: render_world.resource::<Mesh2dPipeline>().clone(),
uniform_layout: render_world
.resource::<LineGizmoUniformBindgroupLayout>()
.layout
.clone(),
}
}
}
#[derive(PartialEq, Eq, Hash, Clone)]
struct LineGizmoPipelineKey {
mesh_key: Mesh2dPipelineKey,
strip: bool,
}
impl SpecializedRenderPipeline for LineGizmoPipeline {
type Key = LineGizmoPipelineKey;
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
let format = if key.mesh_key.contains(Mesh2dPipelineKey::HDR) {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
TextureFormat::bevy_default()
};
let shader_defs = vec![
#[cfg(feature = "webgl")]
"SIXTEEN_BYTE_ALIGNMENT".into(),
];
let layout = vec![
self.mesh_pipeline.view_layout.clone(),
self.uniform_layout.clone(),
];
RenderPipelineDescriptor {
vertex: VertexState {
shader: LINE_SHADER_HANDLE.typed(),
entry_point: "vertex".into(),
shader_defs: shader_defs.clone(),
buffers: line_gizmo_vertex_buffer_layouts(key.strip),
},
fragment: Some(FragmentState {
shader: LINE_SHADER_HANDLE.typed(),
shader_defs,
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format,
blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::ALL,
})],
}),
layout,
primitive: PrimitiveState::default(),
depth_stencil: None,
multisample: MultisampleState {
count: key.mesh_key.msaa_samples(),
mask: !0,
alpha_to_coverage_enabled: false,
},
label: Some("LineGizmo Pipeline 2D".into()),
push_constant_ranges: vec![],
}
}
}
type DrawLineGizmo2d = (
SetItemPipeline,
SetMesh2dViewBindGroup<0>,
SetLineGizmoBindGroup<1>,
DrawLineGizmo,
);
#[allow(clippy::too_many_arguments)]
fn queue_line_gizmos_2d(
draw_functions: Res<DrawFunctions<Transparent2d>>,
pipeline: Res<LineGizmoPipeline>,
mut pipelines: ResMut<SpecializedRenderPipelines<LineGizmoPipeline>>,
pipeline_cache: Res<PipelineCache>,
msaa: Res<Msaa>,
config: Res<GizmoConfig>,
line_gizmos: Query<(Entity, &Handle<LineGizmo>)>,
line_gizmo_assets: Res<RenderAssets<LineGizmo>>,
mut views: Query<(
&ExtractedView,
&mut RenderPhase<Transparent2d>,
Option<&RenderLayers>,
)>,
) {
let draw_function = draw_functions.read().get_id::<DrawLineGizmo2d>().unwrap();
for (view, mut transparent_phase, render_layers) in &mut views {
let render_layers = render_layers.copied().unwrap_or_default();
if !config.render_layers.intersects(&render_layers) {
continue;
}
let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples())
| Mesh2dPipelineKey::from_hdr(view.hdr);
for (entity, handle) in &line_gizmos {
let Some(line_gizmo) = line_gizmo_assets.get(handle) else { continue };
let pipeline = pipelines.specialize(
&pipeline_cache,
&pipeline,
LineGizmoPipelineKey {
mesh_key,
strip: line_gizmo.strip,
},
);
transparent_phase.add(Transparent2d {
entity,
draw_function,
pipeline,
sort_key: FloatOrd(0.),
batch_range: None,
});
}
}
}