mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
EntityRenderCommand and PhaseItemRenderCommand (#3111)
Adds new `EntityRenderCommand`, `EntityPhaseItem`, and `CachedPipelinePhaseItem` traits to make it possible to reuse RenderCommands across phases. This should be helpful for features like #3072 . It also makes the trait impls slightly less generic-ey in the common cases. This also fixes the custom shader examples to account for the recent Frustum Culling and MSAA changes (the UX for these things will be improved later).
This commit is contained in:
parent
290b7dd9ab
commit
9a4cc42b38
8 changed files with 184 additions and 150 deletions
|
@ -11,7 +11,7 @@ var<uniform> view: View;
|
|||
struct Mesh {
|
||||
transform: mat4x4<f32>;
|
||||
};
|
||||
[[group(2), binding(0)]]
|
||||
[[group(1), binding(0)]]
|
||||
var<uniform> mesh: Mesh;
|
||||
|
||||
struct Vertex {
|
||||
|
@ -37,7 +37,7 @@ fn vertex(vertex: Vertex) -> VertexOutput {
|
|||
struct CustomMaterial {
|
||||
color: vec4<f32>;
|
||||
};
|
||||
[[group(1), binding(0)]]
|
||||
[[group(2), binding(0)]]
|
||||
var<uniform> material: CustomMaterial;
|
||||
|
||||
[[stage(fragment)]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::{
|
||||
core_pipeline::{SetItemPipeline, Transparent3d},
|
||||
core_pipeline::Transparent3d,
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
ecs::{
|
||||
prelude::*,
|
||||
|
@ -19,11 +19,12 @@ use bevy::{
|
|||
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
|
||||
render_component::ExtractComponentPlugin,
|
||||
render_phase::{
|
||||
AddRenderCommand, DrawFunctions, RenderCommand, RenderPhase, TrackedRenderPass,
|
||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderPhase, SetItemPipeline,
|
||||
TrackedRenderPass,
|
||||
},
|
||||
render_resource::*,
|
||||
renderer::RenderDevice,
|
||||
view::ExtractedView,
|
||||
view::{ComputedVisibility, ExtractedView, Msaa, Visibility},
|
||||
RenderApp, RenderStage,
|
||||
},
|
||||
PipelinedDefaultPlugins,
|
||||
|
@ -51,6 +52,8 @@ fn setup(
|
|||
meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
|
||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
||||
GlobalTransform::default(),
|
||||
Visibility::default(),
|
||||
ComputedVisibility::default(),
|
||||
materials.add(CustomMaterial {
|
||||
color: Color::GREEN,
|
||||
}),
|
||||
|
@ -118,21 +121,36 @@ impl Plugin for CustomMaterialPlugin {
|
|||
app.sub_app(RenderApp)
|
||||
.add_render_command::<Transparent3d, DrawCustom>()
|
||||
.init_resource::<CustomPipeline>()
|
||||
.init_resource::<SpecializedPipelines<CustomPipeline>>()
|
||||
.add_system_to_stage(RenderStage::Queue, queue_custom);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CustomPipeline {
|
||||
material_layout: BindGroupLayout,
|
||||
pipeline: CachedPipelineId,
|
||||
shader: Handle<Shader>,
|
||||
pbr_pipeline: PbrPipeline,
|
||||
}
|
||||
|
||||
impl SpecializedPipeline for CustomPipeline {
|
||||
type Key = PbrPipelineKey;
|
||||
|
||||
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
|
||||
let mut descriptor = self.pbr_pipeline.specialize(key);
|
||||
descriptor.vertex.shader = self.shader.clone();
|
||||
descriptor.fragment.as_mut().unwrap().shader = self.shader.clone();
|
||||
descriptor.layout = Some(vec![
|
||||
self.pbr_pipeline.view_layout.clone(),
|
||||
self.pbr_pipeline.mesh_layout.clone(),
|
||||
self.material_layout.clone(),
|
||||
]);
|
||||
descriptor
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWorld for CustomPipeline {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let world = world.cell();
|
||||
let asset_server = world.get_resource::<AssetServer>().unwrap();
|
||||
let shader = asset_server.load("shaders/custom.wgsl");
|
||||
|
||||
let render_device = world.get_resource::<RenderDevice>().unwrap();
|
||||
let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
entries: &[BindGroupLayoutEntry {
|
||||
|
@ -148,28 +166,22 @@ impl FromWorld for CustomPipeline {
|
|||
label: None,
|
||||
});
|
||||
|
||||
let pbr_pipeline = world.get_resource::<PbrPipeline>().unwrap();
|
||||
let mut descriptor = pbr_pipeline.specialize(PbrPipelineKey::empty());
|
||||
descriptor.vertex.shader = shader.clone();
|
||||
descriptor.fragment.as_mut().unwrap().shader = shader;
|
||||
descriptor.layout = Some(vec![
|
||||
pbr_pipeline.view_layout.clone(),
|
||||
material_layout.clone(),
|
||||
pbr_pipeline.mesh_layout.clone(),
|
||||
]);
|
||||
|
||||
let mut pipeline_cache = world.get_resource_mut::<RenderPipelineCache>().unwrap();
|
||||
CustomPipeline {
|
||||
pipeline: pipeline_cache.queue(descriptor),
|
||||
pbr_pipeline: world.get_resource::<PbrPipeline>().unwrap().clone(),
|
||||
shader: asset_server.load("shaders/custom.wgsl"),
|
||||
material_layout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn queue_custom(
|
||||
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
|
||||
materials: Res<RenderAssets<CustomMaterial>>,
|
||||
custom_pipeline: Res<CustomPipeline>,
|
||||
mut pipeline_cache: ResMut<RenderPipelineCache>,
|
||||
mut specialized_pipelines: ResMut<SpecializedPipelines<CustomPipeline>>,
|
||||
msaa: Res<Msaa>,
|
||||
material_meshes: Query<(Entity, &Handle<CustomMaterial>, &MeshUniform), With<Handle<Mesh>>>,
|
||||
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
|
||||
) {
|
||||
|
@ -177,6 +189,7 @@ pub fn queue_custom(
|
|||
.read()
|
||||
.get_id::<DrawCustom>()
|
||||
.unwrap();
|
||||
let key = PbrPipelineKey::from_msaa_samples(msaa.samples);
|
||||
for (view, mut transparent_phase) in views.iter_mut() {
|
||||
let view_matrix = view.transform.compute_matrix();
|
||||
let view_row_2 = view_matrix.row(2);
|
||||
|
@ -184,7 +197,11 @@ pub fn queue_custom(
|
|||
if materials.contains_key(material_handle) {
|
||||
transparent_phase.add(Transparent3d {
|
||||
entity,
|
||||
pipeline: custom_pipeline.pipeline,
|
||||
pipeline: specialized_pipelines.specialize(
|
||||
&mut pipeline_cache,
|
||||
&custom_pipeline,
|
||||
key,
|
||||
),
|
||||
draw_function: draw_custom,
|
||||
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
|
||||
});
|
||||
|
@ -196,25 +213,25 @@ pub fn queue_custom(
|
|||
type DrawCustom = (
|
||||
SetItemPipeline,
|
||||
SetMeshViewBindGroup<0>,
|
||||
SetTransformBindGroup<1>,
|
||||
SetCustomMaterialBindGroup,
|
||||
SetTransformBindGroup<2>,
|
||||
DrawMesh,
|
||||
);
|
||||
|
||||
struct SetCustomMaterialBindGroup;
|
||||
impl RenderCommand<Transparent3d> for SetCustomMaterialBindGroup {
|
||||
impl EntityRenderCommand for SetCustomMaterialBindGroup {
|
||||
type Param = (
|
||||
SRes<RenderAssets<CustomMaterial>>,
|
||||
SQuery<Read<Handle<CustomMaterial>>>,
|
||||
);
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &Transparent3d,
|
||||
item: Entity,
|
||||
(materials, query): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let material_handle = query.get(item.entity).unwrap();
|
||||
let material_handle = query.get(item).unwrap();
|
||||
let material = materials.into_inner().get(material_handle).unwrap();
|
||||
pass.set_bind_group(1, &material.bind_group, &[]);
|
||||
pass.set_bind_group(2, &material.bind_group, &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::{
|
||||
core_pipeline::{SetItemPipeline, Transparent3d},
|
||||
core_pipeline::Transparent3d,
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
ecs::prelude::*,
|
||||
math::Vec3,
|
||||
|
@ -12,9 +12,9 @@ use bevy::{
|
|||
camera::PerspectiveCameraBundle,
|
||||
mesh::{shape, Mesh},
|
||||
render_component::{ExtractComponent, ExtractComponentPlugin},
|
||||
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase},
|
||||
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
|
||||
render_resource::*,
|
||||
view::ExtractedView,
|
||||
view::{ComputedVisibility, ExtractedView, Msaa, Visibility},
|
||||
RenderApp, RenderStage,
|
||||
},
|
||||
PipelinedDefaultPlugins,
|
||||
|
@ -64,6 +64,8 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
|
|||
IsRed(true),
|
||||
Transform::from_xyz(-1.0, 0.5, 0.0),
|
||||
GlobalTransform::default(),
|
||||
Visibility::default(),
|
||||
ComputedVisibility::default(),
|
||||
));
|
||||
|
||||
// blue cube
|
||||
|
@ -72,6 +74,8 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
|
|||
IsRed(false),
|
||||
Transform::from_xyz(1.0, 0.5, 0.0),
|
||||
GlobalTransform::default(),
|
||||
Visibility::default(),
|
||||
ComputedVisibility::default(),
|
||||
));
|
||||
|
||||
// camera
|
||||
|
@ -99,14 +103,14 @@ impl FromWorld for IsRedPipeline {
|
|||
}
|
||||
|
||||
impl SpecializedPipeline for IsRedPipeline {
|
||||
type Key = IsRed;
|
||||
type Key = (IsRed, PbrPipelineKey);
|
||||
|
||||
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
|
||||
fn specialize(&self, (is_red, pbr_pipeline_key): Self::Key) -> RenderPipelineDescriptor {
|
||||
let mut shader_defs = Vec::new();
|
||||
if key.0 {
|
||||
if is_red.0 {
|
||||
shader_defs.push("IS_RED".to_string());
|
||||
}
|
||||
let mut descriptor = self.pbr_pipeline.specialize(PbrPipelineKey::empty());
|
||||
let mut descriptor = self.pbr_pipeline.specialize(pbr_pipeline_key);
|
||||
descriptor.vertex.shader = self.shader.clone();
|
||||
descriptor.vertex.shader_defs = shader_defs.clone();
|
||||
let fragment = descriptor.fragment.as_mut().unwrap();
|
||||
|
@ -130,6 +134,7 @@ type DrawIsRed = (
|
|||
fn queue_custom(
|
||||
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
|
||||
custom_pipeline: Res<IsRedPipeline>,
|
||||
msaa: Res<Msaa>,
|
||||
mut pipelines: ResMut<SpecializedPipelines<IsRedPipeline>>,
|
||||
mut pipeline_cache: ResMut<RenderPipelineCache>,
|
||||
material_meshes: Query<(Entity, &MeshUniform, &IsRed), With<Handle<Mesh>>>,
|
||||
|
@ -139,11 +144,13 @@ fn queue_custom(
|
|||
.read()
|
||||
.get_id::<DrawIsRed>()
|
||||
.unwrap();
|
||||
let key = PbrPipelineKey::from_msaa_samples(msaa.samples);
|
||||
for (view, mut transparent_phase) in views.iter_mut() {
|
||||
let view_matrix = view.transform.compute_matrix();
|
||||
let view_row_2 = view_matrix.row(2);
|
||||
for (entity, mesh_uniform, is_red) in material_meshes.iter() {
|
||||
let pipeline = pipelines.specialize(&mut pipeline_cache, &custom_pipeline, *is_red);
|
||||
let pipeline =
|
||||
pipelines.specialize(&mut pipeline_cache, &custom_pipeline, (*is_red, key));
|
||||
transparent_phase.add(Transparent3d {
|
||||
entity,
|
||||
pipeline,
|
||||
|
|
|
@ -8,17 +8,14 @@ pub use main_pass_driver::*;
|
|||
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_core::FloatOrd;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
system::{lifetimeless::SRes, SystemParamItem},
|
||||
};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_render2::{
|
||||
camera::{ActiveCameras, CameraPlugin},
|
||||
color::Color,
|
||||
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
|
||||
render_phase::{
|
||||
sort_phase_system, DrawFunctionId, DrawFunctions, PhaseItem, RenderCommand, RenderPhase,
|
||||
TrackedRenderPass,
|
||||
sort_phase_system, CachedPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem,
|
||||
PhaseItem, RenderPhase,
|
||||
},
|
||||
render_resource::*,
|
||||
renderer::RenderDevice,
|
||||
|
@ -171,38 +168,17 @@ impl PhaseItem for Transparent3d {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SetItemPipeline;
|
||||
impl RenderCommand<Transparent3d> for SetItemPipeline {
|
||||
type Param = SRes<RenderPipelineCache>;
|
||||
impl EntityPhaseItem for Transparent3d {
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &Transparent3d,
|
||||
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let pipeline = pipeline_cache
|
||||
.into_inner()
|
||||
.get_state(item.pipeline)
|
||||
.unwrap();
|
||||
pass.set_render_pipeline(pipeline);
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderCommand<Transparent2d> for SetItemPipeline {
|
||||
type Param = SRes<RenderPipelineCache>;
|
||||
impl CachedPipelinePhaseItem for Transparent3d {
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &Transparent2d,
|
||||
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let pipeline = pipeline_cache
|
||||
.into_inner()
|
||||
.get_state(item.pipeline)
|
||||
.unwrap();
|
||||
pass.set_render_pipeline(pipeline);
|
||||
fn cached_pipeline(&self) -> CachedPipelineId {
|
||||
self.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -108,15 +108,10 @@ impl Plugin for PbrPlugin {
|
|||
.init_resource::<SpecializedPipelines<PbrPipeline>>()
|
||||
.init_resource::<SpecializedPipelines<ShadowPipeline>>();
|
||||
|
||||
let draw_shadow_mesh = DrawShadowMesh::new(&mut render_app.world);
|
||||
let shadow_pass_node = ShadowPassNode::new(&mut render_app.world);
|
||||
render_app.add_render_command::<Transparent3d, DrawPbr>();
|
||||
let render_world = render_app.world.cell();
|
||||
let draw_functions = render_world
|
||||
.get_resource::<DrawFunctions<Shadow>>()
|
||||
.unwrap();
|
||||
draw_functions.write().add(draw_shadow_mesh);
|
||||
let mut graph = render_world.get_resource_mut::<RenderGraph>().unwrap();
|
||||
render_app.add_render_command::<Shadow, DrawShadowMesh>();
|
||||
let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap();
|
||||
let draw_3d_graph = graph
|
||||
.get_sub_graph_mut(bevy_core_pipeline::draw_3d_graph::NAME)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
AmbientLight, CubemapVisibleEntities, DirectionalLight, DirectionalLightShadowMap, MeshUniform,
|
||||
NotShadowCaster, PbrPipeline, PointLight, PointLightShadowMap, TransformBindGroup,
|
||||
AmbientLight, CubemapVisibleEntities, DirectionalLight, DirectionalLightShadowMap, DrawMesh,
|
||||
NotShadowCaster, PbrPipeline, PointLight, PointLightShadowMap, SetTransformBindGroup,
|
||||
SHADOW_SHADER_HANDLE,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
|
@ -8,7 +8,7 @@ use bevy_core::FloatOrd;
|
|||
use bevy_core_pipeline::Transparent3d;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
system::{lifetimeless::*, SystemState},
|
||||
system::{lifetimeless::*, SystemParamItem},
|
||||
};
|
||||
use bevy_math::{const_vec3, Mat4, Vec3, Vec4};
|
||||
use bevy_render2::{
|
||||
|
@ -16,10 +16,10 @@ use bevy_render2::{
|
|||
color::Color,
|
||||
mesh::Mesh,
|
||||
render_asset::RenderAssets,
|
||||
render_component::DynamicUniformIndex,
|
||||
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
||||
render_phase::{
|
||||
Draw, DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase, TrackedRenderPass,
|
||||
CachedPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem,
|
||||
EntityRenderCommand, PhaseItem, RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::*,
|
||||
renderer::{RenderContext, RenderDevice, RenderQueue},
|
||||
|
@ -796,6 +796,19 @@ impl PhaseItem for Shadow {
|
|||
}
|
||||
}
|
||||
|
||||
impl EntityPhaseItem for Shadow {
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedPipelinePhaseItem for Shadow {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedPipelineId {
|
||||
self.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShadowPassNode {
|
||||
main_view_query: QueryState<&'static ViewLights>,
|
||||
view_light_query: QueryState<(&'static ViewLight, &'static RenderPhase<Shadow>)>,
|
||||
|
@ -865,63 +878,32 @@ impl Node for ShadowPassNode {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct DrawShadowMesh {
|
||||
params: SystemState<(
|
||||
SRes<RenderPipelineCache>,
|
||||
SRes<LightMeta>,
|
||||
SRes<TransformBindGroup>,
|
||||
SRes<RenderAssets<Mesh>>,
|
||||
SQuery<(Read<DynamicUniformIndex<MeshUniform>>, Read<Handle<Mesh>>)>,
|
||||
SQuery<Read<ViewUniformOffset>>,
|
||||
)>,
|
||||
}
|
||||
pub type DrawShadowMesh = (
|
||||
SetItemPipeline,
|
||||
SetShadowViewBindGroup<0>,
|
||||
SetTransformBindGroup<1>,
|
||||
DrawMesh,
|
||||
);
|
||||
|
||||
impl DrawShadowMesh {
|
||||
pub fn new(world: &mut World) -> Self {
|
||||
Self {
|
||||
params: SystemState::new(world),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Draw<Shadow> for DrawShadowMesh {
|
||||
fn draw<'w>(
|
||||
&mut self,
|
||||
world: &'w World,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
pub struct SetShadowViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetShadowViewBindGroup<I> {
|
||||
type Param = (SRes<LightMeta>, SQuery<Read<ViewUniformOffset>>);
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
item: &Shadow,
|
||||
_item: Entity,
|
||||
(light_meta, view_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let (pipeline_cache, light_meta, transform_bind_group, meshes, items, views) =
|
||||
self.params.get(world);
|
||||
let (transform_index, mesh_handle) = items.get(item.entity).unwrap();
|
||||
let view_uniform_offset = views.get(view).unwrap();
|
||||
if let Some(pipeline) = pipeline_cache.into_inner().get(item.pipeline) {
|
||||
pass.set_render_pipeline(pipeline);
|
||||
pass.set_bind_group(
|
||||
0,
|
||||
light_meta
|
||||
.into_inner()
|
||||
.shadow_view_bind_group
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
&[view_uniform_offset.offset],
|
||||
);
|
||||
|
||||
pass.set_bind_group(
|
||||
1,
|
||||
&transform_bind_group.into_inner().value,
|
||||
&[transform_index.index()],
|
||||
);
|
||||
|
||||
let gpu_mesh = meshes.into_inner().get(mesh_handle).unwrap();
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
if let Some(index_info) = &gpu_mesh.index_info {
|
||||
pass.set_index_buffer(index_info.buffer.slice(..), 0, index_info.index_format);
|
||||
pass.draw_indexed(0..index_info.count, 0, 0..1);
|
||||
} else {
|
||||
panic!("non-indexed drawing not supported yet")
|
||||
}
|
||||
}
|
||||
let view_uniform_offset = view_query.get(view).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
light_meta
|
||||
.into_inner()
|
||||
.shadow_view_bind_group
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
&[view_uniform_offset.offset],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
PBR_SHADER_HANDLE,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_core_pipeline::{SetItemPipeline, Transparent3d};
|
||||
use bevy_core_pipeline::Transparent3d;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
system::{lifetimeless::*, SystemParamItem},
|
||||
|
@ -17,7 +17,9 @@ use bevy_render2::{
|
|||
mesh::Mesh,
|
||||
render_asset::RenderAssets,
|
||||
render_component::{ComponentUniforms, DynamicUniformIndex},
|
||||
render_phase::{DrawFunctions, RenderCommand, RenderPhase, TrackedRenderPass},
|
||||
render_phase::{
|
||||
DrawFunctions, EntityRenderCommand, RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::*,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo},
|
||||
|
@ -734,7 +736,7 @@ pub type DrawPbr = (
|
|||
);
|
||||
|
||||
pub struct SetMeshViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> RenderCommand<Transparent3d> for SetMeshViewBindGroup<I> {
|
||||
impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
|
||||
type Param = SQuery<(
|
||||
Read<ViewUniformOffset>,
|
||||
Read<ViewLights>,
|
||||
|
@ -743,7 +745,7 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetMeshViewBindGroup<I> {
|
|||
#[inline]
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
_item: &Transparent3d,
|
||||
_item: Entity,
|
||||
view_query: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
|
@ -757,7 +759,7 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetMeshViewBindGroup<I> {
|
|||
}
|
||||
|
||||
pub struct SetTransformBindGroup<const I: usize>;
|
||||
impl<const I: usize> RenderCommand<Transparent3d> for SetTransformBindGroup<I> {
|
||||
impl<const I: usize> EntityRenderCommand for SetTransformBindGroup<I> {
|
||||
type Param = (
|
||||
SRes<TransformBindGroup>,
|
||||
SQuery<Read<DynamicUniformIndex<MeshUniform>>>,
|
||||
|
@ -765,11 +767,11 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetTransformBindGroup<I> {
|
|||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &Transparent3d,
|
||||
item: Entity,
|
||||
(transform_bind_group, mesh_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let transform_index = mesh_query.get(item.entity).unwrap();
|
||||
let transform_index = mesh_query.get(item).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
&transform_bind_group.into_inner().value,
|
||||
|
@ -779,7 +781,7 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetTransformBindGroup<I> {
|
|||
}
|
||||
|
||||
pub struct SetStandardMaterialBindGroup<const I: usize>;
|
||||
impl<const I: usize> RenderCommand<Transparent3d> for SetStandardMaterialBindGroup<I> {
|
||||
impl<const I: usize> EntityRenderCommand for SetStandardMaterialBindGroup<I> {
|
||||
type Param = (
|
||||
SRes<RenderAssets<StandardMaterial>>,
|
||||
SQuery<Read<Handle<StandardMaterial>>>,
|
||||
|
@ -787,11 +789,11 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetStandardMaterialBindGro
|
|||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &Transparent3d,
|
||||
item: Entity,
|
||||
(materials, handle_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let handle = handle_query.get(item.entity).unwrap();
|
||||
let handle = handle_query.get(item).unwrap();
|
||||
let materials = materials.into_inner();
|
||||
let material = materials.get(handle).unwrap();
|
||||
|
||||
|
@ -800,16 +802,16 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetStandardMaterialBindGro
|
|||
}
|
||||
|
||||
pub struct DrawMesh;
|
||||
impl RenderCommand<Transparent3d> for DrawMesh {
|
||||
impl EntityRenderCommand for DrawMesh {
|
||||
type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Handle<Mesh>>>);
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &Transparent3d,
|
||||
item: Entity,
|
||||
(meshes, mesh_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let mesh_handle = mesh_query.get(item.entity).unwrap();
|
||||
let mesh_handle = mesh_query.get(item).unwrap();
|
||||
let gpu_mesh = meshes.into_inner().get(mesh_handle).unwrap();
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
if let Some(index_info) = &gpu_mesh.index_info {
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
use crate::render_phase::TrackedRenderPass;
|
||||
use crate::{
|
||||
render_phase::TrackedRenderPass,
|
||||
render_resource::{CachedPipelineId, RenderPipelineCache},
|
||||
};
|
||||
use bevy_app::App;
|
||||
use bevy_ecs::{
|
||||
all_tuples,
|
||||
entity::Entity,
|
||||
system::{ReadOnlySystemParamFetch, SystemParam, SystemParamItem, SystemState},
|
||||
system::{
|
||||
lifetimeless::SRes, ReadOnlySystemParamFetch, SystemParam, SystemParamItem, SystemState,
|
||||
},
|
||||
world::World,
|
||||
};
|
||||
use bevy_utils::HashMap;
|
||||
|
@ -90,6 +95,56 @@ pub trait RenderCommand<P: PhaseItem> {
|
|||
);
|
||||
}
|
||||
|
||||
pub trait EntityRenderCommand {
|
||||
type Param: SystemParam;
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
item: Entity,
|
||||
param: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
);
|
||||
}
|
||||
|
||||
pub trait EntityPhaseItem: PhaseItem {
|
||||
fn entity(&self) -> Entity;
|
||||
}
|
||||
|
||||
pub trait CachedPipelinePhaseItem: PhaseItem {
|
||||
fn cached_pipeline(&self) -> CachedPipelineId;
|
||||
}
|
||||
|
||||
impl<P: EntityPhaseItem, E: EntityRenderCommand> RenderCommand<P> for E {
|
||||
type Param = E::Param;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
item: &P,
|
||||
param: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
<E as EntityRenderCommand>::render(view, item.entity(), param, pass);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetItemPipeline;
|
||||
impl<P: CachedPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
|
||||
type Param = SRes<RenderPipelineCache>;
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &P,
|
||||
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) {
|
||||
let pipeline = pipeline_cache
|
||||
.into_inner()
|
||||
.get_state(item.cached_pipeline())
|
||||
.unwrap();
|
||||
pass.set_render_pipeline(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! render_command_tuple_impl {
|
||||
($($name: ident),*) => {
|
||||
impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {
|
||||
|
|
Loading…
Reference in a new issue