Skip to content

Commit 724e69b

Browse files
JMS55mockersfcart
authored
Bias texture mipmaps (#7614)
# Objective - Closes #7323 - Reduce texture blurriness for TAA ## Solution - Add a `MipBias` component and view uniform. - Switch material `textureSample()` calls to `textureSampleBias()`. - Add a `-1.0` bias to TAA. --- ## Changelog - Added `MipBias` camera component, mostly for internal use. --------- Co-authored-by: François <[email protected]> Co-authored-by: Carter Anderson <[email protected]>
1 parent c6170d4 commit 724e69b

File tree

7 files changed

+40
-15
lines changed

7 files changed

+40
-15
lines changed

crates/bevy_core_pipeline/src/taa/mod.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ use bevy_core::FrameCount;
1010
use bevy_ecs::{
1111
prelude::{Bundle, Component, Entity},
1212
query::{QueryItem, With},
13-
schedule::IntoSystemConfigs,
13+
schedule::{apply_deferred, IntoSystemConfigs},
1414
system::{Commands, Query, Res, ResMut, Resource},
1515
world::{FromWorld, World},
1616
};
1717
use bevy_math::vec2;
1818
use bevy_reflect::{Reflect, TypeUuid};
1919
use bevy_render::{
20-
camera::{ExtractedCamera, TemporalJitter},
20+
camera::{ExtractedCamera, MipBias, TemporalJitter},
2121
prelude::{Camera, Projection},
2222
render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
2323
render_resource::{
@@ -65,7 +65,8 @@ impl Plugin for TemporalAntiAliasPlugin {
6565
.add_systems(
6666
Render,
6767
(
68-
prepare_taa_jitter
68+
(prepare_taa_jitter_and_mip_bias, apply_deferred)
69+
.chain()
6970
.before(prepare_view_uniforms)
7071
.in_set(RenderSet::Prepare),
7172
prepare_taa_history_textures.in_set(RenderSet::Prepare),
@@ -140,6 +141,8 @@ pub struct TemporalAntiAliasBundle {
140141
/// are added using a third party library, the library must either:
141142
/// 1. Write particle motion vectors to the motion vectors prepass texture
142143
/// 2. Render particles after TAA
144+
///
145+
/// If no [`MipBias`] component is attached to the camera, TAA will add a MipBias(-1.0) component.
143146
#[derive(Component, Reflect, Clone)]
144147
pub struct TemporalAntiAliasSettings {
145148
/// Set to true to delete the saved temporal history (past frames).
@@ -436,9 +439,13 @@ fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut<MainWorld
436439
}
437440
}
438441

439-
fn prepare_taa_jitter(
442+
fn prepare_taa_jitter_and_mip_bias(
440443
frame_count: Res<FrameCount>,
441-
mut query: Query<&mut TemporalJitter, With<TemporalAntiAliasSettings>>,
444+
mut query: Query<
445+
(Entity, &mut TemporalJitter, Option<&MipBias>),
446+
With<TemporalAntiAliasSettings>,
447+
>,
448+
mut commands: Commands,
442449
) {
443450
// Halton sequence (2, 3) - 0.5, skipping i = 0
444451
let halton_sequence = [
@@ -454,8 +461,12 @@ fn prepare_taa_jitter(
454461

455462
let offset = halton_sequence[frame_count.0 as usize % halton_sequence.len()];
456463

457-
for mut jitter in &mut query {
464+
for (entity, mut jitter, mip_bias) in &mut query {
458465
jitter.offset = offset;
466+
467+
if mip_bias.is_none() {
468+
commands.entity(entity).insert(MipBias(-1.0));
469+
}
459470
}
460471
}
461472

crates/bevy_pbr/src/render/pbr.wgsl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
5555
#endif
5656
#ifdef VERTEX_UVS
5757
if ((material.flags & STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
58-
output_color = output_color * textureSample(base_color_texture, base_color_sampler, uv);
58+
output_color = output_color * textureSampleBias(base_color_texture, base_color_sampler, uv, view.mip_bias);
5959
}
6060
#endif
6161

@@ -74,7 +74,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
7474
var emissive: vec4<f32> = material.emissive;
7575
#ifdef VERTEX_UVS
7676
if ((material.flags & STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
77-
emissive = vec4<f32>(emissive.rgb * textureSample(emissive_texture, emissive_sampler, uv).rgb, 1.0);
77+
emissive = vec4<f32>(emissive.rgb * textureSampleBias(emissive_texture, emissive_sampler, uv, view.mip_bias).rgb, 1.0);
7878
}
7979
#endif
8080
pbr_input.material.emissive = emissive;
@@ -83,7 +83,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
8383
var perceptual_roughness: f32 = material.perceptual_roughness;
8484
#ifdef VERTEX_UVS
8585
if ((material.flags & STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) {
86-
let metallic_roughness = textureSample(metallic_roughness_texture, metallic_roughness_sampler, uv);
86+
let metallic_roughness = textureSampleBias(metallic_roughness_texture, metallic_roughness_sampler, uv, view.mip_bias);
8787
// Sampling from GLTF standard channels for now
8888
metallic = metallic * metallic_roughness.b;
8989
perceptual_roughness = perceptual_roughness * metallic_roughness.g;
@@ -96,7 +96,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
9696
var occlusion: vec3<f32> = vec3(1.0);
9797
#ifdef VERTEX_UVS
9898
if ((material.flags & STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {
99-
occlusion = vec3(textureSample(occlusion_texture, occlusion_sampler, in.uv).r);
99+
occlusion = vec3(textureSampleBias(occlusion_texture, occlusion_sampler, in.uv, view.mip_bias).r);
100100
}
101101
#endif
102102
#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION

crates/bevy_pbr/src/render/pbr_functions.wgsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ fn apply_normal_mapping(
8282
#ifdef VERTEX_UVS
8383
#ifdef STANDARDMATERIAL_NORMAL_MAP
8484
// Nt is the tangent-space normal.
85-
var Nt = textureSample(normal_map_texture, normal_map_sampler, uv).rgb;
85+
var Nt = textureSampleBias(normal_map_texture, normal_map_sampler, uv, view.mip_bias).rgb;
8686
if (standard_material_flags & STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP) != 0u {
8787
// Only use the xy components and derive z for 2-component normal maps.
8888
Nt = vec3<f32>(Nt.rg * 2.0 - 1.0, 0.0);

crates/bevy_pbr/src/render/pbr_prepass.wgsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn prepass_alpha_discard(in: FragmentInput) {
3939

4040
#ifdef VERTEX_UVS
4141
if (material.flags & STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u {
42-
output_color = output_color * textureSample(base_color_texture, base_color_sampler, in.uv);
42+
output_color = output_color * textureSampleBias(base_color_texture, base_color_sampler, in.uv, view.mip_bias);
4343
}
4444
#endif // VERTEX_UVS
4545

crates/bevy_render/src/camera/camera.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,3 +771,9 @@ impl TemporalJitter {
771771
projection.z_axis.y += jitter.y;
772772
}
773773
}
774+
775+
/// Camera component specifying a mip bias to apply when sampling from material textures.
776+
///
777+
/// Often used in conjunction with antialiasing post-process effects to reduce textures blurriness.
778+
#[derive(Component)]
779+
pub struct MipBias(pub f32);

crates/bevy_render/src/view/mod.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use visibility::*;
66
pub use window::*;
77

88
use crate::{
9-
camera::{ExtractedCamera, ManualTextureViews, TemporalJitter},
9+
camera::{ExtractedCamera, ManualTextureViews, MipBias, TemporalJitter},
1010
extract_resource::{ExtractResource, ExtractResourcePlugin},
1111
prelude::{Image, Shader},
1212
render_asset::RenderAssets,
@@ -173,6 +173,7 @@ pub struct ViewUniform {
173173
// viewport(x_origin, y_origin, width, height)
174174
viewport: Vec4,
175175
color_grading: ColorGrading,
176+
mip_bias: f32,
176177
}
177178

178179
#[derive(Resource, Default)]
@@ -352,11 +353,16 @@ pub fn prepare_view_uniforms(
352353
render_device: Res<RenderDevice>,
353354
render_queue: Res<RenderQueue>,
354355
mut view_uniforms: ResMut<ViewUniforms>,
355-
views: Query<(Entity, &ExtractedView, Option<&TemporalJitter>)>,
356+
views: Query<(
357+
Entity,
358+
&ExtractedView,
359+
Option<&TemporalJitter>,
360+
Option<&MipBias>,
361+
)>,
356362
) {
357363
view_uniforms.uniforms.clear();
358364

359-
for (entity, camera, temporal_jitter) in &views {
365+
for (entity, camera, temporal_jitter, mip_bias) in &views {
360366
let viewport = camera.viewport.as_vec4();
361367
let unjittered_projection = camera.projection;
362368
let mut projection = unjittered_projection;
@@ -383,6 +389,7 @@ pub fn prepare_view_uniforms(
383389
world_position: camera.transform.translation(),
384390
viewport,
385391
color_grading: camera.color_grading,
392+
mip_bias: mip_bias.unwrap_or(&MipBias(0.0)).0,
386393
}),
387394
};
388395

crates/bevy_render/src/view/view.wgsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ struct View {
1919
// viewport(x_origin, y_origin, width, height)
2020
viewport: vec4<f32>,
2121
color_grading: ColorGrading,
22+
mip_bias: f32,
2223
};

0 commit comments

Comments
 (0)