Port to Bevy 0.10.
This commit is contained in:
parent
2bb0ba2b20
commit
d84e476c78
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bevy_mod_outline"
|
name = "bevy_mod_outline"
|
||||||
version = "0.3.5"
|
version = "0.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "A mesh outlining plugin for Bevy."
|
description = "A mesh outlining plugin for Bevy."
|
||||||
|
@ -11,7 +11,7 @@ keywords = ["gamedev", "bevy", "outline"]
|
||||||
categories = ["game-engines", "rendering"]
|
categories = ["game-engines", "rendering"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.9", default-features = false, features = [
|
bevy = { version = "0.10", default-features = false, features = [
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
"bevy_render",
|
"bevy_render",
|
||||||
"bevy_pbr",
|
"bevy_pbr",
|
||||||
|
@ -22,7 +22,7 @@ interpolation = "0.2"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bevy = { version = "0.9", default-features = false, features = [
|
bevy = { version = "0.10", default-features = false, features = [
|
||||||
"bevy_winit",
|
"bevy_winit",
|
||||||
"x11",
|
"x11",
|
||||||
] }
|
] }
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use bevy::{prelude::*, scene::SceneInstance, window::close_on_esc};
|
use bevy::{
|
||||||
|
prelude::{shape::Plane, *},
|
||||||
|
scene::SceneInstance,
|
||||||
|
window::close_on_esc,
|
||||||
|
};
|
||||||
use bevy_mod_outline::{
|
use bevy_mod_outline::{
|
||||||
AutoGenerateOutlineNormalsPlugin, OutlineBundle, OutlinePlugin, OutlineVolume,
|
AutoGenerateOutlineNormalsPlugin, OutlineBundle, OutlinePlugin, OutlineVolume,
|
||||||
};
|
};
|
||||||
|
@ -41,7 +45,10 @@ fn setup(
|
||||||
|
|
||||||
// Plane
|
// Plane
|
||||||
commands.spawn(PbrBundle {
|
commands.spawn(PbrBundle {
|
||||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 500000.0 })),
|
mesh: meshes.add(Mesh::from(Plane {
|
||||||
|
size: 500000.0,
|
||||||
|
subdivisions: 0,
|
||||||
|
})),
|
||||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::f32::consts::TAU;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::{
|
prelude::{
|
||||||
shape::{Capsule, Torus, UVSphere},
|
shape::{Capsule, Plane, Torus, UVSphere},
|
||||||
*,
|
*,
|
||||||
},
|
},
|
||||||
window::close_on_esc,
|
window::close_on_esc,
|
||||||
|
@ -13,7 +13,7 @@ use bevy_mod_outline::*;
|
||||||
#[bevy_main]
|
#[bevy_main]
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(Msaa { samples: 4 })
|
.insert_resource(Msaa::Sample4)
|
||||||
.insert_resource(ClearColor(Color::BLACK))
|
.insert_resource(ClearColor(Color::BLACK))
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugin(OutlinePlugin)
|
.add_plugin(OutlinePlugin)
|
||||||
|
@ -101,7 +101,10 @@ fn setup(
|
||||||
|
|
||||||
// Add plane, light source, and camera
|
// Add plane, light source, and camera
|
||||||
commands.spawn(PbrBundle {
|
commands.spawn(PbrBundle {
|
||||||
mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })),
|
mesh: meshes.add(Mesh::from(Plane {
|
||||||
|
size: 5.0,
|
||||||
|
subdivisions: 0,
|
||||||
|
})),
|
||||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,16 +2,19 @@ use std::f32::consts::PI;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
core_pipeline::clear_color::ClearColorConfig,
|
core_pipeline::clear_color::ClearColorConfig,
|
||||||
prelude::{shape::Torus, *},
|
prelude::{
|
||||||
|
shape::{Plane, Torus},
|
||||||
|
*,
|
||||||
|
},
|
||||||
render::{camera::Viewport, view::RenderLayers},
|
render::{camera::Viewport, view::RenderLayers},
|
||||||
window::close_on_esc,
|
window::{close_on_esc, PrimaryWindow},
|
||||||
};
|
};
|
||||||
use bevy_mod_outline::{OutlineBundle, OutlinePlugin, OutlineRenderLayers, OutlineVolume};
|
use bevy_mod_outline::{OutlineBundle, OutlinePlugin, OutlineRenderLayers, OutlineVolume};
|
||||||
|
|
||||||
#[bevy_main]
|
#[bevy_main]
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(Msaa { samples: 4 })
|
.insert_resource(Msaa::Sample4)
|
||||||
.insert_resource(ClearColor(Color::BLACK))
|
.insert_resource(ClearColor(Color::BLACK))
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugin(OutlinePlugin)
|
.add_plugin(OutlinePlugin)
|
||||||
|
@ -62,7 +65,10 @@ fn setup(
|
||||||
|
|
||||||
// Add plane and light source
|
// Add plane and light source
|
||||||
commands.spawn(PbrBundle {
|
commands.spawn(PbrBundle {
|
||||||
mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })),
|
mesh: meshes.add(Mesh::from(Plane {
|
||||||
|
size: 5.0,
|
||||||
|
subdivisions: 0,
|
||||||
|
})),
|
||||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
@ -90,7 +96,7 @@ fn setup(
|
||||||
commands
|
commands
|
||||||
.spawn(Camera3dBundle {
|
.spawn(Camera3dBundle {
|
||||||
camera: Camera {
|
camera: Camera {
|
||||||
priority: i,
|
order: i,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
camera_3d: Camera3d {
|
camera_3d: Camera3d {
|
||||||
|
@ -112,10 +118,13 @@ fn setup(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_camera_viewports(windows: Res<Windows>, mut query: Query<(&mut Camera, &CameraMode)>) {
|
fn set_camera_viewports(
|
||||||
if windows.is_changed() {
|
win_query: Query<(&Window, Changed<Window>), With<PrimaryWindow>>,
|
||||||
|
mut query: Query<(&mut Camera, &CameraMode)>,
|
||||||
|
) {
|
||||||
|
let (win, win_changed) = win_query.get_single().unwrap();
|
||||||
|
if win_changed {
|
||||||
// Divide window into quadrants
|
// Divide window into quadrants
|
||||||
let win = windows.primary();
|
|
||||||
let size = UVec2::new(win.physical_width() / 2, win.physical_height() / 2);
|
let size = UVec2::new(win.physical_width() / 2, win.physical_height() / 2);
|
||||||
for (mut camera, mode) in query.iter_mut() {
|
for (mut camera, mode) in query.iter_mut() {
|
||||||
let offset = UVec2::new(
|
let offset = UVec2::new(
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::f32::consts::{PI, TAU};
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::{
|
prelude::{
|
||||||
shape::{Cube, Torus},
|
shape::{Cube, Plane, Torus},
|
||||||
*,
|
*,
|
||||||
},
|
},
|
||||||
window::close_on_esc,
|
window::close_on_esc,
|
||||||
|
@ -13,7 +13,7 @@ use bevy_mod_outline::*;
|
||||||
#[bevy_main]
|
#[bevy_main]
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(Msaa { samples: 4 })
|
.insert_resource(Msaa::Sample4)
|
||||||
.insert_resource(ClearColor(Color::BLACK))
|
.insert_resource(ClearColor(Color::BLACK))
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugin(OutlinePlugin)
|
.add_plugin(OutlinePlugin)
|
||||||
|
@ -81,7 +81,10 @@ fn setup(
|
||||||
|
|
||||||
// Add plane, light source, and camera
|
// Add plane, light source, and camera
|
||||||
commands.spawn(PbrBundle {
|
commands.spawn(PbrBundle {
|
||||||
mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })),
|
mesh: meshes.add(Mesh::from(Plane {
|
||||||
|
size: 5.0,
|
||||||
|
subdivisions: 0,
|
||||||
|
})),
|
||||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
|
12
src/draw.rs
12
src/draw.rs
|
@ -29,7 +29,7 @@ pub(crate) fn queue_outline_stencil_mesh(
|
||||||
stencil_pipeline: Res<OutlinePipeline>,
|
stencil_pipeline: Res<OutlinePipeline>,
|
||||||
msaa: Res<Msaa>,
|
msaa: Res<Msaa>,
|
||||||
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
|
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
|
||||||
mut pipeline_cache: ResMut<PipelineCache>,
|
pipeline_cache: Res<PipelineCache>,
|
||||||
render_meshes: Res<RenderAssets<Mesh>>,
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
material_meshes: Query<(
|
material_meshes: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
|
@ -50,7 +50,7 @@ pub(crate) fn queue_outline_stencil_mesh(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let base_key = PipelineKey::new()
|
let base_key = PipelineKey::new()
|
||||||
.with_msaa_samples(msaa.samples)
|
.with_msaa(*msaa)
|
||||||
.with_pass_type(PassType::Stencil);
|
.with_pass_type(PassType::Stencil);
|
||||||
|
|
||||||
for (view, mut stencil_phase, view_mask) in views.iter_mut() {
|
for (view, mut stencil_phase, view_mask) in views.iter_mut() {
|
||||||
|
@ -68,7 +68,7 @@ pub(crate) fn queue_outline_stencil_mesh(
|
||||||
.with_depth_mode(stencil_flags.depth_mode)
|
.with_depth_mode(stencil_flags.depth_mode)
|
||||||
.with_offset_zero(stencil_uniform.offset == 0.0);
|
.with_offset_zero(stencil_uniform.offset == 0.0);
|
||||||
let pipeline = pipelines
|
let pipeline = pipelines
|
||||||
.specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout)
|
.specialize(&pipeline_cache, &stencil_pipeline, key, &mesh.layout)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let distance =
|
let distance =
|
||||||
rangefinder.distance(&Mat4::from_translation(stencil_uniform.origin));
|
rangefinder.distance(&Mat4::from_translation(stencil_uniform.origin));
|
||||||
|
@ -99,7 +99,7 @@ pub(crate) fn queue_outline_volume_mesh(
|
||||||
outline_pipeline: Res<OutlinePipeline>,
|
outline_pipeline: Res<OutlinePipeline>,
|
||||||
msaa: Res<Msaa>,
|
msaa: Res<Msaa>,
|
||||||
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
|
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
|
||||||
mut pipeline_cache: ResMut<PipelineCache>,
|
pipeline_cache: Res<PipelineCache>,
|
||||||
render_meshes: Res<RenderAssets<Mesh>>,
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
material_meshes: Query<(
|
material_meshes: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
|
@ -125,7 +125,7 @@ pub(crate) fn queue_outline_volume_mesh(
|
||||||
.get_id::<DrawOutline>()
|
.get_id::<DrawOutline>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let base_key = PipelineKey::new().with_msaa_samples(msaa.samples);
|
let base_key = PipelineKey::new().with_msaa(*msaa);
|
||||||
|
|
||||||
for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() {
|
for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() {
|
||||||
let view_mask = view_mask.copied().unwrap_or_default();
|
let view_mask = view_mask.copied().unwrap_or_default();
|
||||||
|
@ -149,7 +149,7 @@ pub(crate) fn queue_outline_volume_mesh(
|
||||||
.with_offset_zero(volume_uniform.offset == 0.0)
|
.with_offset_zero(volume_uniform.offset == 0.0)
|
||||||
.with_hdr_format(view.hdr);
|
.with_hdr_format(view.hdr);
|
||||||
let pipeline = pipelines
|
let pipeline = pipelines
|
||||||
.specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout)
|
.specialize(&pipeline_cache, &outline_pipeline, key, &mesh.layout)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let distance = rangefinder.distance(&Mat4::from_translation(volume_uniform.origin));
|
let distance = rangefinder.distance(&Mat4::from_translation(volume_uniform.origin));
|
||||||
if transparent {
|
if transparent {
|
||||||
|
|
86
src/lib.rs
86
src/lib.rs
|
@ -31,7 +31,7 @@ use bevy::render::render_graph::RenderGraph;
|
||||||
use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
|
use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
|
||||||
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
|
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
|
||||||
use bevy::render::view::RenderLayers;
|
use bevy::render::view::RenderLayers;
|
||||||
use bevy::render::{RenderApp, RenderStage};
|
use bevy::render::{RenderApp, RenderSet};
|
||||||
use bevy::transform::TransformSystem;
|
use bevy::transform::TransformSystem;
|
||||||
use interpolation::Lerp;
|
use interpolation::Lerp;
|
||||||
|
|
||||||
|
@ -82,9 +82,10 @@ pub struct OutlineStencil {
|
||||||
impl ExtractComponent for OutlineStencil {
|
impl ExtractComponent for OutlineStencil {
|
||||||
type Query = &'static OutlineStencil;
|
type Query = &'static OutlineStencil;
|
||||||
type Filter = ();
|
type Filter = ();
|
||||||
|
type Out = Self;
|
||||||
|
|
||||||
fn extract_component(item: QueryItem<Self::Query>) -> Self {
|
fn extract_component(item: QueryItem<Self::Query>) -> Option<Self> {
|
||||||
item.clone()
|
Some(item.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,14 +144,17 @@ impl ExtractComponent for OutlineRenderLayers {
|
||||||
Option<&'static RenderLayers>,
|
Option<&'static RenderLayers>,
|
||||||
);
|
);
|
||||||
type Filter = Or<(With<OutlineVolume>, With<OutlineStencil>)>;
|
type Filter = Or<(With<OutlineVolume>, With<OutlineStencil>)>;
|
||||||
|
type Out = Self;
|
||||||
|
|
||||||
fn extract_component(
|
fn extract_component(
|
||||||
(outline_mask, object_mask): (Option<&OutlineRenderLayers>, Option<&RenderLayers>),
|
(outline_mask, object_mask): (Option<&OutlineRenderLayers>, Option<&RenderLayers>),
|
||||||
) -> Self {
|
) -> Option<Self> {
|
||||||
outline_mask
|
Some(
|
||||||
.copied()
|
outline_mask
|
||||||
.or_else(|| object_mask.copied().map(OutlineRenderLayers))
|
.copied()
|
||||||
.unwrap_or_default()
|
.or_else(|| object_mask.copied().map(OutlineRenderLayers))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,9 +197,10 @@ impl Plugin for OutlinePlugin {
|
||||||
.add_plugin(UniformComponentPlugin::<OutlineVolumeUniform>::default())
|
.add_plugin(UniformComponentPlugin::<OutlineVolumeUniform>::default())
|
||||||
.add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default())
|
.add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default())
|
||||||
.add_plugin(UniformComponentPlugin::<OutlineViewUniform>::default())
|
.add_plugin(UniformComponentPlugin::<OutlineViewUniform>::default())
|
||||||
.add_system_to_stage(
|
.add_system(
|
||||||
CoreStage::PostUpdate,
|
compute_outline_depth
|
||||||
compute_outline_depth.after(TransformSystem::TransformPropagate),
|
.in_base_set(CoreSet::PostUpdate)
|
||||||
|
.after(TransformSystem::TransformPropagate),
|
||||||
)
|
)
|
||||||
.sub_app_mut(RenderApp)
|
.sub_app_mut(RenderApp)
|
||||||
.init_resource::<DrawFunctions<StencilOutline>>()
|
.init_resource::<DrawFunctions<StencilOutline>>()
|
||||||
|
@ -206,20 +211,17 @@ impl Plugin for OutlinePlugin {
|
||||||
.add_render_command::<StencilOutline, DrawStencil>()
|
.add_render_command::<StencilOutline, DrawStencil>()
|
||||||
.add_render_command::<OpaqueOutline, DrawOutline>()
|
.add_render_command::<OpaqueOutline, DrawOutline>()
|
||||||
.add_render_command::<TransparentOutline, DrawOutline>()
|
.add_render_command::<TransparentOutline, DrawOutline>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_outline_view_uniforms)
|
.add_system(extract_outline_view_uniforms.in_schedule(ExtractSchedule))
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_outline_stencil_uniforms)
|
.add_system(extract_outline_stencil_uniforms.in_schedule(ExtractSchedule))
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_outline_volume_uniforms)
|
.add_system(extract_outline_volume_uniforms.in_schedule(ExtractSchedule))
|
||||||
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<StencilOutline>)
|
.add_system(sort_phase_system::<StencilOutline>.in_set(RenderSet::PhaseSort))
|
||||||
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<OpaqueOutline>)
|
.add_system(sort_phase_system::<OpaqueOutline>.in_set(RenderSet::PhaseSort))
|
||||||
.add_system_to_stage(
|
.add_system(sort_phase_system::<TransparentOutline>.in_set(RenderSet::PhaseSort))
|
||||||
RenderStage::PhaseSort,
|
.add_system(queue_outline_view_bind_group.in_set(RenderSet::Queue))
|
||||||
sort_phase_system::<TransparentOutline>,
|
.add_system(queue_outline_stencil_bind_group.in_set(RenderSet::Queue))
|
||||||
)
|
.add_system(queue_outline_volume_bind_group.in_set(RenderSet::Queue))
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_outline_view_bind_group)
|
.add_system(queue_outline_stencil_mesh.in_set(RenderSet::Queue))
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_outline_stencil_bind_group)
|
.add_system(queue_outline_volume_mesh.in_set(RenderSet::Queue));
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_outline_volume_bind_group)
|
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_outline_stencil_mesh)
|
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_outline_volume_mesh);
|
|
||||||
|
|
||||||
let world = &mut app.sub_app_mut(RenderApp).world;
|
let world = &mut app.sub_app_mut(RenderApp).world;
|
||||||
let node = OutlineNode::new(world);
|
let node = OutlineNode::new(world);
|
||||||
|
@ -230,28 +232,22 @@ impl Plugin for OutlinePlugin {
|
||||||
.get_sub_graph_mut(bevy::core_pipeline::core_3d::graph::NAME)
|
.get_sub_graph_mut(bevy::core_pipeline::core_3d::graph::NAME)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
draw_3d_graph.add_node(OUTLINE_PASS_NODE_NAME, node);
|
draw_3d_graph.add_node(OUTLINE_PASS_NODE_NAME, node);
|
||||||
draw_3d_graph
|
draw_3d_graph.add_slot_edge(
|
||||||
.add_slot_edge(
|
draw_3d_graph.input_node().id,
|
||||||
draw_3d_graph.input_node().unwrap().id,
|
bevy::core_pipeline::core_3d::graph::input::VIEW_ENTITY,
|
||||||
bevy::core_pipeline::core_3d::graph::input::VIEW_ENTITY,
|
OUTLINE_PASS_NODE_NAME,
|
||||||
OUTLINE_PASS_NODE_NAME,
|
OutlineNode::IN_VIEW,
|
||||||
OutlineNode::IN_VIEW,
|
);
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Run after main 3D pass, but before UI psss
|
// Run after main 3D pass, but before UI psss
|
||||||
draw_3d_graph
|
draw_3d_graph.add_node_edge(
|
||||||
.add_node_edge(
|
bevy::core_pipeline::core_3d::graph::node::MAIN_PASS,
|
||||||
bevy::core_pipeline::core_3d::graph::node::MAIN_PASS,
|
OUTLINE_PASS_NODE_NAME,
|
||||||
OUTLINE_PASS_NODE_NAME,
|
);
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
#[cfg(feature = "bevy_ui")]
|
#[cfg(feature = "bevy_ui")]
|
||||||
draw_3d_graph
|
draw_3d_graph.add_node_edge(
|
||||||
.add_node_edge(
|
OUTLINE_PASS_NODE_NAME,
|
||||||
OUTLINE_PASS_NODE_NAME,
|
bevy::ui::draw_ui_graph::node::UI_PASS,
|
||||||
bevy::ui::draw_ui_graph::node::UI_PASS,
|
);
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
75
src/node.rs
75
src/node.rs
|
@ -5,8 +5,7 @@ use bevy::prelude::*;
|
||||||
use bevy::render::camera::ExtractedCamera;
|
use bevy::render::camera::ExtractedCamera;
|
||||||
use bevy::render::render_graph::{NodeRunError, SlotInfo, SlotType};
|
use bevy::render::render_graph::{NodeRunError, SlotInfo, SlotType};
|
||||||
use bevy::render::render_phase::{
|
use bevy::render::render_phase::{
|
||||||
CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem,
|
CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem, RenderPhase,
|
||||||
RenderPhase, TrackedRenderPass,
|
|
||||||
};
|
};
|
||||||
use bevy::render::render_resource::{
|
use bevy::render::render_resource::{
|
||||||
CachedRenderPipelineId, LoadOp, Operations, RenderPassDepthStencilAttachment,
|
CachedRenderPipelineId, LoadOp, Operations, RenderPassDepthStencilAttachment,
|
||||||
|
@ -29,6 +28,11 @@ pub(crate) struct StencilOutline {
|
||||||
impl PhaseItem for StencilOutline {
|
impl PhaseItem for StencilOutline {
|
||||||
type SortKey = Reverse<FloatOrd>;
|
type SortKey = Reverse<FloatOrd>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn entity(&self) -> Entity {
|
||||||
|
self.entity
|
||||||
|
}
|
||||||
|
|
||||||
fn sort_key(&self) -> Self::SortKey {
|
fn sort_key(&self) -> Self::SortKey {
|
||||||
Reverse(FloatOrd(self.distance))
|
Reverse(FloatOrd(self.distance))
|
||||||
}
|
}
|
||||||
|
@ -38,13 +42,6 @@ impl PhaseItem for StencilOutline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityPhaseItem for StencilOutline {
|
|
||||||
#[inline]
|
|
||||||
fn entity(&self) -> Entity {
|
|
||||||
self.entity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CachedRenderPipelinePhaseItem for StencilOutline {
|
impl CachedRenderPipelinePhaseItem for StencilOutline {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||||
|
@ -62,6 +59,11 @@ pub(crate) struct OpaqueOutline {
|
||||||
impl PhaseItem for OpaqueOutline {
|
impl PhaseItem for OpaqueOutline {
|
||||||
type SortKey = Reverse<FloatOrd>;
|
type SortKey = Reverse<FloatOrd>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn entity(&self) -> Entity {
|
||||||
|
self.entity
|
||||||
|
}
|
||||||
|
|
||||||
fn sort_key(&self) -> Self::SortKey {
|
fn sort_key(&self) -> Self::SortKey {
|
||||||
Reverse(FloatOrd(self.distance))
|
Reverse(FloatOrd(self.distance))
|
||||||
}
|
}
|
||||||
|
@ -71,13 +73,6 @@ impl PhaseItem for OpaqueOutline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityPhaseItem for OpaqueOutline {
|
|
||||||
#[inline]
|
|
||||||
fn entity(&self) -> Entity {
|
|
||||||
self.entity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CachedRenderPipelinePhaseItem for OpaqueOutline {
|
impl CachedRenderPipelinePhaseItem for OpaqueOutline {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||||
|
@ -95,6 +90,11 @@ pub(crate) struct TransparentOutline {
|
||||||
impl PhaseItem for TransparentOutline {
|
impl PhaseItem for TransparentOutline {
|
||||||
type SortKey = FloatOrd;
|
type SortKey = FloatOrd;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn entity(&self) -> Entity {
|
||||||
|
self.entity
|
||||||
|
}
|
||||||
|
|
||||||
fn sort_key(&self) -> Self::SortKey {
|
fn sort_key(&self) -> Self::SortKey {
|
||||||
FloatOrd(self.distance)
|
FloatOrd(self.distance)
|
||||||
}
|
}
|
||||||
|
@ -104,13 +104,6 @@ impl PhaseItem for TransparentOutline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityPhaseItem for TransparentOutline {
|
|
||||||
#[inline]
|
|
||||||
fn entity(&self) -> Entity {
|
|
||||||
self.entity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CachedRenderPipelinePhaseItem for TransparentOutline {
|
impl CachedRenderPipelinePhaseItem for TransparentOutline {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||||
|
@ -182,19 +175,11 @@ impl Node for OutlineNode {
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let draw_functions = world.resource::<DrawFunctions<StencilOutline>>();
|
let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor);
|
||||||
let render_pass = render_context
|
|
||||||
.command_encoder
|
|
||||||
.begin_render_pass(&pass_descriptor);
|
|
||||||
let mut draw_functions = draw_functions.write();
|
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
if let Some(viewport) = camera.viewport.as_ref() {
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
tracked_pass.set_camera_viewport(viewport);
|
||||||
}
|
}
|
||||||
for item in &stencil_phase.items {
|
stencil_phase.render(&mut tracked_pass, world, view_entity);
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opaque_phase.items.is_empty() {
|
if !opaque_phase.items.is_empty() {
|
||||||
|
@ -213,19 +198,11 @@ impl Node for OutlineNode {
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let draw_functions = world.resource::<DrawFunctions<OpaqueOutline>>();
|
let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor);
|
||||||
let render_pass = render_context
|
|
||||||
.command_encoder
|
|
||||||
.begin_render_pass(&pass_descriptor);
|
|
||||||
let mut draw_functions = draw_functions.write();
|
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
if let Some(viewport) = camera.viewport.as_ref() {
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
tracked_pass.set_camera_viewport(viewport);
|
||||||
}
|
}
|
||||||
for item in &opaque_phase.items {
|
opaque_phase.render(&mut tracked_pass, world, view_entity);
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !transparent_phase.items.is_empty() {
|
if !transparent_phase.items.is_empty() {
|
||||||
|
@ -244,19 +221,11 @@ impl Node for OutlineNode {
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let draw_functions = world.resource::<DrawFunctions<TransparentOutline>>();
|
let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor);
|
||||||
let render_pass = render_context
|
|
||||||
.command_encoder
|
|
||||||
.begin_render_pass(&pass_descriptor);
|
|
||||||
let mut draw_functions = draw_functions.write();
|
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
if let Some(viewport) = camera.viewport.as_ref() {
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
tracked_pass.set_camera_viewport(viewport);
|
||||||
}
|
}
|
||||||
for item in &transparent_phase.items {
|
transparent_phase.render(&mut tracked_pass, world, view_entity);
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use bevy::pbr::{MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::reflect::TypeUuid;
|
use bevy::reflect::TypeUuid;
|
||||||
use bevy::render::render_resource::{
|
use bevy::render::render_resource::{
|
||||||
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState,
|
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState,
|
||||||
BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
|
BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
|
||||||
DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode,
|
DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode,
|
||||||
PrimitiveState, PrimitiveTopology, ShaderSize, ShaderStages, StencilState, TextureFormat,
|
PrimitiveState, PrimitiveTopology, ShaderDefVal, ShaderSize, ShaderStages, StencilState,
|
||||||
VertexState,
|
TextureFormat, VertexState,
|
||||||
};
|
};
|
||||||
use bevy::render::renderer::RenderDevice;
|
use bevy::render::renderer::RenderDevice;
|
||||||
use bevy::render::texture::BevyDefault;
|
use bevy::render::texture::BevyDefault;
|
||||||
|
@ -61,13 +62,19 @@ impl PipelineKey {
|
||||||
PipelineKey(0)
|
PipelineKey(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_msaa_samples(mut self, msaa_samples: u32) -> Self {
|
pub(crate) fn with_msaa(mut self, msaa: Msaa) -> Self {
|
||||||
self.set_msaa_samples_minus_one(msaa_samples - 1);
|
self.set_msaa_samples_minus_one(msaa as u32 - 1);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn msaa_samples(&self) -> u32 {
|
pub(crate) fn msaa(&self) -> Msaa {
|
||||||
self.msaa_samples_minus_one() + 1
|
match self.msaa_samples_minus_one() + 1 {
|
||||||
|
x if x == Msaa::Off as u32 => Msaa::Off,
|
||||||
|
x if x == Msaa::Sample2 as u32 => Msaa::Sample2,
|
||||||
|
x if x == Msaa::Sample4 as u32 => Msaa::Sample4,
|
||||||
|
x if x == Msaa::Sample8 as u32 => Msaa::Sample8,
|
||||||
|
x => panic!("Invalid value for Msaa: {}", x),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_primitive_topology(mut self, primitive_topology: PrimitiveTopology) -> Self {
|
pub(crate) fn with_primitive_topology(mut self, primitive_topology: PrimitiveTopology) -> Self {
|
||||||
|
@ -213,15 +220,28 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
||||||
mesh_layout: &MeshVertexBufferLayout,
|
mesh_layout: &MeshVertexBufferLayout,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut targets = vec![];
|
let mut targets = vec![];
|
||||||
let mut bind_layouts = vec![self.mesh_pipeline.view_layout.clone()];
|
let mut bind_layouts = vec![if key.msaa() == Msaa::Off {
|
||||||
|
self.mesh_pipeline.view_layout.clone()
|
||||||
|
} else {
|
||||||
|
self.mesh_pipeline.view_layout_multisampled.clone()
|
||||||
|
}];
|
||||||
let mut buffer_attrs = vec![Mesh::ATTRIBUTE_POSITION.at_shader_location(0)];
|
let mut buffer_attrs = vec![Mesh::ATTRIBUTE_POSITION.at_shader_location(0)];
|
||||||
let mut vertex_defs = vec![];
|
let mut vertex_defs = vec![
|
||||||
|
ShaderDefVal::Int(
|
||||||
|
"MAX_CASCADES_PER_LIGHT".to_string(),
|
||||||
|
MAX_CASCADES_PER_LIGHT as i32,
|
||||||
|
),
|
||||||
|
ShaderDefVal::Int(
|
||||||
|
"MAX_DIRECTIONAL_LIGHTS".to_string(),
|
||||||
|
MAX_DIRECTIONAL_LIGHTS as i32,
|
||||||
|
),
|
||||||
|
];
|
||||||
let mut fragment_defs = vec![];
|
let mut fragment_defs = vec![];
|
||||||
bind_layouts.push(
|
bind_layouts.push(
|
||||||
if mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
|
if mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
|
||||||
&& mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
|
&& mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
|
||||||
{
|
{
|
||||||
vertex_defs.push("SKINNED".to_string());
|
vertex_defs.push(ShaderDefVal::from("SKINNED"));
|
||||||
buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(2));
|
buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(2));
|
||||||
buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(3));
|
buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(3));
|
||||||
self.mesh_pipeline.skinned_mesh_layout.clone()
|
self.mesh_pipeline.skinned_mesh_layout.clone()
|
||||||
|
@ -232,7 +252,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
||||||
bind_layouts.push(self.outline_view_bind_group_layout.clone());
|
bind_layouts.push(self.outline_view_bind_group_layout.clone());
|
||||||
let cull_mode;
|
let cull_mode;
|
||||||
if key.depth_mode() == DepthMode::Flat {
|
if key.depth_mode() == DepthMode::Flat {
|
||||||
vertex_defs.push("FLAT_DEPTH".to_string());
|
vertex_defs.push(ShaderDefVal::from("FLAT_DEPTH"));
|
||||||
cull_mode = Some(Face::Back);
|
cull_mode = Some(Face::Back);
|
||||||
} else if key.pass_type() == PassType::Stencil {
|
} else if key.pass_type() == PassType::Stencil {
|
||||||
cull_mode = Some(Face::Back);
|
cull_mode = Some(Face::Back);
|
||||||
|
@ -240,7 +260,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
||||||
cull_mode = Some(Face::Front);
|
cull_mode = Some(Face::Front);
|
||||||
}
|
}
|
||||||
if key.offset_zero() {
|
if key.offset_zero() {
|
||||||
vertex_defs.push("OFFSET_ZERO".to_string());
|
vertex_defs.push(ShaderDefVal::from("OFFSET_ZERO"));
|
||||||
} else {
|
} else {
|
||||||
buffer_attrs.push(
|
buffer_attrs.push(
|
||||||
if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) {
|
if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) {
|
||||||
|
@ -256,7 +276,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
||||||
bind_layouts.push(self.outline_stencil_bind_group_layout.clone());
|
bind_layouts.push(self.outline_stencil_bind_group_layout.clone());
|
||||||
}
|
}
|
||||||
PassType::Opaque | PassType::Transparent => {
|
PassType::Opaque | PassType::Transparent => {
|
||||||
fragment_defs.push("VOLUME".to_string());
|
fragment_defs.push(ShaderDefVal::from("VOLUME"));
|
||||||
targets.push(Some(ColorTargetState {
|
targets.push(Some(ColorTargetState {
|
||||||
format: if key.hdr_format() {
|
format: if key.hdr_format() {
|
||||||
ViewTarget::TEXTURE_FORMAT_HDR
|
ViewTarget::TEXTURE_FORMAT_HDR
|
||||||
|
@ -288,7 +308,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
||||||
entry_point: "fragment".into(),
|
entry_point: "fragment".into(),
|
||||||
targets,
|
targets,
|
||||||
}),
|
}),
|
||||||
layout: Some(bind_layouts),
|
layout: bind_layouts,
|
||||||
primitive: PrimitiveState {
|
primitive: PrimitiveState {
|
||||||
front_face: FrontFace::Ccw,
|
front_face: FrontFace::Ccw,
|
||||||
cull_mode,
|
cull_mode,
|
||||||
|
@ -315,10 +335,11 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
multisample: MultisampleState {
|
multisample: MultisampleState {
|
||||||
count: key.msaa_samples(),
|
count: key.msaa().samples(),
|
||||||
mask: !0,
|
mask: !0,
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
},
|
},
|
||||||
|
push_constant_ranges: default(),
|
||||||
label: Some(Cow::Borrowed("outline_pipeline")),
|
label: Some(Cow::Borrowed("outline_pipeline")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::system::{
|
ecs::system::{
|
||||||
lifetimeless::{Read, SQuery, SRes},
|
lifetimeless::{Read, SRes},
|
||||||
SystemParamItem,
|
SystemParamItem,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
extract_component::{ComponentUniforms, DynamicUniformIndex},
|
extract_component::{ComponentUniforms, DynamicUniformIndex},
|
||||||
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||||
render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry, ShaderType},
|
render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry, ShaderType},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
Extract,
|
Extract,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil, OutlineVolume};
|
use crate::{
|
||||||
|
node::StencilOutline, pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil,
|
||||||
|
OutlineVolume,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Component, ShaderType)]
|
#[derive(Clone, Component, ShaderType)]
|
||||||
pub(crate) struct OutlineStencilUniform {
|
pub(crate) struct OutlineStencilUniform {
|
||||||
|
@ -150,40 +153,46 @@ pub(crate) fn queue_outline_volume_bind_group(
|
||||||
|
|
||||||
pub(crate) struct SetOutlineStencilBindGroup<const I: usize>();
|
pub(crate) struct SetOutlineStencilBindGroup<const I: usize>();
|
||||||
|
|
||||||
impl<const I: usize> EntityRenderCommand for SetOutlineStencilBindGroup<I> {
|
impl<const I: usize> RenderCommand<StencilOutline> for SetOutlineStencilBindGroup<I> {
|
||||||
type Param = (
|
type ViewWorldQuery = ();
|
||||||
SRes<OutlineStencilBindGroup>,
|
type ItemWorldQuery = Read<DynamicUniformIndex<OutlineStencilUniform>>;
|
||||||
SQuery<Read<DynamicUniformIndex<OutlineStencilUniform>>>,
|
type Param = SRes<OutlineStencilBindGroup>;
|
||||||
);
|
|
||||||
fn render<'w>(
|
fn render<'w>(
|
||||||
_view: Entity,
|
_item: &StencilOutline,
|
||||||
item: Entity,
|
_view_data: (),
|
||||||
(bind_group, query): SystemParamItem<'w, '_, Self::Param>,
|
entity_data: &DynamicUniformIndex<OutlineStencilUniform>,
|
||||||
|
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let vertex = query.get(item).unwrap();
|
pass.set_bind_group(
|
||||||
pass.set_bind_group(I, &bind_group.into_inner().bind_group, &[vertex.index()]);
|
I,
|
||||||
|
&bind_group.into_inner().bind_group,
|
||||||
|
&[entity_data.index()],
|
||||||
|
);
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SetOutlineVolumeBindGroup<const I: usize>();
|
pub(crate) struct SetOutlineVolumeBindGroup<const I: usize>();
|
||||||
|
|
||||||
impl<const I: usize> EntityRenderCommand for SetOutlineVolumeBindGroup<I> {
|
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetOutlineVolumeBindGroup<I> {
|
||||||
type Param = (
|
type ViewWorldQuery = ();
|
||||||
SRes<OutlineVolumeBindGroup>,
|
type ItemWorldQuery = (
|
||||||
SQuery<(
|
Read<DynamicUniformIndex<OutlineVolumeUniform>>,
|
||||||
Read<DynamicUniformIndex<OutlineVolumeUniform>>,
|
Read<DynamicUniformIndex<OutlineFragmentUniform>>,
|
||||||
Read<DynamicUniformIndex<OutlineFragmentUniform>>,
|
|
||||||
)>,
|
|
||||||
);
|
);
|
||||||
|
type Param = SRes<OutlineVolumeBindGroup>;
|
||||||
fn render<'w>(
|
fn render<'w>(
|
||||||
_view: Entity,
|
_item: &P,
|
||||||
item: Entity,
|
_view_data: (),
|
||||||
(bind_group, query): SystemParamItem<'w, '_, Self::Param>,
|
entity_data: (
|
||||||
|
&DynamicUniformIndex<OutlineVolumeUniform>,
|
||||||
|
&DynamicUniformIndex<OutlineFragmentUniform>,
|
||||||
|
),
|
||||||
|
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let (vertex, fragment) = query.get(item).unwrap();
|
let (vertex, fragment) = entity_data;
|
||||||
pass.set_bind_group(
|
pass.set_bind_group(
|
||||||
I,
|
I,
|
||||||
&bind_group.into_inner().bind_group,
|
&bind_group.into_inner().bind_group,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use bevy::ecs::system::lifetimeless::{Read, SQuery, SRes};
|
use bevy::ecs::system::lifetimeless::{Read, SRes};
|
||||||
use bevy::ecs::system::SystemParamItem;
|
use bevy::ecs::system::SystemParamItem;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::extract_component::{ComponentUniforms, DynamicUniformIndex};
|
use bevy::render::extract_component::{ComponentUniforms, DynamicUniformIndex};
|
||||||
use bevy::render::render_phase::{
|
use bevy::render::render_phase::{
|
||||||
EntityRenderCommand, RenderCommandResult, RenderPhase, TrackedRenderPass,
|
PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, TrackedRenderPass,
|
||||||
};
|
};
|
||||||
use bevy::render::render_resource::ShaderType;
|
use bevy::render::render_resource::ShaderType;
|
||||||
use bevy::render::render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry};
|
use bevy::render::render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry};
|
||||||
|
@ -70,23 +70,18 @@ pub(crate) fn queue_outline_view_bind_group(
|
||||||
|
|
||||||
pub(crate) struct SetOutlineViewBindGroup<const I: usize>();
|
pub(crate) struct SetOutlineViewBindGroup<const I: usize>();
|
||||||
|
|
||||||
impl<const I: usize> EntityRenderCommand for SetOutlineViewBindGroup<I> {
|
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetOutlineViewBindGroup<I> {
|
||||||
type Param = (
|
type ViewWorldQuery = Read<DynamicUniformIndex<OutlineViewUniform>>;
|
||||||
SRes<OutlineViewBindGroup>,
|
type ItemWorldQuery = ();
|
||||||
SQuery<Read<DynamicUniformIndex<OutlineViewUniform>>>,
|
type Param = SRes<OutlineViewBindGroup>;
|
||||||
);
|
|
||||||
fn render<'w>(
|
fn render<'w>(
|
||||||
view: Entity,
|
_item: &P,
|
||||||
_item: Entity,
|
view_data: &DynamicUniformIndex<OutlineViewUniform>,
|
||||||
(bind_group, query): SystemParamItem<'w, '_, Self::Param>,
|
_entity_data: (),
|
||||||
|
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||||
pass: &mut TrackedRenderPass<'w>,
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
) -> RenderCommandResult {
|
) -> RenderCommandResult {
|
||||||
let view_index = query.get(view).unwrap();
|
pass.set_bind_group(I, &bind_group.into_inner().bind_group, &[view_data.index()]);
|
||||||
pass.set_bind_group(
|
|
||||||
I,
|
|
||||||
&bind_group.into_inner().bind_group,
|
|
||||||
&[view_index.index()],
|
|
||||||
);
|
|
||||||
RenderCommandResult::Success
|
RenderCommandResult::Success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue