2023-06-13 06:49:47 +00:00
|
|
|
use crate::{
|
|
|
|
line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, LineGizmo,
|
|
|
|
LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE,
|
|
|
|
};
|
|
|
|
use bevy_app::{App, Plugin};
|
2023-03-20 20:57:54 +00:00
|
|
|
use bevy_asset::Handle;
|
2023-06-13 06:49:47 +00:00
|
|
|
use bevy_core_pipeline::core_3d::Transparent3d;
|
|
|
|
|
2023-03-20 20:57:54 +00:00
|
|
|
use bevy_ecs::{
|
2023-06-13 06:49:47 +00:00
|
|
|
prelude::Entity,
|
|
|
|
schedule::IntoSystemConfigs,
|
2023-03-20 20:57:54 +00:00
|
|
|
system::{Query, Res, ResMut, Resource},
|
|
|
|
world::{FromWorld, World},
|
|
|
|
};
|
2023-06-13 06:49:47 +00:00
|
|
|
use bevy_pbr::{
|
|
|
|
MeshPipeline, MeshPipelineKey, SetMeshViewBindGroup, MAX_CASCADES_PER_LIGHT,
|
|
|
|
MAX_DIRECTIONAL_LIGHTS,
|
2023-03-20 20:57:54 +00:00
|
|
|
};
|
|
|
|
use bevy_render::{
|
|
|
|
render_asset::RenderAssets,
|
2023-06-13 06:49:47 +00:00
|
|
|
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
|
2023-03-20 20:57:54 +00:00
|
|
|
render_resource::*,
|
|
|
|
texture::BevyDefault,
|
2023-06-13 06:49:47 +00:00
|
|
|
view::{ExtractedView, Msaa, ViewTarget},
|
|
|
|
Render, RenderApp, RenderSet,
|
2023-03-20 20:57:54 +00:00
|
|
|
};
|
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
pub struct LineGizmo3dPlugin;
|
|
|
|
impl Plugin for LineGizmo3dPlugin {
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { return };
|
2023-03-20 20:57:54 +00:00
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
render_app
|
|
|
|
.add_render_command::<Transparent3d, DrawLineGizmo3d>()
|
|
|
|
.init_resource::<SpecializedRenderPipelines<LineGizmoPipeline>>()
|
|
|
|
.add_systems(Render, queue_line_gizmos_3d.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 {
|
2023-03-20 20:57:54 +00:00
|
|
|
mesh_pipeline: MeshPipeline,
|
2023-06-13 06:49:47 +00:00
|
|
|
uniform_layout: BindGroupLayout,
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
impl FromWorld for LineGizmoPipeline {
|
2023-03-20 20:57:54 +00:00
|
|
|
fn from_world(render_world: &mut World) -> Self {
|
2023-06-13 06:49:47 +00:00
|
|
|
LineGizmoPipeline {
|
2023-03-20 20:57:54 +00:00
|
|
|
mesh_pipeline: render_world.resource::<MeshPipeline>().clone(),
|
2023-06-13 06:49:47 +00:00
|
|
|
uniform_layout: render_world
|
|
|
|
.resource::<LineGizmoUniformBindgroupLayout>()
|
|
|
|
.layout
|
|
|
|
.clone(),
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
#[derive(PartialEq, Eq, Hash, Clone)]
|
|
|
|
struct LineGizmoPipelineKey {
|
|
|
|
mesh_key: MeshPipelineKey,
|
|
|
|
strip: bool,
|
|
|
|
perspective: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SpecializedRenderPipeline for LineGizmoPipeline {
|
|
|
|
type Key = LineGizmoPipelineKey;
|
|
|
|
|
|
|
|
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
|
|
|
|
let mut shader_defs = vec![
|
|
|
|
"GIZMO_3D".into(),
|
|
|
|
#[cfg(feature = "webgl")]
|
|
|
|
"SIXTEEN_BYTE_ALIGNMENT".into(),
|
|
|
|
];
|
2023-03-20 20:57:54 +00:00
|
|
|
|
|
|
|
shader_defs.push(ShaderDefVal::Int(
|
|
|
|
"MAX_DIRECTIONAL_LIGHTS".to_string(),
|
|
|
|
MAX_DIRECTIONAL_LIGHTS as i32,
|
|
|
|
));
|
|
|
|
shader_defs.push(ShaderDefVal::Int(
|
|
|
|
"MAX_CASCADES_PER_LIGHT".to_string(),
|
|
|
|
MAX_CASCADES_PER_LIGHT as i32,
|
|
|
|
));
|
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
if key.perspective {
|
|
|
|
shader_defs.push("PERSPECTIVE".into());
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
let format = if key.mesh_key.contains(MeshPipelineKey::HDR) {
|
2023-03-20 20:57:54 +00:00
|
|
|
ViewTarget::TEXTURE_FORMAT_HDR
|
|
|
|
} else {
|
|
|
|
TextureFormat::bevy_default()
|
|
|
|
};
|
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
let view_layout = if key.mesh_key.msaa_samples() == 1 {
|
|
|
|
self.mesh_pipeline.view_layout.clone()
|
|
|
|
} else {
|
|
|
|
self.mesh_pipeline.view_layout_multisampled.clone()
|
|
|
|
};
|
|
|
|
|
|
|
|
let layout = vec![view_layout, self.uniform_layout.clone()];
|
|
|
|
|
|
|
|
RenderPipelineDescriptor {
|
2023-03-20 20:57:54 +00:00
|
|
|
vertex: VertexState {
|
2023-06-13 06:49:47 +00:00
|
|
|
shader: LINE_SHADER_HANDLE.typed(),
|
2023-03-20 20:57:54 +00:00
|
|
|
entry_point: "vertex".into(),
|
|
|
|
shader_defs: shader_defs.clone(),
|
2023-06-13 06:49:47 +00:00
|
|
|
buffers: line_gizmo_vertex_buffer_layouts(key.strip),
|
2023-03-20 20:57:54 +00:00
|
|
|
},
|
|
|
|
fragment: Some(FragmentState {
|
2023-06-13 06:49:47 +00:00
|
|
|
shader: LINE_SHADER_HANDLE.typed(),
|
2023-03-20 20:57:54 +00:00
|
|
|
shader_defs,
|
|
|
|
entry_point: "fragment".into(),
|
|
|
|
targets: vec![Some(ColorTargetState {
|
|
|
|
format,
|
2023-06-13 06:49:47 +00:00
|
|
|
blend: Some(BlendState::ALPHA_BLENDING),
|
2023-03-20 20:57:54 +00:00
|
|
|
write_mask: ColorWrites::ALL,
|
|
|
|
})],
|
|
|
|
}),
|
2023-06-13 06:49:47 +00:00
|
|
|
layout,
|
|
|
|
primitive: PrimitiveState::default(),
|
2023-03-20 20:57:54 +00:00
|
|
|
depth_stencil: Some(DepthStencilState {
|
|
|
|
format: TextureFormat::Depth32Float,
|
|
|
|
depth_write_enabled: true,
|
|
|
|
depth_compare: CompareFunction::Greater,
|
2023-06-13 06:49:47 +00:00
|
|
|
stencil: StencilState::default(),
|
|
|
|
bias: DepthBiasState::default(),
|
2023-03-20 20:57:54 +00:00
|
|
|
}),
|
|
|
|
multisample: MultisampleState {
|
2023-06-13 06:49:47 +00:00
|
|
|
count: key.mesh_key.msaa_samples(),
|
2023-03-20 20:57:54 +00:00
|
|
|
mask: !0,
|
|
|
|
alpha_to_coverage_enabled: false,
|
|
|
|
},
|
2023-06-13 06:49:47 +00:00
|
|
|
label: Some("LineGizmo Pipeline".into()),
|
2023-03-20 20:57:54 +00:00
|
|
|
push_constant_ranges: vec![],
|
2023-06-13 06:49:47 +00:00
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-13 06:49:47 +00:00
|
|
|
type DrawLineGizmo3d = (
|
2023-03-20 20:57:54 +00:00
|
|
|
SetItemPipeline,
|
|
|
|
SetMeshViewBindGroup<0>,
|
2023-06-13 06:49:47 +00:00
|
|
|
SetLineGizmoBindGroup<1>,
|
|
|
|
DrawLineGizmo,
|
2023-03-20 20:57:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
2023-06-13 06:49:47 +00:00
|
|
|
fn queue_line_gizmos_3d(
|
|
|
|
draw_functions: Res<DrawFunctions<Transparent3d>>,
|
|
|
|
pipeline: Res<LineGizmoPipeline>,
|
|
|
|
mut pipelines: ResMut<SpecializedRenderPipelines<LineGizmoPipeline>>,
|
2023-03-20 20:57:54 +00:00
|
|
|
pipeline_cache: Res<PipelineCache>,
|
|
|
|
msaa: Res<Msaa>,
|
|
|
|
config: Res<GizmoConfig>,
|
2023-06-13 06:49:47 +00:00
|
|
|
line_gizmos: Query<(Entity, &Handle<LineGizmo>)>,
|
|
|
|
line_gizmo_assets: Res<RenderAssets<LineGizmo>>,
|
|
|
|
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
|
2023-03-20 20:57:54 +00:00
|
|
|
) {
|
2023-06-13 06:49:47 +00:00
|
|
|
let draw_function = draw_functions.read().get_id::<DrawLineGizmo3d>().unwrap();
|
|
|
|
|
|
|
|
for (view, mut transparent_phase) in &mut views {
|
|
|
|
let mesh_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
|
|
|
|
| MeshPipelineKey::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,
|
|
|
|
perspective: config.line_perspective,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
transparent_phase.add(Transparent3d {
|
|
|
|
entity,
|
|
|
|
draw_function,
|
|
|
|
pipeline,
|
|
|
|
distance: 0.,
|
|
|
|
});
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|