Initial port to Bevy 0.13.

This commit is contained in:
Robin KAY 2024-02-16 00:30:51 +00:00
parent bcc0cdd86a
commit fffb75b20c
12 changed files with 188 additions and 201 deletions

View File

@ -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",

View File

@ -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()
});

View File

@ -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

View File

@ -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 {

View File

@ -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() {

View File

@ -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 {

View File

@ -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 {

View File

@ -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) {

View File

@ -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() {

View File

@ -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))
}
}

View File

@ -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,

View File

@ -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 {