diff --git a/Cargo.toml b/Cargo.toml index a41280d..664fa4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,35 @@ [package] -name = "bevy_jfa" +authors = ["dataphract"] +categories = ["game-development", "graphics"] description = "The jump flooding algorithm (JFA) for Bevy" +documentation = "https://docs.rs/bevy_jfa" keywords = ["bevy", "jfa", "outline", "graphics"] -categories = ["game-development", "graphics"] -authors = ["dataphract"] license = "MIT OR Apache-2.0" -documentation = "https://docs.rs/bevy_jfa" -repository = "https://github.com/dataphract/bevy_jfa" +name = "bevy_jfa" readme = "README.md" +repository = "https://github.com/dataphract/bevy_jfa" -version = "0.1.0" edition = "2021" resolver = "2" +version = "0.1.0" [features] default = ["wgpu-profiler"] [dependencies] -bitflags = "1" -wgpu-profiler = { version = "0.9", optional = true } +bitflags = "2.3.1" +wgpu-profiler = {version = "0.12.1", optional = true} [dependencies.bevy] -version = "0.8.0" default-features = false features = [ - "bevy_asset", - "bevy_core_pipeline", - "bevy_pbr", - "bevy_render", - "bevy_winit", + "bevy_asset", + "bevy_core_pipeline", + "bevy_pbr", + "bevy_render", + "bevy_winit", ] +version = "0.10.1" [profile.dev] opt-level = 3 diff --git a/examples/Cargo.toml b/examples/Cargo.toml deleted file mode 100644 index 69593e6..0000000 --- a/examples/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[workspace] -members = ["*"] -exclude = ["target"] -resolver = "2" - -[profile.dev] -opt-level = 3 diff --git a/examples/cube/src/main.rs b/examples/cube.rs similarity index 93% rename from examples/cube/src/main.rs rename to examples/cube.rs index a674d83..2e9e970 100644 --- a/examples/cube/src/main.rs +++ b/examples/cube.rs @@ -22,7 +22,7 @@ fn setup( }); commands - .spawn_bundle(PbrBundle { + .spawn(PbrBundle { mesh: mesh.clone(), material: material.clone(), transform: Transform::from_xyz(0.0, 0.0, 0.0), @@ -32,7 +32,7 @@ fn setup( .insert(Outline { enabled: true }); commands - .spawn_bundle(PbrBundle { + .spawn(PbrBundle { mesh: mesh.clone(), material: material.clone(), transform: Transform::from_xyz(-2.0, 0.0, 0.0), @@ -42,7 +42,7 @@ fn setup( .insert(Outline { enabled: true }); commands - .spawn_bundle(PbrBundle { + .spawn(PbrBundle { mesh, material, transform: Transform::from_xyz(0.0, 0.0, -2.0), @@ -52,7 +52,7 @@ fn setup( .insert(Outline { enabled: true }); commands - .spawn_bundle(Camera3dBundle { + .spawn(Camera3dBundle { transform: Transform::from_xyz(3.0, 2.0, 3.0) .looking_at([-1.0, -0.5, -1.0].into(), Vec3::Y), ..Camera3dBundle::default() @@ -65,7 +65,7 @@ fn setup( }), }); - commands.spawn_bundle(PointLightBundle { + commands.spawn(PointLightBundle { point_light: PointLight { color: Color::WHITE, intensity: 800.0, @@ -99,6 +99,7 @@ fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugin(OutlinePlugin) + // .insert_resource(Msaa::Off) .add_startup_system(setup) .add_system(rotate_cube) .add_system(handle_keys) diff --git a/examples/cube/Cargo.toml b/examples/cube/Cargo.toml deleted file mode 100644 index 58f1e62..0000000 --- a/examples/cube/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "cube" -authors = ["dataphract"] -version = "0.1.0" -edition = "2021" - -[dependencies] -bevy = { version = "0.8.0" } -bevy_jfa = { path = "../.." } diff --git a/src/graph.rs b/src/graph.rs index 9fde761..2d70fd6 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -90,7 +90,7 @@ pub fn outline(render_app: &mut App) -> Result { outline::input::VIEW_ENTITY, outline::node::MASK_PASS, MeshMaskNode::IN_VIEW, - )?; + ); // Mask -> JFA Init graph.add_slot_edge( @@ -98,7 +98,7 @@ pub fn outline(render_app: &mut App) -> Result { MeshMaskNode::OUT_MASK, outline::node::JFA_INIT_PASS, JfaInitNode::IN_MASK, - )?; + ); // Input -> JFA graph.add_slot_edge( @@ -106,7 +106,7 @@ pub fn outline(render_app: &mut App) -> Result { outline::input::VIEW_ENTITY, outline::node::JFA_PASS, JfaNode::IN_VIEW, - )?; + ); // JFA Init -> JFA graph.add_slot_edge( @@ -114,7 +114,7 @@ pub fn outline(render_app: &mut App) -> Result { JfaInitNode::OUT_JFA_INIT, outline::node::JFA_PASS, JfaNode::IN_BASE, - )?; + ); // Input -> Outline graph.add_slot_edge( @@ -122,7 +122,7 @@ pub fn outline(render_app: &mut App) -> Result { outline::input::VIEW_ENTITY, outline::node::OUTLINE_PASS, OutlineNode::IN_VIEW, - )?; + ); // JFA -> Outline graph.add_slot_edge( @@ -130,7 +130,7 @@ pub fn outline(render_app: &mut App) -> Result { JfaNode::OUT_JUMP, outline::node::OUTLINE_PASS, OutlineNode::IN_JFA, - )?; + ); Ok(graph) } diff --git a/src/jfa.rs b/src/jfa.rs index bc0f427..ba0eed6 100644 --- a/src/jfa.rs +++ b/src/jfa.rs @@ -3,7 +3,6 @@ use bevy::{ render::{ render_asset::RenderAssets, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, - render_phase::TrackedRenderPass, render_resource::{ BindGroup, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState, LoadOp, MultisampleState, Operations, PipelineCache, RenderPassColorAttachment, @@ -42,6 +41,7 @@ impl Dimensions { } } +#[derive(Resource)] pub struct JfaPipeline { cached: CachedRenderPipelineId, } @@ -51,10 +51,10 @@ impl FromWorld for JfaPipeline { let res = world.get_resource::().unwrap(); let dimensions_bind_group_layout = res.dimensions_bind_group_layout.clone(); let jfa_bind_group_layout = res.jfa_bind_group_layout.clone(); - let mut pipeline_cache = world.get_resource_mut::().unwrap(); + let pipeline_cache = world.get_resource_mut::().unwrap(); let cached = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { label: Some("outline_jfa_pipeline".into()), - layout: Some(vec![dimensions_bind_group_layout, jfa_bind_group_layout]), + layout: vec![dimensions_bind_group_layout, jfa_bind_group_layout], vertex: VertexState { shader: JFA_SHADER_HANDLE.typed::(), shader_defs: vec![], @@ -74,6 +74,7 @@ impl FromWorld for JfaPipeline { primitive: FULLSCREEN_PRIMITIVE_STATE, depth_stencil: None, multisample: MultisampleState::default(), + push_constant_ranges: vec![], }); JfaPipeline { cached } @@ -197,15 +198,11 @@ impl Node for JfaNode { store: true, }, }; - let render_pass = - render_context - .command_encoder - .begin_render_pass(&RenderPassDescriptor { - label: Some("outline_jfa"), - color_attachments: &[Some(attachment)], - depth_stencil_attachment: None, - }); - let mut tracked_pass = TrackedRenderPass::new(render_pass); + let mut tracked_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { + label: Some("outline_jfa"), + color_attachments: &[Some(attachment)], + depth_stencil_attachment: None, + }); tracked_pass.set_render_pipeline(cached_pipeline); tracked_pass.set_bind_group(0, &res.dimensions_bind_group, &[]); tracked_pass.set_bind_group(1, src, &[res.jfa_distance_offsets[exp]]); diff --git a/src/jfa_init.rs b/src/jfa_init.rs index 502873a..6293ca8 100644 --- a/src/jfa_init.rs +++ b/src/jfa_init.rs @@ -2,7 +2,6 @@ use bevy::{ prelude::*, render::{ render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, - render_phase::TrackedRenderPass, render_resource::{ CachedRenderPipelineId, ColorTargetState, ColorWrites, Face, FragmentState, FrontFace, LoadOp, MultisampleState, Operations, PipelineCache, PolygonMode, PrimitiveState, @@ -15,6 +14,7 @@ use bevy::{ use crate::{resources::OutlineResources, JFA_INIT_SHADER_HANDLE, JFA_TEXTURE_FORMAT}; +#[derive(Resource)] pub struct JfaInitPipeline { cached: CachedRenderPipelineId, } @@ -25,10 +25,10 @@ impl FromWorld for JfaInitPipeline { let dims_layout = res.dimensions_bind_group_layout.clone(); let init_layout = res.jfa_init_bind_group_layout.clone(); - let mut pipeline_cache = world.get_resource_mut::().unwrap(); + let pipeline_cache = world.get_resource_mut::().unwrap(); let cached = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor { label: Some("outline_jfa_init_pipeline".into()), - layout: Some(vec![dims_layout, init_layout]), + layout: vec![dims_layout, init_layout], vertex: VertexState { shader: JFA_INIT_SHADER_HANDLE.typed::(), shader_defs: vec![], @@ -56,6 +56,7 @@ impl FromWorld for JfaInitPipeline { write_mask: ColorWrites::ALL, })], }), + push_constant_ranges: vec![], }); JfaInitPipeline { cached } @@ -115,29 +116,26 @@ impl Node for JfaInitNode { } }; - let render_pass = render_context - .command_encoder - .begin_render_pass(&RenderPassDescriptor { - label: Some("outline_jfa_init"), - color_attachments: &[Some(RenderPassColorAttachment { - view: &res.jfa_primary_output.default_view, - resolve_target: None, - ops: Operations { - load: LoadOp::Clear( - Color::RgbaLinear { - red: -1.0, - green: -1.0, - blue: 0.0, - alpha: 0.0, - } - .into(), - ), - store: true, - }, - })], - depth_stencil_attachment: None, - }); - let mut tracked_pass = TrackedRenderPass::new(render_pass); + let mut tracked_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { + label: Some("outline_jfa_init"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &res.jfa_primary_output.default_view, + resolve_target: None, + ops: Operations { + load: LoadOp::Clear( + Color::RgbaLinear { + red: -1.0, + green: -1.0, + blue: 0.0, + alpha: 0.0, + } + .into(), + ), + store: true, + }, + })], + depth_stencil_attachment: None, + }); tracked_pass.set_render_pipeline(cached_pipeline); tracked_pass.set_bind_group(0, &res.dimensions_bind_group, &[]); tracked_pass.set_bind_group(1, &res.jfa_init_bind_group, &[]); diff --git a/src/lib.rs b/src/lib.rs index fae682f..b104c59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,12 +34,12 @@ use bevy::{ render_graph::RenderGraph, render_phase::{ AddRenderCommand, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, - EntityPhaseItem, PhaseItem, RenderPhase, SetItemPipeline, + PhaseItem, RenderPhase, SetItemPipeline, }, render_resource::*, renderer::{RenderDevice, RenderQueue}, view::{ExtractedView, VisibleEntities}, - Extract, RenderApp, RenderStage, + Extract, RenderApp, RenderSet, }, utils::FloatOrd, }; @@ -74,7 +74,7 @@ const FULLSCREEN_PRIMITIVE_STATE: PrimitiveState = PrimitiveState { pub struct OutlinePlugin; /// Performance and visual quality settings for JFA-based outlines. -#[derive(Clone, ExtractResource)] +#[derive(Clone, ExtractResource, Resource)] pub struct OutlineSettings { pub(crate) half_resolution: bool, } @@ -154,31 +154,27 @@ impl Plugin for OutlinePlugin { .init_resource::() .init_resource::() .init_resource::>() - .add_system_to_stage(RenderStage::Extract, extract_outline_settings) - .add_system_to_stage(RenderStage::Extract, extract_camera_outlines) - .add_system_to_stage(RenderStage::Extract, extract_mask_camera_phase) - .add_system_to_stage(RenderStage::Prepare, resources::recreate_outline_resources) - .add_system_to_stage(RenderStage::Queue, queue_mesh_masks); + .add_system(extract_outline_settings.in_schedule(ExtractSchedule)) + .add_system(extract_camera_outlines.in_schedule(ExtractSchedule)) + .add_system(extract_mask_camera_phase.in_schedule(ExtractSchedule)) + .add_system(resources::recreate_outline_resources.in_set(RenderSet::Queue)) + .add_system(queue_mesh_masks.in_set(RenderSet::Queue)); let outline_graph = graph::outline(render_app).unwrap(); let mut root_graph = render_app.world.resource_mut::(); let draw_3d_graph = root_graph.get_sub_graph_mut(core_3d::graph::NAME).unwrap(); - let draw_3d_input = draw_3d_graph.input_node().unwrap().id; + let draw_3d_input = draw_3d_graph.input_node().id; draw_3d_graph.add_sub_graph(outline_graph::NAME, outline_graph); let outline_driver = draw_3d_graph.add_node(OutlineDriverNode::NAME, OutlineDriverNode); - draw_3d_graph - .add_slot_edge( - draw_3d_input, - core_3d::graph::input::VIEW_ENTITY, - outline_driver, - OutlineDriverNode::INPUT_VIEW, - ) - .unwrap(); - draw_3d_graph - .add_node_edge(core_3d::graph::node::MAIN_PASS, outline_driver) - .unwrap(); + draw_3d_graph.add_slot_edge( + draw_3d_input, + core_3d::graph::input::VIEW_ENTITY, + outline_driver, + OutlineDriverNode::INPUT_VIEW, + ); + draw_3d_graph.add_node_edge(core_3d::graph::node::MAIN_PASS, outline_driver); } } @@ -199,9 +195,7 @@ impl PhaseItem for MeshMask { fn draw_function(&self) -> DrawFunctionId { self.draw_function } -} -impl EntityPhaseItem for MeshMask { fn entity(&self) -> Entity { self.entity } diff --git a/src/mask.rs b/src/mask.rs index 72f9bed..eef5d80 100644 --- a/src/mask.rs +++ b/src/mask.rs @@ -2,9 +2,9 @@ use bevy::{ pbr::{MeshPipeline, MeshPipelineKey}, prelude::*, render::{ - mesh::InnerMeshVertexBufferLayout, + mesh::MeshVertexBufferLayout, render_graph::{Node, RenderGraphContext, SlotInfo, SlotType}, - render_phase::{DrawFunctions, PhaseItem, RenderPhase, TrackedRenderPass}, + render_phase::RenderPhase, render_resource::{ ColorTargetState, ColorWrites, FragmentState, LoadOp, MultisampleState, Operations, RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, @@ -12,11 +12,11 @@ use bevy::{ }, renderer::RenderContext, }, - utils::{FixedState, Hashed}, }; use crate::{resources::OutlineResources, MeshMask, MASK_SHADER_HANDLE}; +#[derive(Resource)] pub struct MeshMaskPipeline { mesh_pipeline: MeshPipeline, } @@ -35,14 +35,14 @@ impl SpecializedMeshPipeline for MeshMaskPipeline { fn specialize( &self, key: Self::Key, - layout: &Hashed, + layout: &MeshVertexBufferLayout, ) -> Result { let mut desc = self.mesh_pipeline.specialize(key, layout)?; - desc.layout = Some(vec![ - self.mesh_pipeline.view_layout.clone(), + desc.layout = vec![ + self.mesh_pipeline.view_layout_multisampled.clone(), self.mesh_pipeline.mesh_layout.clone(), - ]); + ]; desc.vertex.shader = MASK_SHADER_HANDLE.typed::(); @@ -117,33 +117,24 @@ impl Node for MeshMaskNode { .unwrap(); let view_entity = graph.get_input_entity(Self::IN_VIEW).unwrap(); - let stencil_phase = match self.query.get_manual(world, view_entity) { - Ok(q) => q, - Err(_) => return Ok(()), + let Ok(stencil_phase) = self.query.get_manual(world, view_entity) else { + return Ok(()); }; - let pass_raw = render_context - .command_encoder - .begin_render_pass(&RenderPassDescriptor { - label: Some("outline_stencil_render_pass"), - color_attachments: &[Some(RenderPassColorAttachment { - view: &res.mask_multisample.default_view, - resolve_target: Some(&res.mask_output.default_view), - ops: Operations { - load: LoadOp::Clear(Color::BLACK.into()), - store: true, - }, - })], - depth_stencil_attachment: None, - }); - let mut pass = TrackedRenderPass::new(pass_raw); - - let draw_functions = world.get_resource::>().unwrap(); - let mut draw_functions = draw_functions.write(); - for item in stencil_phase.items.iter() { - let draw_function = draw_functions.get_mut(item.draw_function()).unwrap(); - draw_function.draw(world, &mut pass, view_entity, item); - } + let mut tracked_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { + label: Some("outline_stencil_render_pass"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &res.mask_multisample.default_view, + resolve_target: Some(&res.mask_output.default_view), + ops: Operations { + load: LoadOp::Clear(Color::BLACK.into()), + store: true, + }, + })], + depth_stencil_attachment: None, + }); + + stencil_phase.render(&mut tracked_pass, world, view_entity); Ok(()) } diff --git a/src/outline.rs b/src/outline.rs index 794c1de..bbaa783 100644 --- a/src/outline.rs +++ b/src/outline.rs @@ -1,10 +1,8 @@ use bevy::{ prelude::*, render::{ - camera::ExtractedCamera, render_asset::RenderAssets, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, - render_phase::TrackedRenderPass, render_resource::{ BindGroup, BindGroupLayout, BlendComponent, BlendFactor, BlendOperation, BlendState, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState, LoadOp, @@ -14,7 +12,7 @@ use bevy::{ UniformBuffer, VertexState, }, renderer::RenderContext, - view::ExtractedWindows, + view::ViewTarget, }, }; @@ -45,7 +43,7 @@ pub struct GpuOutlineParams { pub(crate) bind_group: BindGroup, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Resource)] pub struct OutlinePipeline { dimensions_layout: BindGroupLayout, input_layout: BindGroupLayout, @@ -112,11 +110,11 @@ impl SpecializedRenderPipeline for OutlinePipeline { RenderPipelineDescriptor { label: Some("jfa_outline_pipeline".into()), - layout: Some(vec![ + layout: vec![ self.dimensions_layout.clone(), self.input_layout.clone(), self.params_layout.clone(), - ]), + ], vertex: VertexState { shader: OUTLINE_SHADER_HANDLE.typed::(), shader_defs: vec![], @@ -140,13 +138,14 @@ impl SpecializedRenderPipeline for OutlinePipeline { mask: !0, alpha_to_coverage_enabled: false, }, + push_constant_ranges: vec![], } } } pub struct OutlineNode { pipeline_id: CachedRenderPipelineId, - query: QueryState<(&'static ExtractedCamera, &'static CameraOutline)>, + query: QueryState<(&'static CameraOutline, &'static ViewTarget)>, } impl OutlineNode { @@ -205,14 +204,7 @@ impl Node for OutlineNode { let view_ent = graph.get_input_entity(Self::IN_VIEW)?; graph.set_output(Self::OUT_VIEW, view_ent)?; - let (camera, outline) = &self.query.get_manual(world, view_ent).unwrap(); - - let windows = world.resource::(); - let images = world.resource::>(); - let target_view = match camera.target.get_texture_view(windows, images) { - Some(v) => v, - None => return Ok(()), - }; + let (outline, target) = self.query.get_manual(world, view_ent).unwrap(); let styles = world.resource::>(); let style = styles.get(&outline.style).unwrap(); @@ -225,23 +217,20 @@ impl Node for OutlineNode { None => return Ok(()), }; - let render_pass = render_context - .command_encoder - .begin_render_pass(&RenderPassDescriptor { - label: Some("jfa_outline"), - color_attachments: &[Some(RenderPassColorAttachment { - view: target_view, - resolve_target: None, - ops: Operations { - load: LoadOp::Load, - store: true, - }, - })], - // TODO: support outlines being occluded by world geometry - depth_stencil_attachment: None, - }); + let mut tracked_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor { + label: Some("jfa_outline"), + color_attachments: &[Some(RenderPassColorAttachment { + view: target.main_texture(), + resolve_target: None, + ops: Operations { + load: LoadOp::Load, + store: true, + }, + })], + // TODO: support outlines being occluded by world geometry + depth_stencil_attachment: None, + }); - let mut tracked_pass = TrackedRenderPass::new(render_pass); tracked_pass.set_render_pipeline(pipeline); tracked_pass.set_bind_group(0, &res.dimensions_bind_group, &[]); tracked_pass.set_bind_group(1, &res.outline_src_bind_group, &[]); diff --git a/src/resources.rs b/src/resources.rs index 170d3aa..11c37f9 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -13,7 +13,6 @@ use bevy::{ texture::{CachedTexture, TextureCache}, view::ExtractedWindows, }, - window::WindowId, }; use crate::{jfa, outline, OutlineSettings, JFA_TEXTURE_FORMAT}; @@ -22,6 +21,7 @@ const JFA_FROM_PRIMARY: &str = "jfa_from_primary_output_bind_group"; const JFA_FROM_SECONDARY: &str = "jfa_from_secondary_output_bind_group"; const JFA_OUTLINE_SRC: &str = "jfa_outline_src_bind_group"; +#[derive(Resource)] pub struct OutlineResources { // Multisample target for initial mask pass. pub mask_multisample: CachedTexture, @@ -408,9 +408,12 @@ pub fn recreate_outline_resources( mut textures: ResMut, windows: Res, ) { - let primary = match windows.get(&WindowId::primary()) { - Some(w) => w, - None => return, + let Some(primary_entity) = windows.primary else { + return + }; + + let Some(primary) = windows.get(&primary_entity) else { + return; }; let half_size = Extent3d { @@ -514,5 +517,6 @@ fn tex_desc(label: &'static str, size: Extent3d, format: TextureFormat) -> Textu dimension: TextureDimension::D2, format, usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, + view_formats: &[], } } diff --git a/src/shaders/fullscreen.wgsl b/src/shaders/fullscreen.wgsl index 99438cb..4c8f742 100644 --- a/src/shaders/fullscreen.wgsl +++ b/src/shaders/fullscreen.wgsl @@ -19,7 +19,7 @@ struct Vertex { // \ // NDC [-1, -1] / Texcoord [0, 1] // -let VERTICES: array = array( +const VERTICES: array = array( // Bottom left Vertex( vec2(-1.0, -1.0), diff --git a/src/shaders/jfa_init.wgsl b/src/shaders/jfa_init.wgsl index 365accd..9eb10ea 100644 --- a/src/shaders/jfa_init.wgsl +++ b/src/shaders/jfa_init.wgsl @@ -36,23 +36,23 @@ fn fragment(in: FragmentIn) -> @location(0) vec4 { samples[2][1] = textureSample(mask_buffer, mask_sampler, in.texcoord + vec2(dx, 0.0)).x; samples[2][2] = textureSample(mask_buffer, mask_sampler, in.texcoord + vec2(dx, dy)).x; - if (samples[1][1] > 0.99) { + if samples[1][1] > 0.99 { return out_position; } - if (samples[1][1] < 0.01) { + if samples[1][1] < 0.01 { return vec4(-1.0, -1.0, 0.0, 1.0); } let sobel_x = samples[0][0] + 2.0 * samples[0][1] + samples[0][2] - samples[2][0] - 2.0 * samples[2][1] - samples[2][2]; let sobel_y = samples[0][0] + 2.0 * samples[1][0] + samples[2][0] - samples[0][2] - 2.0 * samples[1][2] - samples[2][2]; - let dir = -vec2(sobel_x, sobel_y); + var dir = -vec2(sobel_x, sobel_y); - if (abs(dir.x) < 0.005 && abs(dir.y) < 0.005) { + if abs(dir.x) < 0.005 && abs(dir.y) < 0.005 { return out_position; } - let dir = normalize(dir); + dir = normalize(dir); let offset = dir * (1.0 - samples[1][1]) * vec2(dx, dy); return out_position + vec4(offset, 0.0, 1.0); diff --git a/src/shaders/mask.wgsl b/src/shaders/mask.wgsl index cc9f547..bf64887 100644 --- a/src/shaders/mask.wgsl +++ b/src/shaders/mask.wgsl @@ -1,8 +1,12 @@ // Mask generation shader. -#import bevy_pbr::mesh_view_bindings +#import bevy_render::view #import bevy_pbr::mesh_types +@group(0) @binding(0) +var view: View; + + @group(1) @binding(0) var mesh: Mesh; diff --git a/src/shaders/outline.wgsl b/src/shaders/outline.wgsl index 9270e92..44f5065 100644 --- a/src/shaders/outline.wgsl +++ b/src/shaders/outline.wgsl @@ -39,8 +39,8 @@ fn fragment(in: FragmentIn) -> @location(0) vec4 { // Computed texcoord and stored texcoord are likely to differ even if they // represent the same position due to storage as fp16, so an epsilon is // needed. - if (mask_value < 1.0) { - if (mask_value > 0.0) { + if mask_value < 1.0 { + if mask_value > 0.0 { return vec4(params.color.rgb, 1.0 - mask_value); } else { let fade = clamp(params.weight - mag, 0.0, 1.0);