Initial port to Bevy 0.13.
This commit is contained in:
parent
bcc0cdd86a
commit
fffb75b20c
|
@ -11,7 +11,7 @@ keywords = ["gamedev", "bevy", "outline"]
|
|||
categories = ["game-engines", "rendering"]
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.12", default-features = false, features = [
|
||||
bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "4ebc560dfb0fee5d3728d1d8f7362f484b784e4c", default-features = false, features = [
|
||||
"bevy_asset",
|
||||
"bevy_render",
|
||||
"bevy_pbr",
|
||||
|
@ -24,10 +24,10 @@ bitfield = "0.14"
|
|||
interpolation = "0.2"
|
||||
interpolation_03 = { package = "interpolation", version = "0.3", optional = true }
|
||||
thiserror = "1.0"
|
||||
wgpu-types = "0.17"
|
||||
wgpu-types = "0.19"
|
||||
|
||||
[dev-dependencies]
|
||||
bevy = { version = "0.12", default-features = false, features = [
|
||||
bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "4ebc560dfb0fee5d3728d1d8f7362f484b784e4c", default-features = false, features = [
|
||||
"animation",
|
||||
"bevy_gltf",
|
||||
"bevy_pbr",
|
||||
|
|
|
@ -51,7 +51,7 @@ fn setup(
|
|||
size: 500000.0,
|
||||
subdivisions: 0,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -36,18 +36,15 @@ fn setup(
|
|||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
commands.insert_resource(MyAssets {
|
||||
mesh: meshes.add(
|
||||
Capsule {
|
||||
radius: 1.0,
|
||||
rings: 10,
|
||||
depth: 2.0,
|
||||
latitudes: 15,
|
||||
longitudes: 15,
|
||||
..default()
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::BEIGE.into()),
|
||||
mesh: meshes.add(Mesh::from(Capsule {
|
||||
radius: 1.0,
|
||||
rings: 10,
|
||||
depth: 2.0,
|
||||
latitudes: 15,
|
||||
longitudes: 15,
|
||||
..default()
|
||||
})),
|
||||
material: materials.add(StandardMaterial::from(Color::BEIGE)),
|
||||
});
|
||||
|
||||
// Add light source and camera
|
||||
|
|
|
@ -32,15 +32,12 @@ fn setup(
|
|||
// Add sphere with child meshes sticking out of it
|
||||
commands
|
||||
.spawn(PbrBundle {
|
||||
mesh: meshes.add(
|
||||
UVSphere {
|
||||
radius: 0.75,
|
||||
sectors: 30,
|
||||
stacks: 30,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::rgb(0.9, 0.1, 0.1).into()),
|
||||
mesh: meshes.add(Mesh::from(UVSphere {
|
||||
radius: 0.75,
|
||||
sectors: 30,
|
||||
stacks: 30,
|
||||
})),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.9, 0.1, 0.1))),
|
||||
transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)),
|
||||
..default()
|
||||
})
|
||||
|
@ -60,18 +57,15 @@ fn setup(
|
|||
.with_children(|parent| {
|
||||
parent
|
||||
.spawn(PbrBundle {
|
||||
mesh: meshes.add(
|
||||
Capsule {
|
||||
radius: 0.2,
|
||||
rings: 15,
|
||||
depth: 1.0,
|
||||
latitudes: 15,
|
||||
longitudes: 15,
|
||||
..Default::default()
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
mesh: meshes.add(Mesh::from(Capsule {
|
||||
radius: 0.2,
|
||||
rings: 15,
|
||||
depth: 1.0,
|
||||
latitudes: 15,
|
||||
longitudes: 15,
|
||||
..Default::default()
|
||||
})),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))),
|
||||
transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::X, TAU / 4.0))
|
||||
.with_translation(Vec3::new(0.0, 0.0, 0.75)),
|
||||
..default()
|
||||
|
@ -79,16 +73,13 @@ fn setup(
|
|||
.insert(InheritOutlineBundle::default());
|
||||
parent
|
||||
.spawn(PbrBundle {
|
||||
mesh: meshes.add(
|
||||
Torus {
|
||||
radius: 0.5,
|
||||
ring_radius: 0.1,
|
||||
subdivisions_segments: 30,
|
||||
subdivisions_sides: 15,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
mesh: meshes.add(Mesh::from(Torus {
|
||||
radius: 0.5,
|
||||
ring_radius: 0.1,
|
||||
subdivisions_segments: 30,
|
||||
subdivisions_sides: 15,
|
||||
})),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))),
|
||||
transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::Z, TAU / 4.0))
|
||||
.with_translation(Vec3::new(0.0, 0.0, -0.75)),
|
||||
..default()
|
||||
|
@ -102,7 +93,7 @@ fn setup(
|
|||
size: 5.0,
|
||||
subdivisions: 0,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))),
|
||||
..default()
|
||||
});
|
||||
commands.spawn(PointLightBundle {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::f32::consts::PI;
|
||||
|
||||
use bevy::{
|
||||
core_pipeline::clear_color::ClearColorConfig,
|
||||
prelude::{
|
||||
shape::{Plane, Torus},
|
||||
*,
|
||||
|
@ -45,7 +44,7 @@ fn setup(
|
|||
subdivisions_segments: 40,
|
||||
subdivisions_sides: 20,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))),
|
||||
transform: Transform::from_rotation(Quat::from_rotation_x(0.5 * PI))
|
||||
.with_translation(0.8 * Vec3::Y),
|
||||
..default()
|
||||
|
@ -67,7 +66,7 @@ fn setup(
|
|||
size: 5.0,
|
||||
subdivisions: 0,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))),
|
||||
..default()
|
||||
});
|
||||
commands.spawn(PointLightBundle {
|
||||
|
@ -95,9 +94,6 @@ fn setup(
|
|||
.spawn(Camera3dBundle {
|
||||
camera: Camera {
|
||||
order: i,
|
||||
..default()
|
||||
},
|
||||
camera_3d: Camera3d {
|
||||
clear_color: if i > 0 {
|
||||
ClearColorConfig::None
|
||||
} else {
|
||||
|
@ -105,6 +101,7 @@ fn setup(
|
|||
},
|
||||
..default()
|
||||
},
|
||||
camera_3d: Camera3d { ..default() },
|
||||
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
})
|
||||
|
@ -117,11 +114,11 @@ fn setup(
|
|||
}
|
||||
|
||||
fn set_camera_viewports(
|
||||
win_query: Query<(&Window, Changed<Window>), With<PrimaryWindow>>,
|
||||
win_query: Query<Ref<Window>, With<PrimaryWindow>>,
|
||||
mut query: Query<(&mut Camera, &CameraMode)>,
|
||||
) {
|
||||
let (win, win_changed) = win_query.get_single().unwrap();
|
||||
if win_changed {
|
||||
let win = win_query.get_single().unwrap();
|
||||
if win.is_changed() {
|
||||
// Divide window into quadrants
|
||||
let size = UVec2::new(win.physical_width() / 2, win.physical_height() / 2);
|
||||
for (mut camera, mode) in query.iter_mut() {
|
||||
|
|
|
@ -38,7 +38,7 @@ fn setup(
|
|||
commands
|
||||
.spawn(PbrBundle {
|
||||
mesh: meshes.add(cube_mesh),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))),
|
||||
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
||||
..default()
|
||||
})
|
||||
|
@ -61,7 +61,7 @@ fn setup(
|
|||
subdivisions_segments: 20,
|
||||
subdivisions_sides: 10,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.9, 0.1, 0.1).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.9, 0.1, 0.1))),
|
||||
transform: Transform::from_xyz(0.0, 1.2, 2.0)
|
||||
.with_rotation(Quat::from_rotation_x(0.5 * PI)),
|
||||
..default()
|
||||
|
@ -82,7 +82,7 @@ fn setup(
|
|||
size: 5.0,
|
||||
subdivisions: 0,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||
material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))),
|
||||
..default()
|
||||
});
|
||||
commands.spawn(PointLightBundle {
|
||||
|
|
|
@ -58,9 +58,13 @@ impl<T: Clone + Default> Sourced<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_changed<U: Component>(&self, tuple: Option<(&U, bool)>) -> bool {
|
||||
pub fn is_changed<U: Component>(&self, tuple: &Option<Ref<U>>) -> bool {
|
||||
tuple.is_some() != matches!(self.source, Source::Set)
|
||||
|| if let Some((_, c)) = tuple { c } else { false }
|
||||
|| if let Some(r) = tuple {
|
||||
r.is_changed()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,11 +81,11 @@ pub(crate) struct ComputedInternal {
|
|||
pub struct ComputedOutline(pub(crate) Option<ComputedInternal>);
|
||||
|
||||
type OutlineComponents<'a> = (
|
||||
(&'a InheritedVisibility, Changed<InheritedVisibility>),
|
||||
(&'a GlobalTransform, Changed<GlobalTransform>),
|
||||
Option<(&'a OutlineVolume, Changed<OutlineVolume>)>,
|
||||
Option<(&'a OutlineStencil, Changed<OutlineStencil>)>,
|
||||
Option<(&'a OutlineMode, Changed<OutlineMode>)>,
|
||||
Ref<'a, InheritedVisibility>,
|
||||
Ref<'a, GlobalTransform>,
|
||||
Option<Ref<'a, OutlineVolume>>,
|
||||
Option<Ref<'a, OutlineStencil>>,
|
||||
Option<Ref<'a, OutlineMode>>,
|
||||
);
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
|
@ -150,7 +154,7 @@ fn propagate_computed_outline(
|
|||
|
||||
fn update_computed_outline(
|
||||
computed: &mut ComputedOutline,
|
||||
((visibility, changed_visibility), (transform, changed_transform), volume, stencil, mode): QueryItem<'_, OutlineComponents>,
|
||||
(visibility, transform, volume, stencil, mode): QueryItem<'_, OutlineComponents>,
|
||||
parent_computed: &ComputedInternal,
|
||||
parent_entity: Option<Entity>,
|
||||
force_update: bool,
|
||||
|
@ -158,27 +162,31 @@ fn update_computed_outline(
|
|||
let changed = force_update
|
||||
|| if let ComputedOutline(Some(computed)) = computed {
|
||||
computed.inherited_from != parent_entity
|
||||
|| changed_visibility
|
||||
|| (changed_transform && matches!(mode, Some((OutlineMode::FlatVertex { .. }, _))))
|
||||
|| computed.volume.is_changed(volume)
|
||||
|| computed.stencil.is_changed(stencil)
|
||||
|| computed.mode.is_changed(mode)
|
||||
|| visibility.is_changed()
|
||||
|| (transform.is_changed()
|
||||
&& mode
|
||||
.as_ref()
|
||||
.map(|r| matches!(r.as_ref(), OutlineMode::FlatVertex { .. }))
|
||||
.unwrap_or(false))
|
||||
|| computed.volume.is_changed(&volume)
|
||||
|| computed.stencil.is_changed(&stencil)
|
||||
|| computed.mode.is_changed(&mode)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if changed {
|
||||
*computed = ComputedOutline(Some(ComputedInternal {
|
||||
inherited_from: parent_entity,
|
||||
volume: if let Some((vol, _)) = volume {
|
||||
volume: if let Some(vol) = volume {
|
||||
Sourced::set(ComputedVolume {
|
||||
enabled: visibility.get() && vol.visible && vol.colour.a() != 0.0,
|
||||
offset: vol.width,
|
||||
colour: vol.colour.into(),
|
||||
colour: vol.colour.as_linear_rgba_f32().into(),
|
||||
})
|
||||
} else {
|
||||
Sourced::inherit(&parent_computed.volume.value)
|
||||
},
|
||||
stencil: if let Some((sten, _)) = stencil {
|
||||
stencil: if let Some(sten) = stencil {
|
||||
Sourced::set(ComputedStencil {
|
||||
enabled: visibility.get() && sten.enabled,
|
||||
offset: sten.offset,
|
||||
|
@ -186,8 +194,8 @@ fn update_computed_outline(
|
|||
} else {
|
||||
Sourced::inherit(&parent_computed.stencil.value)
|
||||
},
|
||||
mode: if let Some((m, _)) = mode {
|
||||
Sourced::set(match m {
|
||||
mode: if let Some(m) = mode {
|
||||
Sourced::set(match m.as_ref() {
|
||||
OutlineMode::FlatVertex {
|
||||
model_origin: origin,
|
||||
} => ComputedMode {
|
||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -23,18 +23,20 @@
|
|||
//! [`AutoGenerateOutlineNormalsPlugin`].
|
||||
|
||||
use bevy::asset::load_internal_asset;
|
||||
use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d};
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::batching::{batch_and_prepare_render_phase, write_batched_instance_buffer};
|
||||
use bevy::render::extract_component::{
|
||||
ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin,
|
||||
};
|
||||
use bevy::render::mesh::MeshVertexAttribute;
|
||||
use bevy::render::render_graph::RenderGraph;
|
||||
use bevy::render::render_graph::{RenderGraph, RenderLabel};
|
||||
use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
|
||||
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
|
||||
use bevy::render::view::{RenderLayers, VisibilitySystems};
|
||||
use bevy::render::{Render, RenderApp, RenderSet};
|
||||
use bevy::transform::TransformSystem;
|
||||
use bevy::ui::graph::LabelsUi;
|
||||
use interpolation::Lerp;
|
||||
|
||||
use crate::draw::{
|
||||
|
@ -72,7 +74,10 @@ pub const ATTRIBUTE_OUTLINE_NORMAL: MeshVertexAttribute =
|
|||
///
|
||||
/// This node runs after the main 3D passes and before the UI pass. The name can be used to
|
||||
/// add additional constraints on node execution order with respect to other passes.
|
||||
pub const OUTLINE_PASS_NODE_NAME: &str = "bevy_mod_outline_node";
|
||||
#[derive(Copy, Clone, Debug, RenderLabel, Hash, PartialEq, Eq)]
|
||||
pub enum LabelsOutline {
|
||||
OutlinePass,
|
||||
}
|
||||
|
||||
/// A component for stenciling meshes during outline rendering.
|
||||
#[derive(Clone, Component)]
|
||||
|
@ -108,7 +113,7 @@ impl Lerp for OutlineStencil {
|
|||
fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self {
|
||||
OutlineStencil {
|
||||
enabled: lerp_bool(self.enabled, other.enabled, *scalar),
|
||||
offset: self.offset.lerp(&other.offset, scalar),
|
||||
offset: self.offset.lerp(other.offset, *scalar),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +144,7 @@ impl Lerp for OutlineVolume {
|
|||
fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self {
|
||||
OutlineVolume {
|
||||
visible: lerp_bool(self.visible, other.visible, *scalar),
|
||||
width: self.width.lerp(&other.width, scalar),
|
||||
width: self.width.lerp(other.width, *scalar),
|
||||
colour: {
|
||||
let [r, g, b, a] = self
|
||||
.colour
|
||||
|
@ -165,11 +170,11 @@ impl interpolation_03::Lerp for OutlineVolume {
|
|||
pub struct OutlineRenderLayers(pub RenderLayers);
|
||||
|
||||
impl ExtractComponent for OutlineRenderLayers {
|
||||
type Query = (
|
||||
type QueryData = (
|
||||
Option<&'static OutlineRenderLayers>,
|
||||
Option<&'static RenderLayers>,
|
||||
);
|
||||
type Filter = With<ComputedOutline>;
|
||||
type QueryFilter = With<ComputedOutline>;
|
||||
type Out = Self;
|
||||
|
||||
fn extract_component(
|
||||
|
@ -319,21 +324,13 @@ impl Plugin for OutlinePlugin {
|
|||
|
||||
let mut graph = world.resource_mut::<RenderGraph>();
|
||||
|
||||
let draw_3d_graph = graph
|
||||
.get_sub_graph_mut(bevy::core_pipeline::core_3d::graph::NAME)
|
||||
.unwrap();
|
||||
draw_3d_graph.add_node(OUTLINE_PASS_NODE_NAME, node);
|
||||
let draw_3d_graph = graph.get_sub_graph_mut(SubGraph3d).unwrap();
|
||||
draw_3d_graph.add_node(LabelsOutline::OutlinePass, node);
|
||||
|
||||
// Run after main 3D pass, but before UI psss
|
||||
draw_3d_graph.add_node_edge(
|
||||
bevy::core_pipeline::core_3d::graph::node::END_MAIN_PASS,
|
||||
OUTLINE_PASS_NODE_NAME,
|
||||
);
|
||||
draw_3d_graph.add_node_edge(Labels3d::EndMainPass, LabelsOutline::OutlinePass);
|
||||
#[cfg(feature = "bevy_ui")]
|
||||
draw_3d_graph.add_node_edge(
|
||||
OUTLINE_PASS_NODE_NAME,
|
||||
bevy::ui::draw_ui_graph::node::UI_PASS,
|
||||
);
|
||||
draw_3d_graph.add_node_edge(LabelsOutline::OutlinePass, LabelsUi::UiPass);
|
||||
}
|
||||
|
||||
fn finish(&self, app: &mut App) {
|
||||
|
|
30
src/node.rs
30
src/node.rs
|
@ -10,7 +10,7 @@ use bevy::render::render_phase::{
|
|||
};
|
||||
use bevy::render::render_resource::{
|
||||
CachedRenderPipelineId, LoadOp, Operations, RenderPassDepthStencilAttachment,
|
||||
RenderPassDescriptor,
|
||||
RenderPassDescriptor, StoreOp,
|
||||
};
|
||||
use bevy::render::view::{ExtractedView, ViewDepthTexture, ViewTarget};
|
||||
use bevy::render::{
|
||||
|
@ -217,13 +217,15 @@ impl Node for OutlineNode {
|
|||
label: Some("outline_stencil_pass"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||
view: &depth.view,
|
||||
view: &depth.view(),
|
||||
depth_ops: Some(Operations {
|
||||
load: camera_3d.depth_load_op.clone().into(),
|
||||
store: true,
|
||||
store: StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor);
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
|
@ -235,18 +237,17 @@ impl Node for OutlineNode {
|
|||
if !opaque_phase.items.is_empty() {
|
||||
let pass_descriptor = RenderPassDescriptor {
|
||||
label: Some("outline_opaque_pass"),
|
||||
color_attachments: &[Some(target.get_color_attachment(Operations {
|
||||
load: LoadOp::Load,
|
||||
store: true,
|
||||
}))],
|
||||
color_attachments: &[Some(target.get_color_attachment())],
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||
view: &depth.view,
|
||||
view: &depth.view(),
|
||||
depth_ops: Some(Operations {
|
||||
load: LoadOp::Load,
|
||||
store: true,
|
||||
store: StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor);
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
|
@ -258,18 +259,17 @@ impl Node for OutlineNode {
|
|||
if !transparent_phase.items.is_empty() {
|
||||
let pass_descriptor = RenderPassDescriptor {
|
||||
label: Some("outline_transparent_pass"),
|
||||
color_attachments: &[Some(target.get_color_attachment(Operations {
|
||||
load: LoadOp::Load,
|
||||
store: true,
|
||||
}))],
|
||||
color_attachments: &[Some(target.get_color_attachment())],
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||
view: &depth.view,
|
||||
view: &depth.view(),
|
||||
depth_ops: Some(Operations {
|
||||
load: LoadOp::Load,
|
||||
store: true,
|
||||
store: StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor);
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
|
|
146
src/pipeline.rs
146
src/pipeline.rs
|
@ -1,7 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use bevy::ecs::query::QueryItem;
|
||||
use bevy::ecs::system::lifetimeless::Read;
|
||||
use bevy::ecs::system::lifetimeless::SQuery;
|
||||
use bevy::ecs::system::SystemParamItem;
|
||||
use bevy::pbr::{
|
||||
setup_morph_and_skinning_defs, MeshFlags, MeshPipelineKey, MeshTransforms, MeshUniform,
|
||||
|
@ -9,11 +8,10 @@ use bevy::pbr::{
|
|||
use bevy::prelude::*;
|
||||
use bevy::render::batching::GetBatchData;
|
||||
use bevy::render::render_resource::{
|
||||
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState,
|
||||
BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
|
||||
DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode,
|
||||
PrimitiveState, PrimitiveTopology, ShaderDefVal, ShaderSize, ShaderStages, ShaderType,
|
||||
StencilState, TextureFormat, VertexState,
|
||||
BindGroupLayout, BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, BufferSize,
|
||||
ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Face,
|
||||
FragmentState, FrontFace, MultisampleState, PolygonMode, PrimitiveState, PrimitiveTopology,
|
||||
ShaderDefVal, ShaderSize, ShaderStages, ShaderType, StencilState, TextureFormat, VertexState,
|
||||
};
|
||||
use bevy::render::renderer::RenderDevice;
|
||||
use bevy::render::settings::WgpuSettings;
|
||||
|
@ -168,76 +166,71 @@ impl FromWorld for OutlinePipeline {
|
|||
let world = world.cell();
|
||||
let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap().clone();
|
||||
let render_device = world.get_resource::<RenderDevice>().unwrap();
|
||||
let outline_view_bind_group_layout =
|
||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
label: Some("outline_view_bind_group_layout"),
|
||||
entries: &[
|
||||
BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: Some(ViewUniform::min_size()),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: Some(OutlineViewUniform::min_size()),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
let outline_volume_bind_group_layout =
|
||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
label: Some("outline_volume_bind_group_layout"),
|
||||
entries: &[
|
||||
BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(
|
||||
OutlineVolumeUniform::SHADER_SIZE.get(),
|
||||
),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: ShaderStages::FRAGMENT,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(
|
||||
OutlineFragmentUniform::SHADER_SIZE.get(),
|
||||
),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
let outline_stencil_bind_group_layout =
|
||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
label: Some("outline_stencil_bind_group_layout"),
|
||||
entries: &[BindGroupLayoutEntry {
|
||||
let outline_view_bind_group_layout = render_device.create_bind_group_layout(
|
||||
"outline_view_bind_group_layout",
|
||||
&[
|
||||
BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(OutlineStencilUniform::SHADER_SIZE.get()),
|
||||
min_binding_size: Some(ViewUniform::min_size()),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
});
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: Some(OutlineViewUniform::min_size()),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
);
|
||||
let outline_volume_bind_group_layout = render_device.create_bind_group_layout(
|
||||
"outline_volume_bind_group_layout",
|
||||
&[
|
||||
BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(OutlineVolumeUniform::SHADER_SIZE.get()),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: ShaderStages::FRAGMENT,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(
|
||||
OutlineFragmentUniform::SHADER_SIZE.get(),
|
||||
),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
);
|
||||
let outline_stencil_bind_group_layout = render_device.create_bind_group_layout(
|
||||
"outline_stencil_bind_group_layout",
|
||||
&[BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(OutlineStencilUniform::SHADER_SIZE.get()),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
);
|
||||
OutlinePipeline {
|
||||
mesh_pipeline,
|
||||
outline_view_bind_group_layout,
|
||||
|
@ -373,21 +366,20 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
|||
}
|
||||
|
||||
impl GetBatchData for OutlinePipeline {
|
||||
type Param = ();
|
||||
type Query = Read<ExtractedOutline>;
|
||||
type QueryFilter = ();
|
||||
type Param = SQuery<&'static ExtractedOutline>;
|
||||
type CompareData = ();
|
||||
type BufferData = MeshUniform;
|
||||
|
||||
fn get_batch_data(
|
||||
_: &SystemParamItem<Self::Param>,
|
||||
outline: &QueryItem<Self::Query>,
|
||||
) -> (Self::BufferData, Option<Self::CompareData>) {
|
||||
param: &SystemParamItem<Self::Param>,
|
||||
entity: Entity,
|
||||
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
|
||||
let outline = param.get(entity).unwrap();
|
||||
let ts = MeshTransforms {
|
||||
transform: (&outline.transform).into(),
|
||||
previous_transform: (&outline.transform).into(),
|
||||
flags: MeshFlags::NONE.bits(),
|
||||
};
|
||||
((&ts).into(), None)
|
||||
Some((MeshUniform::new(&ts, None), None))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,20 +149,23 @@ pub(crate) fn prepare_outline_volume_bind_group(
|
|||
pub(crate) struct SetOutlineStencilBindGroup<const I: usize>();
|
||||
|
||||
impl<const I: usize> RenderCommand<StencilOutline> for SetOutlineStencilBindGroup<I> {
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<DynamicUniformIndex<OutlineStencilUniform>>;
|
||||
type ViewQuery = ();
|
||||
type ItemQuery = Read<DynamicUniformIndex<OutlineStencilUniform>>;
|
||||
type Param = SRes<OutlineStencilBindGroup>;
|
||||
fn render<'w>(
|
||||
_item: &StencilOutline,
|
||||
_view_data: (),
|
||||
entity_data: &DynamicUniformIndex<OutlineStencilUniform>,
|
||||
entity_data: Option<&DynamicUniformIndex<OutlineStencilUniform>>,
|
||||
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let Some(dyn_uniform) = entity_data else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
&bind_group.into_inner().bind_group,
|
||||
&[entity_data.index()],
|
||||
&[dyn_uniform.index()],
|
||||
);
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
|
@ -171,8 +174,8 @@ impl<const I: usize> RenderCommand<StencilOutline> for SetOutlineStencilBindGrou
|
|||
pub(crate) struct SetOutlineVolumeBindGroup<const I: usize>();
|
||||
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetOutlineVolumeBindGroup<I> {
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = (
|
||||
type ViewQuery = ();
|
||||
type ItemQuery = (
|
||||
Read<DynamicUniformIndex<OutlineVolumeUniform>>,
|
||||
Read<DynamicUniformIndex<OutlineFragmentUniform>>,
|
||||
);
|
||||
|
@ -180,14 +183,16 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetOutlineVolumeBindGrou
|
|||
fn render<'w>(
|
||||
_item: &P,
|
||||
_view_data: (),
|
||||
entity_data: (
|
||||
entity_data: Option<(
|
||||
&DynamicUniformIndex<OutlineVolumeUniform>,
|
||||
&DynamicUniformIndex<OutlineFragmentUniform>,
|
||||
),
|
||||
)>,
|
||||
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let (vertex, fragment) = entity_data;
|
||||
let Some((vertex, fragment)) = entity_data else {
|
||||
return RenderCommandResult::Failure;
|
||||
};
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
&bind_group.into_inner().bind_group,
|
||||
|
|
|
@ -82,16 +82,16 @@ pub(crate) fn prepare_outline_view_bind_group(
|
|||
pub(crate) struct SetOutlineViewBindGroup<const I: usize>();
|
||||
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetOutlineViewBindGroup<I> {
|
||||
type ViewWorldQuery = (
|
||||
type ViewQuery = (
|
||||
Read<ViewUniformOffset>,
|
||||
Read<DynamicUniformIndex<OutlineViewUniform>>,
|
||||
);
|
||||
type ItemWorldQuery = ();
|
||||
type ItemQuery = ();
|
||||
type Param = SRes<OutlineViewBindGroup>;
|
||||
fn render<'w>(
|
||||
_item: &P,
|
||||
(core_view_data, outline_view_data): ROQueryItem<'w, Self::ViewWorldQuery>,
|
||||
_entity_data: (),
|
||||
(core_view_data, outline_view_data): ROQueryItem<'w, Self::ViewQuery>,
|
||||
_entity_data: Option<()>,
|
||||
bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
|
Loading…
Reference in New Issue