Add TransmissiveQuality enum to control number of taps

This commit is contained in:
Marco Buono 2023-09-26 02:23:12 -03:00
parent d4cc7b8ff7
commit e2b017fae9
4 changed files with 77 additions and 3 deletions

View File

@ -41,6 +41,9 @@ pub struct Camera3d {
/// Setting this to `0` disables the screen-space refraction effect entirely, and falls
/// back to refracting the environment map light's texture.
pub transmissive_steps: usize,
/// The quality of the transmissive blur effect.
pub transmissive_quality: TransmissiveQuality,
}
impl Default for Camera3d {
@ -50,6 +53,7 @@ impl Default for Camera3d {
depth_load_op: Default::default(),
depth_texture_usages: TextureUsages::RENDER_ATTACHMENT.into(),
transmissive_steps: 1,
transmissive_quality: Default::default(),
}
}
}
@ -94,6 +98,34 @@ impl From<Camera3dDepthLoadOp> for LoadOp<f32> {
}
}
/// The quality of the transmissive blur effect. Higher qualities are more GPU-intensive.
///
/// **Note:** You can get better-looking results at any quality level by enabling TAA. See: [`TemporalAntiAliasPlugin`](crate::experimental::taa::TemporalAntiAliasPlugin).
#[derive(Resource, Default, Clone, Copy, Reflect, PartialEq, PartialOrd, Debug)]
#[reflect(Resource)]
pub enum TransmissiveQuality {
/// Best performance at the cost of quality. Suitable for lower end GPUs. (e.g. Mobile)
///
/// `num_taps` = 4
Low,
/// A balanced option between quality and performance.
///
/// `num_taps` = 8
#[default]
Medium,
/// Best quality. Suitable for high end GPUs. (e.g. Desktop)
///
/// `num_taps` = 16
High,
/// The highest quality, suitable for non-realtime rendering. (e.g. Pre-rendered cinematics and photo mode)
///
/// `num_taps` = 32
Ultra,
}
#[derive(Bundle)]
pub struct Camera3dBundle {
pub camera: Camera,

View File

@ -6,7 +6,9 @@ use crate::{
use bevy_app::{App, Plugin};
use bevy_asset::{Asset, AssetApp, AssetEvent, AssetId, AssetServer, Assets, Handle};
use bevy_core_pipeline::{
core_3d::{AlphaMask3d, Opaque3d, Transmissive3d, Transparent3d},
core_3d::{
AlphaMask3d, Camera3d, Opaque3d, Transmissive3d, TransmissiveQuality, Transparent3d,
},
prepass::NormalPrepass,
tonemapping::{DebandDither, Tonemapping},
};
@ -423,6 +425,17 @@ const fn tonemapping_pipeline_key(tonemapping: Tonemapping) -> MeshPipelineKey {
}
}
const fn transmissive_quality_pipeline_key(
transmissive_quality: TransmissiveQuality,
) -> MeshPipelineKey {
match transmissive_quality {
TransmissiveQuality::Low => MeshPipelineKey::TRANSMISSIVE_QUALITY_LOW,
TransmissiveQuality::Medium => MeshPipelineKey::TRANSMISSIVE_QUALITY_MEDIUM,
TransmissiveQuality::High => MeshPipelineKey::TRANSMISSIVE_QUALITY_HIGH,
TransmissiveQuality::Ultra => MeshPipelineKey::TRANSMISSIVE_QUALITY_ULTRA,
}
}
#[allow(clippy::too_many_arguments)]
pub fn queue_material_meshes<M: Material>(
opaque_draw_functions: Res<DrawFunctions<Opaque3d>>,
@ -451,6 +464,7 @@ pub fn queue_material_meshes<M: Material>(
Option<&ScreenSpaceAmbientOcclusionSettings>,
Option<&NormalPrepass>,
Option<&TemporalJitter>,
Option<&Camera3d>,
&mut RenderPhase<Opaque3d>,
&mut RenderPhase<AlphaMask3d>,
&mut RenderPhase<Transmissive3d>,
@ -468,6 +482,7 @@ pub fn queue_material_meshes<M: Material>(
ssao,
normal_prepass,
temporal_jitter,
camera_3d,
mut opaque_phase,
mut alpha_mask_phase,
mut transmissive_phase,
@ -502,6 +517,9 @@ pub fn queue_material_meshes<M: Material>(
if ssao.is_some() {
view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
}
if let Some(camera_3d) = camera_3d {
view_key |= transmissive_quality_pipeline_key(camera_3d.transmissive_quality);
}
let rangefinder = view.rangefinder3d();
for visible_entity in &visible_entities.entities {
let Ok((material_handle, mut material_bind_group_id, mesh_handle, mesh_transforms)) =

View File

@ -729,6 +729,11 @@ bitflags::bitflags! {
const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
const TONEMAP_METHOD_TONY_MC_MAPFACE = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
const TONEMAP_METHOD_BLENDER_FILMIC = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
const TRANSMISSIVE_QUALITY_RESERVED_BITS = Self::TRANSMISSIVE_QUALITY_MASK_BITS << Self::TRANSMISSIVE_QUALITY_SHIFT_BITS;
const TRANSMISSIVE_QUALITY_LOW = 0 << Self::TRANSMISSIVE_QUALITY_SHIFT_BITS;
const TRANSMISSIVE_QUALITY_MEDIUM = 1 << Self::TRANSMISSIVE_QUALITY_SHIFT_BITS;
const TRANSMISSIVE_QUALITY_HIGH = 2 << Self::TRANSMISSIVE_QUALITY_SHIFT_BITS;
const TRANSMISSIVE_QUALITY_ULTRA = 3 << Self::TRANSMISSIVE_QUALITY_SHIFT_BITS;
}
}
@ -744,6 +749,9 @@ impl MeshPipelineKey {
const TONEMAP_METHOD_MASK_BITS: u32 = 0b111;
const TONEMAP_METHOD_SHIFT_BITS: u32 =
Self::BLEND_SHIFT_BITS - Self::TONEMAP_METHOD_MASK_BITS.count_ones();
const TRANSMISSIVE_QUALITY_MASK_BITS: u32 = 0b11;
const TRANSMISSIVE_QUALITY_SHIFT_BITS: u32 =
Self::TONEMAP_METHOD_SHIFT_BITS - Self::TRANSMISSIVE_QUALITY_MASK_BITS.count_ones();
pub fn from_msaa_samples(msaa_samples: u32) -> Self {
let msaa_bits =
@ -975,6 +983,19 @@ impl SpecializedMeshPipeline for MeshPipeline {
shader_defs.push("TEMPORAL_JITTER".into());
}
let transmissive_quality =
key.intersection(MeshPipelineKey::TRANSMISSIVE_QUALITY_RESERVED_BITS);
if transmissive_quality == MeshPipelineKey::TRANSMISSIVE_QUALITY_LOW {
shader_defs.push(ShaderDefVal::Int("TRANSMISSIVE_TAPS".into(), 4));
} else if transmissive_quality == MeshPipelineKey::TRANSMISSIVE_QUALITY_MEDIUM {
shader_defs.push(ShaderDefVal::Int("TRANSMISSIVE_TAPS".into(), 8));
} else if transmissive_quality == MeshPipelineKey::TRANSMISSIVE_QUALITY_HIGH {
shader_defs.push(ShaderDefVal::Int("TRANSMISSIVE_TAPS".into(), 16));
} else if transmissive_quality == MeshPipelineKey::TRANSMISSIVE_QUALITY_ULTRA {
shader_defs.push(ShaderDefVal::Int("TRANSMISSIVE_TAPS".into(), 32));
}
let format = if key.contains(MeshPipelineKey::HDR) {
ViewTarget::TEXTURE_FORMAT_HDR
} else {

View File

@ -342,8 +342,11 @@ fn fetch_transmissive_background(offset_position: vec2<f32>, frag_coord: vec3<f3
// - inversely proportional to view z
let blur_intensity = (perceptual_roughness * perceptual_roughness) / view_z;
// TODO: Make this configurable
let num_taps = 8;
#ifdef TRANSMISSIVE_TAPS
let num_taps = #{TRANSMISSIVE_TAPS}; // Controlled by the `Camera3d::transmissive_quality` property
#else
let num_taps = 8; // Fallback to 8 taps
#endif
let num_spirals = i32(ceil(f32(num_taps) / 8.0));
let random_angle = interleaved_gradient_noise(frag_coord.xy);