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