Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to enable deterministic rendering #11248

Merged
merged 2 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
7 changes: 7 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,11 @@ 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 {
// We can use the faster unstable sort here because
// the values (`Entity`) are guaranteed to be unique.
visible_entities.entities.sort_unstable();
stepancheg marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

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());
alice-i-cecile marked this conversation as resolved.
Show resolved Hide resolved
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