Path: blob/main/crates/bevy_gizmos_render/src/pipeline_3d.rs
7228 views
use crate::{1init_line_gizmo_uniform_bind_group_layout, line_gizmo_vertex_buffer_layouts,2line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, DrawLineJointGizmo, GizmoRenderSystems,3GpuLineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup,4};5use bevy_app::{App, Plugin};6use bevy_asset::{load_embedded_asset, AssetServer, Handle};7use bevy_camera::visibility::RenderLayers;8use bevy_core_pipeline::{9core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT},10oit::OrderIndependentTransparencySettings,11prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},12};13use bevy_gizmos::config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig};1415use bevy_ecs::{16prelude::Entity,17query::Has,18resource::Resource,19schedule::IntoScheduleConfigs,20system::{Commands, Query, Res, ResMut},21};22use bevy_image::BevyDefault as _;23use bevy_pbr::{MeshPipeline, MeshPipelineKey, SetMeshViewBindGroup};24use bevy_render::{25render_asset::{prepare_assets, RenderAssets},26render_phase::{27AddRenderCommand, DrawFunctions, PhaseItemExtraIndex, SetItemPipeline,28ViewSortedRenderPhases,29},30render_resource::*,31view::{ExtractedView, Msaa, ViewTarget},32Render, RenderApp, RenderSystems,33};34use bevy_render::{sync_world::MainEntity, RenderStartup};35use bevy_shader::Shader;36use bevy_utils::default;37use tracing::error;3839pub struct LineGizmo3dPlugin;40impl Plugin for LineGizmo3dPlugin {41fn build(&self, app: &mut App) {42let Some(render_app) = app.get_sub_app_mut(RenderApp) else {43return;44};4546render_app47.add_render_command::<Transparent3d, DrawLineGizmo3d>()48.add_render_command::<Transparent3d, DrawLineGizmo3dStrip>()49.add_render_command::<Transparent3d, DrawLineJointGizmo3d>()50.init_resource::<SpecializedRenderPipelines<LineGizmoPipeline>>()51.init_resource::<SpecializedRenderPipelines<LineJointGizmoPipeline>>()52.configure_sets(53Render,54GizmoRenderSystems::QueueLineGizmos3d.in_set(RenderSystems::Queue),55)56.add_systems(57RenderStartup,58init_line_gizmo_pipelines.after(init_line_gizmo_uniform_bind_group_layout),59)60.add_systems(61Render,62(queue_line_gizmos_3d, queue_line_joint_gizmos_3d)63.in_set(GizmoRenderSystems::QueueLineGizmos3d)64.after(prepare_assets::<GpuLineGizmo>),65);66}67}6869#[derive(Clone, Resource)]70struct LineGizmoPipeline {71mesh_pipeline: MeshPipeline,72uniform_layout: BindGroupLayoutDescriptor,73shader: Handle<Shader>,74}7576fn init_line_gizmo_pipelines(77mut commands: Commands,78mesh_pipeline: Res<MeshPipeline>,79uniform_bind_group_layout: Res<LineGizmoUniformBindgroupLayout>,80asset_server: Res<AssetServer>,81) {82commands.insert_resource(LineGizmoPipeline {83mesh_pipeline: mesh_pipeline.clone(),84uniform_layout: uniform_bind_group_layout.layout.clone(),85shader: load_embedded_asset!(asset_server.as_ref(), "lines.wgsl"),86});87commands.insert_resource(LineJointGizmoPipeline {88mesh_pipeline: mesh_pipeline.clone(),89uniform_layout: uniform_bind_group_layout.layout.clone(),90shader: load_embedded_asset!(asset_server.as_ref(), "line_joints.wgsl"),91});92}9394#[derive(PartialEq, Eq, Hash, Clone)]95struct LineGizmoPipelineKey {96view_key: MeshPipelineKey,97strip: bool,98perspective: bool,99line_style: GizmoLineStyle,100}101102impl SpecializedRenderPipeline for LineGizmoPipeline {103type Key = LineGizmoPipelineKey;104105fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {106let mut shader_defs = vec![107#[cfg(feature = "webgl")]108"SIXTEEN_BYTE_ALIGNMENT".into(),109];110111if key.perspective {112shader_defs.push("PERSPECTIVE".into());113}114115let format = if key.view_key.contains(MeshPipelineKey::HDR) {116ViewTarget::TEXTURE_FORMAT_HDR117} else {118TextureFormat::bevy_default()119};120121let view_layout = self122.mesh_pipeline123.get_view_layout(key.view_key.into())124.clone();125let layout = vec![view_layout.main_layout.clone(), self.uniform_layout.clone()];126127let fragment_entry_point = match key.line_style {128GizmoLineStyle::Solid => "fragment_solid",129GizmoLineStyle::Dotted => "fragment_dotted",130GizmoLineStyle::Dashed { .. } => "fragment_dashed",131_ => unimplemented!(),132};133134RenderPipelineDescriptor {135vertex: VertexState {136shader: self.shader.clone(),137shader_defs: shader_defs.clone(),138buffers: line_gizmo_vertex_buffer_layouts(key.strip),139..default()140},141fragment: Some(FragmentState {142shader: self.shader.clone(),143shader_defs,144entry_point: Some(fragment_entry_point.into()),145targets: vec![Some(ColorTargetState {146format,147blend: Some(BlendState::ALPHA_BLENDING),148write_mask: ColorWrites::ALL,149})],150}),151layout,152depth_stencil: Some(DepthStencilState {153format: CORE_3D_DEPTH_FORMAT,154depth_write_enabled: true,155depth_compare: CompareFunction::Greater,156stencil: StencilState::default(),157bias: DepthBiasState::default(),158}),159multisample: MultisampleState {160count: key.view_key.msaa_samples(),161mask: !0,162alpha_to_coverage_enabled: false,163},164label: Some("LineGizmo 3d Pipeline".into()),165..default()166}167}168}169170#[derive(Clone, Resource)]171struct LineJointGizmoPipeline {172mesh_pipeline: MeshPipeline,173uniform_layout: BindGroupLayoutDescriptor,174shader: Handle<Shader>,175}176177#[derive(PartialEq, Eq, Hash, Clone)]178struct LineJointGizmoPipelineKey {179view_key: MeshPipelineKey,180perspective: bool,181joints: GizmoLineJoint,182}183184impl SpecializedRenderPipeline for LineJointGizmoPipeline {185type Key = LineJointGizmoPipelineKey;186187fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {188let mut shader_defs = vec![189#[cfg(feature = "webgl")]190"SIXTEEN_BYTE_ALIGNMENT".into(),191];192193if key.perspective {194shader_defs.push("PERSPECTIVE".into());195}196197let format = if key.view_key.contains(MeshPipelineKey::HDR) {198ViewTarget::TEXTURE_FORMAT_HDR199} else {200TextureFormat::bevy_default()201};202203let view_layout = self204.mesh_pipeline205.get_view_layout(key.view_key.into())206.clone();207let layout = vec![view_layout.main_layout.clone(), self.uniform_layout.clone()];208209if key.joints == GizmoLineJoint::None {210error!("There is no entry point for line joints with GizmoLineJoints::None. Please consider aborting the drawing process before reaching this stage.");211};212213let entry_point = match key.joints {214GizmoLineJoint::Miter => "vertex_miter",215GizmoLineJoint::Round(_) => "vertex_round",216GizmoLineJoint::None | GizmoLineJoint::Bevel => "vertex_bevel",217};218219RenderPipelineDescriptor {220vertex: VertexState {221shader: self.shader.clone(),222entry_point: Some(entry_point.into()),223shader_defs: shader_defs.clone(),224buffers: line_joint_gizmo_vertex_buffer_layouts(),225},226fragment: Some(FragmentState {227shader: self.shader.clone(),228shader_defs,229targets: vec![Some(ColorTargetState {230format,231blend: Some(BlendState::ALPHA_BLENDING),232write_mask: ColorWrites::ALL,233})],234..default()235}),236layout,237depth_stencil: Some(DepthStencilState {238format: CORE_3D_DEPTH_FORMAT,239depth_write_enabled: true,240depth_compare: CompareFunction::Greater,241stencil: StencilState::default(),242bias: DepthBiasState::default(),243}),244multisample: MultisampleState {245count: key.view_key.msaa_samples(),246mask: !0,247alpha_to_coverage_enabled: false,248},249label: Some("LineJointGizmo 3d Pipeline".into()),250..default()251}252}253}254255type DrawLineGizmo3d = (256SetItemPipeline,257SetMeshViewBindGroup<0>,258SetLineGizmoBindGroup<1>,259DrawLineGizmo<false>,260);261type DrawLineGizmo3dStrip = (262SetItemPipeline,263SetMeshViewBindGroup<0>,264SetLineGizmoBindGroup<1>,265DrawLineGizmo<true>,266);267type DrawLineJointGizmo3d = (268SetItemPipeline,269SetMeshViewBindGroup<0>,270SetLineGizmoBindGroup<1>,271DrawLineJointGizmo,272);273274fn queue_line_gizmos_3d(275draw_functions: Res<DrawFunctions<Transparent3d>>,276pipeline: Res<LineGizmoPipeline>,277mut pipelines: ResMut<SpecializedRenderPipelines<LineGizmoPipeline>>,278pipeline_cache: Res<PipelineCache>,279line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,280line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,281mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,282views: Query<(283&ExtractedView,284&Msaa,285Option<&RenderLayers>,286(287Has<NormalPrepass>,288Has<DepthPrepass>,289Has<MotionVectorPrepass>,290Has<DeferredPrepass>,291Has<OrderIndependentTransparencySettings>,292),293)>,294) {295let draw_function = draw_functions.read().get_id::<DrawLineGizmo3d>().unwrap();296let draw_function_strip = draw_functions297.read()298.get_id::<DrawLineGizmo3dStrip>()299.unwrap();300301for (302view,303msaa,304render_layers,305(normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass, oit),306) in &views307{308let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)309else {310continue;311};312313let render_layers = render_layers.unwrap_or_default();314315let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())316| MeshPipelineKey::from_hdr(view.hdr);317318if normal_prepass {319view_key |= MeshPipelineKey::NORMAL_PREPASS;320}321322if depth_prepass {323view_key |= MeshPipelineKey::DEPTH_PREPASS;324}325326if motion_vector_prepass {327view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;328}329330if deferred_prepass {331view_key |= MeshPipelineKey::DEFERRED_PREPASS;332}333334if oit {335view_key |= MeshPipelineKey::OIT_ENABLED;336}337338for (entity, main_entity, config) in &line_gizmos {339if !config.render_layers.intersects(render_layers) {340continue;341}342343let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {344continue;345};346347if line_gizmo.list_vertex_count > 0 {348let pipeline = pipelines.specialize(349&pipeline_cache,350&pipeline,351LineGizmoPipelineKey {352view_key,353strip: false,354perspective: config.line_perspective,355line_style: config.line_style,356},357);358transparent_phase.add(Transparent3d {359entity: (entity, *main_entity),360draw_function,361pipeline,362distance: 0.,363batch_range: 0..1,364extra_index: PhaseItemExtraIndex::None,365indexed: true,366});367}368369if line_gizmo.strip_vertex_count >= 2 {370let pipeline = pipelines.specialize(371&pipeline_cache,372&pipeline,373LineGizmoPipelineKey {374view_key,375strip: true,376perspective: config.line_perspective,377line_style: config.line_style,378},379);380transparent_phase.add(Transparent3d {381entity: (entity, *main_entity),382draw_function: draw_function_strip,383pipeline,384distance: 0.,385batch_range: 0..1,386extra_index: PhaseItemExtraIndex::None,387indexed: true,388});389}390}391}392}393394fn queue_line_joint_gizmos_3d(395draw_functions: Res<DrawFunctions<Transparent3d>>,396pipeline: Res<LineJointGizmoPipeline>,397mut pipelines: ResMut<SpecializedRenderPipelines<LineJointGizmoPipeline>>,398pipeline_cache: Res<PipelineCache>,399line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>,400line_gizmo_assets: Res<RenderAssets<GpuLineGizmo>>,401mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,402views: Query<(403&ExtractedView,404&Msaa,405Option<&RenderLayers>,406(407Has<NormalPrepass>,408Has<DepthPrepass>,409Has<MotionVectorPrepass>,410Has<DeferredPrepass>,411),412)>,413) {414let draw_function = draw_functions415.read()416.get_id::<DrawLineJointGizmo3d>()417.unwrap();418419for (420view,421msaa,422render_layers,423(normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),424) in &views425{426let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)427else {428continue;429};430431let render_layers = render_layers.unwrap_or_default();432433let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())434| MeshPipelineKey::from_hdr(view.hdr);435436if normal_prepass {437view_key |= MeshPipelineKey::NORMAL_PREPASS;438}439440if depth_prepass {441view_key |= MeshPipelineKey::DEPTH_PREPASS;442}443444if motion_vector_prepass {445view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;446}447448if deferred_prepass {449view_key |= MeshPipelineKey::DEFERRED_PREPASS;450}451452for (entity, main_entity, config) in &line_gizmos {453if !config.render_layers.intersects(render_layers) {454continue;455}456457let Some(line_gizmo) = line_gizmo_assets.get(&config.handle) else {458continue;459};460461if line_gizmo.strip_vertex_count < 3 || config.line_joints == GizmoLineJoint::None {462continue;463}464465let pipeline = pipelines.specialize(466&pipeline_cache,467&pipeline,468LineJointGizmoPipelineKey {469view_key,470perspective: config.line_perspective,471joints: config.line_joints,472},473);474475transparent_phase.add(Transparent3d {476entity: (entity, *main_entity),477draw_function,478pipeline,479distance: 0.,480batch_range: 0..1,481extra_index: PhaseItemExtraIndex::None,482indexed: true,483});484}485}486}487488489