Compare commits

..

4 Commits

Author SHA1 Message Date
da9cf82129 Merge pull request 'Added HDR Support (pipeline specialization)' (#4) from 3-add-hdr-support into master
All checks were successful
Build / Build (push) Successful in 2m14s
Reviewed-on: #4
2025-03-23 11:40:17 -04:00
85251459b5 Added HDR Support (pipeline specialization)
All checks were successful
Build / Build (push) Successful in 2m19s
2025-03-22 20:43:55 -04:00
6f019ff2d0 Merge pull request 'Add build action' (#2) from 1-add-build-action into master
All checks were successful
Build / Build (push) Successful in 2m47s
Reviewed-on: #2
2025-03-19 05:58:51 -04:00
914ad234a1
Added build action
All checks were successful
Build / Build (push) Successful in 41m14s
2025-03-18 20:07:54 -04:00
7 changed files with 131 additions and 89 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[profile.dev.package."*"]
opt-level = 2

View File

@ -0,0 +1,25 @@
name: Build
on: [push]
jobs:
Build:
env:
RUNNER_TOOL_CACHE: /toolcache
container: rust:alpine
steps:
- name: Install node
run: apk add nodejs gcc libc-dev pkgconf libx11-dev alsa-lib-dev eudev-dev tar
- name: Check out repository code
uses: actions/checkout@v4
- name: Restore cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build
run: cargo build --release

58
Cargo.lock generated
View File

@ -572,7 +572,7 @@ dependencies = [
"bevy_reflect",
"derive_more",
"glam",
"itertools 0.13.0",
"itertools",
"rand",
"rand_distr",
"serde",
@ -613,7 +613,7 @@ dependencies = [
[[package]]
name = "bevy_outline_post_process"
version = "0.4.0"
version = "0.5.0"
dependencies = [
"bevy",
]
@ -829,7 +829,7 @@ dependencies = [
"bitflags 2.6.0",
"cexpr",
"clang-sys",
"itertools 0.12.1",
"itertools",
"log",
"prettyplease",
"proc-macro2",
@ -1515,7 +1515,7 @@ dependencies = [
"log",
"presser",
"thiserror",
"windows 0.54.0",
"windows",
]
[[package]]
@ -1587,15 +1587,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
@ -1682,7 +1673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.52.6",
]
[[package]]
@ -2775,8 +2766,8 @@ dependencies = [
"wasm-bindgen",
"web-sys",
"wgpu-types",
"windows 0.58.0",
"windows-core 0.58.0",
"windows",
"windows-core",
]
[[package]]
@ -2821,33 +2812,13 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
"windows-core 0.54.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
dependencies = [
"windows-core 0.58.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [
"windows-result 0.1.1",
"windows-core",
"windows-targets 0.52.6",
]
@ -2859,7 +2830,7 @@ checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result 0.2.0",
"windows-result",
"windows-strings",
"windows-targets 0.52.6",
]
@ -2886,15 +2857,6 @@ dependencies = [
"syn",
]
[[package]]
name = "windows-result"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.2.0"
@ -2910,7 +2872,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result 0.2.0",
"windows-result",
"windows-targets 0.52.6",
]

View File

@ -1,9 +1,13 @@
use bevy::{
core_pipeline::prepass::{DeferredPrepass, DepthPrepass, NormalPrepass},
prelude::*,
render::{extract_component::ExtractComponent, render_resource::ShaderType},
render::{extract_component::ExtractComponent, render_resource::{CachedRenderPipelineId, ShaderType}},
};
/// Stores the cached pipeline ID for the post processing pass for this camera
#[derive(Component, Deref, DerefMut)]
pub struct OutlinePostProcessPipelineId(pub CachedRenderPipelineId);
/// Component which, when inserted into an entity with a camera and normal prepass, enables an outline effect for that
/// camera.
#[derive(Component, ShaderType, ExtractComponent, PartialEq, Clone)]

View File

@ -11,12 +11,15 @@ use bevy::{
render::{
extract_component::{ExtractComponentPlugin, UniformComponentPlugin},
render_graph::{RenderGraphApp, ViewNodeRunner},
RenderApp,
render_resource::{PipelineCache, SpecializedRenderPipelines, TextureFormat},
view::{ExtractedView, ViewTarget},
Render, RenderApp, RenderSet,
},
};
use components::OutlinePostProcessSettings;
use components::{OutlinePostProcessPipelineId, OutlinePostProcessSettings};
pub use nodes::OutlineRenderLabel;
use resources::{OutlinePostProcessPipeline, OutlinePostProcessingPipelineKey};
/// Components used by this plugin.
pub mod components;
@ -41,6 +44,11 @@ impl Plugin for OutlinePostProcessPlugin {
};
render_app
.add_systems(
Render,
prepare_post_processing_pipelines.in_set(RenderSet::Prepare),
)
.init_resource::<SpecializedRenderPipelines<OutlinePostProcessPipeline>>()
.add_render_graph_node::<ViewNodeRunner<nodes::OutlineRenderNode>>(
Core3d,
nodes::OutlineRenderLabel,
@ -64,6 +72,32 @@ impl Plugin for OutlinePostProcessPlugin {
}
}
fn prepare_post_processing_pipelines(
mut commands: Commands,
pipeline_cache: Res<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<OutlinePostProcessPipeline>>,
post_processing_pipeline: Res<OutlinePostProcessPipeline>,
views: Query<(Entity, &ExtractedView), With<OutlinePostProcessSettings>>,
) {
for (entity, view) in views.iter() {
let pipeline_id = pipelines.specialize(
&pipeline_cache,
&post_processing_pipeline,
OutlinePostProcessingPipelineKey {
texture_format: if view.hdr {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
TextureFormat::bevy_default()
},
},
);
commands
.entity(entity)
.insert(OutlinePostProcessPipelineId(pipeline_id));
}
}
fn update_shader_clip_planes(
mut settings_query: Query<(Ref<Projection>, &mut OutlinePostProcessSettings)>,
) {

View File

@ -1,6 +1,6 @@
use bevy::{
core_pipeline::prepass::ViewPrepassTextures,
ecs::query::QueryItem,
ecs::{query::QueryItem, system::lifetimeless::Read},
prelude::*,
render::{
extract_component::ComponentUniforms,
@ -14,6 +14,8 @@ use bevy::{
},
};
use crate::components::OutlinePostProcessPipelineId;
use super::components;
use super::resources;
@ -26,21 +28,27 @@ pub struct OutlineRenderNode;
impl ViewNode for OutlineRenderNode {
type ViewQuery = (
&'static ViewTarget,
&'static ViewPrepassTextures,
&'static components::OutlinePostProcessSettings,
Read<ViewTarget>,
Read<ViewPrepassTextures>,
Read<OutlinePostProcessPipelineId>,
Read<components::OutlinePostProcessSettings>,
);
fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
(view_target, view_prepass_textures, _): QueryItem<Self::ViewQuery>,
(
view_target,
view_prepass_textures,
pipeline_id,
_,
): QueryItem<Self::ViewQuery>,
world: &World,
) -> Result<(), NodeRunError> {
let render_pipeline = world.resource::<resources::OutlinePostProcessPipeline>();
let pipeline_cache = world.resource::<PipelineCache>();
let Some(pipeline) = pipeline_cache.get_render_pipeline(render_pipeline.pipeline_id) else {
let Some(pipeline) = pipeline_cache.get_render_pipeline(**pipeline_id) else {
warn!("Failed to get render pipeline from cache, skipping...");
return Ok(());
};

View File

@ -1,13 +1,9 @@
use bevy::{
core_pipeline::fullscreen_vertex_shader::fullscreen_shader_vertex_state,
core_pipeline::fullscreen_vertex_shader,
prelude::*,
render::{
render_resource::{
binding_types::{sampler, texture_2d, uniform_buffer},
BindGroupLayout, BindGroupLayoutEntries, CachedRenderPipelineId, ColorTargetState,
ColorWrites, FragmentState, MultisampleState, PipelineCache, PrimitiveState,
RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages,
TextureFormat, TextureSampleType,
binding_types::{sampler, texture_2d, uniform_buffer}, BindGroupLayout, BindGroupLayoutEntries, ColorTargetState, ColorWrites, FragmentState, RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, SpecializedRenderPipeline, TextureFormat, TextureSampleType
},
renderer::RenderDevice,
},
@ -21,7 +17,7 @@ pub struct OutlinePostProcessPipeline {
pub screen_sampler: Sampler,
pub normal_sampler: Sampler,
pub depth_sampler: Sampler,
pub pipeline_id: CachedRenderPipelineId,
pub shader: Handle<Shader>,
}
impl FromWorld for OutlinePostProcessPipeline {
@ -52,36 +48,47 @@ impl FromWorld for OutlinePostProcessPipeline {
"embedded://bevy_outline_post_process/../assets/shaders/outline_post_process.wgsl",
);
let pipeline_id =
world
.resource_mut::<PipelineCache>()
.queue_render_pipeline(RenderPipelineDescriptor {
label: Some("outline_post_process_render_pipeline".into()),
layout: vec![layout.clone()],
push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(),
primitive: PrimitiveState::default(),
depth_stencil: None,
multisample: MultisampleState::default(),
fragment: Some(FragmentState {
shader,
shader_defs: vec![],
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(),
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
zero_initialize_workgroup_memory: false,
});
Self {
layout,
screen_sampler,
normal_sampler,
depth_sampler,
pipeline_id,
shader,
}
}
}
/// A key that uniquely identifies a built-in postprocessing pipeline.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct OutlinePostProcessingPipelineKey {
/// The format of the source and destination textures.
pub texture_format: TextureFormat,
}
impl SpecializedRenderPipeline for OutlinePostProcessPipeline {
type Key = OutlinePostProcessingPipelineKey;
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
RenderPipelineDescriptor {
label: Some("outline_post_processing".into()),
layout: vec![self.layout.clone()],
vertex: fullscreen_vertex_shader::fullscreen_shader_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader_defs: vec![],
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: key.texture_format,
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
primitive: default(),
depth_stencil: None,
multisample: default(),
push_constant_ranges: vec![],
zero_initialize_workgroup_memory: false,
}
}
}