mirror of
https://github.com/bevyengine/bevy
synced 2024-11-28 07:30:23 +00:00
Make some examples deterministic (#16488)
# Objective - Improve reproducibility of examples ## Solution - Use seeded rng when needed - Use fixed z-ordering when needed ## Testing ```sh steps=5; echo "cpu_draw\nparallel_query\nanimated_fox\ntransparency_2d" > test cargo run -p example-showcase -- run --stop-frame 250 --screenshot-frame 100 --fixed-frame-time 0.05 --example-list test --in-ci; mv screenshots base; for prefix in `seq 0 $steps`; do echo step $prefix; cargo run -p example-showcase -- run --stop-frame 250 --screenshot-frame 100 --fixed-frame-time 0.05 --example-list test; mv screenshots $prefix-screenshots; done; mv base screenshots for prefix in `seq 0 $steps`; do echo check $prefix for file in screenshots/*/*; do echo $file; diff $file $prefix-$file; done; done; ```
This commit is contained in:
parent
636e99c9fb
commit
a9a4b069b6
4 changed files with 33 additions and 15 deletions
|
@ -11,7 +11,8 @@ use bevy::render::{
|
|||
render_asset::RenderAssetUsages,
|
||||
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
||||
};
|
||||
use rand::Rng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
const IMAGE_WIDTH: u32 = 256;
|
||||
const IMAGE_HEIGHT: u32 = 256;
|
||||
|
@ -33,6 +34,9 @@ fn main() {
|
|||
#[derive(Resource)]
|
||||
struct MyProcGenImage(Handle<Image>);
|
||||
|
||||
#[derive(Resource)]
|
||||
struct SeededRng(ChaCha8Rng);
|
||||
|
||||
fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
|
||||
// spawn a camera
|
||||
commands.spawn(Camera2d);
|
||||
|
@ -80,6 +84,11 @@ fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
|
|||
// create a sprite entity using our image
|
||||
commands.spawn(Sprite::from_image(handle.clone()));
|
||||
commands.insert_resource(MyProcGenImage(handle));
|
||||
|
||||
// We're seeding the PRNG here to make this example deterministic for testing purposes.
|
||||
// This isn't strictly required in practical use unless you need your app to be deterministic.
|
||||
let seeded_rng = ChaCha8Rng::seed_from_u64(19878367467712);
|
||||
commands.insert_resource(SeededRng(seeded_rng));
|
||||
}
|
||||
|
||||
/// Every fixed update tick, draw one more pixel to make a spiral pattern
|
||||
|
@ -89,12 +98,11 @@ fn draw(
|
|||
// used to keep track of where we are
|
||||
mut i: Local<u32>,
|
||||
mut draw_color: Local<Color>,
|
||||
mut seeded_rng: ResMut<SeededRng>,
|
||||
) {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
if *i == 0 {
|
||||
// Generate a random color on first run.
|
||||
*draw_color = Color::linear_rgb(rng.gen(), rng.gen(), rng.gen());
|
||||
*draw_color = Color::linear_rgb(seeded_rng.0.gen(), seeded_rng.0.gen(), seeded_rng.0.gen());
|
||||
}
|
||||
|
||||
// Get the image from Bevy's asset storage.
|
||||
|
@ -117,7 +125,7 @@ fn draw(
|
|||
// If the old color is our current color, change our drawing color.
|
||||
let tolerance = 1.0 / 255.0;
|
||||
if old_color.distance(&draw_color) <= tolerance {
|
||||
*draw_color = Color::linear_rgb(rng.gen(), rng.gen(), rng.gen());
|
||||
*draw_color = Color::linear_rgb(seeded_rng.0.gen(), seeded_rng.0.gen(), seeded_rng.0.gen());
|
||||
}
|
||||
|
||||
// Set the new color, but keep old alpha value from image.
|
||||
|
|
|
@ -23,7 +23,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
color: Color::srgba(0.0, 0.0, 1.0, 0.7),
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(100.0, 0.0, 0.0),
|
||||
Transform::from_xyz(100.0, 0.0, 0.1),
|
||||
));
|
||||
commands.spawn((
|
||||
Sprite {
|
||||
|
@ -31,6 +31,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
color: Color::srgba(0.0, 1.0, 0.0, 0.3),
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(200.0, 0.0, 0.0),
|
||||
Transform::from_xyz(200.0, 0.0, 0.2),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ use bevy::{
|
|||
pbr::CascadeShadowConfigBuilder,
|
||||
prelude::*,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
const FOX_PATH: &str = "models/animated/Fox.glb";
|
||||
|
||||
|
@ -28,6 +29,9 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct SeededRng(ChaCha8Rng);
|
||||
|
||||
#[derive(Resource)]
|
||||
struct Animations {
|
||||
animations: Vec<AnimationNodeIndex>,
|
||||
|
@ -42,19 +46,19 @@ fn observe_on_step(
|
|||
particle: Res<ParticleAssets>,
|
||||
mut commands: Commands,
|
||||
transforms: Query<&GlobalTransform>,
|
||||
mut seeded_rng: ResMut<SeededRng>,
|
||||
) {
|
||||
let translation = transforms.get(trigger.entity()).unwrap().translation();
|
||||
let mut rng = thread_rng();
|
||||
// Spawn a bunch of particles.
|
||||
for _ in 0..14 {
|
||||
let horizontal = rng.gen::<Dir2>() * rng.gen_range(8.0..12.0);
|
||||
let vertical = rng.gen_range(0.0..4.0);
|
||||
let size = rng.gen_range(0.2..1.0);
|
||||
let horizontal = seeded_rng.0.gen::<Dir2>() * seeded_rng.0.gen_range(8.0..12.0);
|
||||
let vertical = seeded_rng.0.gen_range(0.0..4.0);
|
||||
let size = seeded_rng.0.gen_range(0.2..1.0);
|
||||
commands.queue(spawn_particle(
|
||||
particle.mesh.clone(),
|
||||
particle.material.clone(),
|
||||
translation.reject_from_normalized(Vec3::Y),
|
||||
rng.gen_range(0.2..0.6),
|
||||
seeded_rng.0.gen_range(0.2..0.6),
|
||||
size,
|
||||
Vec3::new(horizontal.x, vertical, horizontal.y) * 10.0,
|
||||
));
|
||||
|
@ -121,6 +125,11 @@ fn setup(
|
|||
println!(" - digit 1 / 3 / 5: play the animation <digit> times");
|
||||
println!(" - L: loop the animation forever");
|
||||
println!(" - return: change animation");
|
||||
|
||||
// We're seeding the PRNG here to make this example deterministic for testing purposes.
|
||||
// This isn't strictly required in practical use unless you need your app to be deterministic.
|
||||
let seeded_rng = ChaCha8Rng::seed_from_u64(19878367467712);
|
||||
commands.insert_resource(SeededRng(seeded_rng));
|
||||
}
|
||||
|
||||
// An `AnimationPlayer` is automatically added to the scene when it's ready.
|
||||
|
|
|
@ -14,10 +14,11 @@ fn spawn_system(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
// We're seeding the PRNG here to make this example deterministic for testing purposes.
|
||||
// This isn't strictly required in practical use unless you need your app to be deterministic.
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
|
||||
for _ in 0..128 {
|
||||
for z in 0..128 {
|
||||
commands.spawn((
|
||||
Sprite::from_image(texture.clone()),
|
||||
Transform::from_scale(Vec3::splat(0.1)),
|
||||
Transform::from_scale(Vec3::splat(0.1))
|
||||
.with_translation(Vec2::splat(0.0).extend(z as f32)),
|
||||
Velocity(20.0 * Vec2::new(rng.gen::<f32>() - 0.5, rng.gen::<f32>() - 0.5)),
|
||||
));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue