use bevy::{prelude::*, render::{render_graph::{ViewNode, NodeRunError, RenderGraphContext, RenderLabel}, view::ViewTarget, renderer::RenderContext, render_resource::{PipelineCache, BindGroupEntries, RenderPassDescriptor, RenderPassColorAttachment, Operations}, extract_component::ComponentUniforms}, core_pipeline::prepass::ViewPrepassTextures, ecs::query::QueryItem}; use super::components; use super::resources; #[derive(RenderLabel, Clone, Eq, PartialEq, Hash, Debug)] pub struct OutlineRenderLabel; #[derive(Default)] pub struct OutlineRenderNode; impl ViewNode for OutlineRenderNode { type ViewQuery = ( &'static ViewTarget, &'static ViewPrepassTextures, &'static components::OutlinePostProcessSettings, ); fn run( &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, (view_target, view_prepass_textures, _): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let render_pipeline = world.resource::(); let pipeline_cache = world.resource::(); let Some(pipeline) = pipeline_cache.get_render_pipeline(render_pipeline.pipeline_id) else { warn!("Failed to get render pipeline from cache, skipping..."); return Ok(()); }; let uniforms = world.resource::>(); let Some(uniform_binding) = uniforms.uniforms().binding() else { error!("Failed to get settings uniform binding"); return Ok(()); }; let Some(normal_buffer_view) = view_prepass_textures.normal_view() else { error!("Failed to get normal buffer view"); return Ok(()); }; let post_process = view_target.post_process_write(); let bind_group = render_context.render_device().create_bind_group( "outline_post_process_bind_group", &render_pipeline.layout, &BindGroupEntries::sequential(( post_process.source, &render_pipeline.screen_sampler, normal_buffer_view, &render_pipeline.normal_sampler, uniform_binding, )), ); let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { label: Some("outline_post_process_render_pass"), color_attachments: &[Some(RenderPassColorAttachment { view: post_process.destination, ops: Operations::default(), resolve_target: None, })], timestamp_writes: None, depth_stencil_attachment: None, occlusion_query_set: None, }); render_pass.set_render_pipeline(pipeline); render_pass.set_bind_group(0, &bind_group, &[]); render_pass.draw(0..3, 0..1); Ok(()) } }