Skip to content

Commit

Permalink
Option to enable deterministic rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
stepancheg committed Jan 8, 2024
1 parent c1b785c commit cfc756e
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,17 @@ description = "Showcases different blend modes"
category = "3D Rendering"
wasm = true

[[example]]
name = "deterministic"
path = "examples/3d/deterministic.rs"
doc-scrape-examples = true

[package.metadata.example.deterministic]
name = "Deterministic rendering"
description = "Stop flickering from z-fighting at a performance cost"
category = "3D Rendering"
wasm = true

[[example]]
name = "lighting"
path = "examples/3d/lighting.rs"
Expand Down
14 changes: 14 additions & 0 deletions crates/bevy_render/src/deterministic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use bevy_ecs::system::Resource;

/// Configure deterministic rendering to fix flickering due to z-fighting.
#[derive(Resource, Default)]
pub struct DeterministicRenderingConfig {
/// Sort visible entities by id before rendering to avoid flickering.
///
/// Render is parallel by default, and if there's z-fighting, it may cause flickering.
/// Default fix for the issue is to set `depth_bias` per material.
/// When it is not possible, entities sorting can be used.
///
/// This option costs performance and disabled by default.
pub stable_sort_z_fighting: bool,
}
4 changes: 4 additions & 0 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ extern crate core;
pub mod batching;
pub mod camera;
pub mod color;
pub mod deterministic;
pub mod extract_component;
pub mod extract_instances;
mod extract_param;
Expand Down Expand Up @@ -48,6 +49,7 @@ use bevy_window::{PrimaryWindow, RawHandleWrapper};
use globals::GlobalsPlugin;
use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue};

use crate::deterministic::DeterministicRenderingConfig;
use crate::{
camera::CameraPlugin,
mesh::{morph::MorphPlugin, Mesh, MeshPlugin},
Expand Down Expand Up @@ -209,6 +211,8 @@ pub const MATHS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(106653563
impl Plugin for RenderPlugin {
/// Initializes the renderer, sets up the [`RenderSet`] and creates the rendering sub-app.
fn build(&self, app: &mut App) {
app.init_resource::<DeterministicRenderingConfig>();

app.init_asset::<Shader>()
.init_asset_loader::<ShaderLoader>();

Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_render/src/view/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use bevy_transform::{components::GlobalTransform, TransformSystem};
use std::cell::Cell;
use thread_local::ThreadLocal;

use crate::deterministic::DeterministicRenderingConfig;
use crate::{
camera::{
camera_system, Camera, CameraProjection, OrthographicProjection, PerspectiveProjection,
Expand Down Expand Up @@ -392,6 +393,7 @@ pub fn check_visibility(
&GlobalTransform,
Has<NoFrustumCulling>,
)>,
deterministic_rendering_config: Res<DeterministicRenderingConfig>,
) {
for (mut visible_entities, frustum, maybe_view_mask, camera) in &mut view_query {
if !camera.is_active {
Expand Down Expand Up @@ -452,6 +454,9 @@ pub fn check_visibility(
for cell in &mut thread_queues {
visible_entities.entities.append(cell.get_mut());
}
if deterministic_rendering_config.stable_sort_z_fighting {
visible_entities.entities.sort_unstable();
}
}
}

Expand Down
87 changes: 87 additions & 0 deletions examples/3d/deterministic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! Shows how to enable deterministic rendering which helps with flickering due to z-fighting.
//! Rendering is not deterministic by default.
//! Note most users don't need rendering to be deterministic, and should rely on depth bias instead.

use bevy::app::App;
use bevy::app::Startup;
use bevy::prelude::shape::Plane;
use bevy::prelude::*;
use bevy::render::deterministic::DeterministicRenderingConfig;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, (keys, update_help).chain())
.run();
}

fn setup(
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut deterministic_rendering_config: ResMut<DeterministicRenderingConfig>,
) {
// Safe default.
deterministic_rendering_config.stable_sort_z_fighting = true;

// Help message will be rendered there.
commands.spawn(TextBundle::default());

commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(3.0, 3.0, 3.0).looking_at(Vec3::new(0., 0., 0.), Vec3::Y),
..default()
});

let mesh = meshes.add(Plane::from_size(2.0).into());
for i in 0..360 {
let color = Color::hsl(i as f32, 1.0, 0.5);
commands.spawn(PbrBundle {
mesh: mesh.clone(),
material: materials.add(StandardMaterial {
base_color: color,
// Setting depth bias would be a default choice to fix z-fighting.
// When it is not possible, deterministic rendering can be used.
// Here we intentionally don't use depth bias to demonstrate the issue.
depth_bias: 0.0,
unlit: true,
..Default::default()
}),
..default()
});
}
}

fn keys(
mut deterministic_rendering_config: ResMut<DeterministicRenderingConfig>,
keyboard_input: Res<ButtonInput<KeyCode>>,
) {
if keyboard_input.just_pressed(KeyCode::KeyD) {
deterministic_rendering_config.stable_sort_z_fighting ^= true;
}
}

fn update_help(
mut text: Query<&mut Text>,
deterministic_rendering_config: Res<DeterministicRenderingConfig>,
) {
if deterministic_rendering_config.is_changed() {
*text.single_mut() = Text::from_section(
format!(
"\
Press D to enable/disable deterministic rendering\n\
\n\
Deterministic rendering: {}\n\
\n\
When rendering is not deterministic, you may notice flickering due to z-fighting\n\
\n\
Warning: may cause seizures for people with photosensitive epilepsy",
deterministic_rendering_config.stable_sort_z_fighting
),
TextStyle {
font_size: 20.,
..default()
},
);
}
}
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Example | Description
[Atmospheric Fog](../examples/3d/atmospheric_fog.rs) | A scene showcasing the atmospheric fog effect
[Blend Modes](../examples/3d/blend_modes.rs) | Showcases different blend modes
[Deferred Rendering](../examples/3d/deferred_rendering.rs) | Renders meshes with both forward and deferred pipelines
[Deterministic rendering](../examples/3d/deterministic.rs) | Stop flickering from z-fighting at a performance cost
[Fog](../examples/3d/fog.rs) | A scene showcasing the distance fog effect
[Generate Custom Mesh](../examples/3d/generate_custom_mesh.rs) | Simple showcase of how to generate a custom mesh with a custom texture
[Lighting](../examples/3d/lighting.rs) | Illustrates various lighting options in a simple scene
Expand Down

0 comments on commit cfc756e

Please sign in to comment.