
# Objective - #17581 broke gizmos - Fixes #18325 ## Solution - Revert #17581 - Add gizmos to testbed ## Testing - Run any example with gizmos, it renders correctly
327 lines
9.4 KiB
Rust
327 lines
9.4 KiB
Rust
//! 3d testbed
|
|
//!
|
|
//! You can switch scene by pressing the spacebar
|
|
|
|
mod helpers;
|
|
|
|
use bevy::prelude::*;
|
|
use helpers::Next;
|
|
|
|
fn main() {
|
|
let mut app = App::new();
|
|
app.add_plugins((DefaultPlugins,))
|
|
.init_state::<Scene>()
|
|
.add_systems(OnEnter(Scene::Light), light::setup)
|
|
.add_systems(OnEnter(Scene::Bloom), bloom::setup)
|
|
.add_systems(OnEnter(Scene::Gltf), gltf::setup)
|
|
.add_systems(OnEnter(Scene::Animation), animation::setup)
|
|
.add_systems(OnEnter(Scene::Gizmos), gizmos::setup)
|
|
.add_systems(Update, switch_scene)
|
|
.add_systems(Update, gizmos::draw_gizmos.run_if(in_state(Scene::Gizmos)));
|
|
|
|
#[cfg(feature = "bevy_ci_testing")]
|
|
app.add_systems(Update, helpers::switch_scene_in_ci::<Scene>);
|
|
|
|
app.run();
|
|
}
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, States, Default)]
|
|
#[states(scoped_entities)]
|
|
enum Scene {
|
|
#[default]
|
|
Light,
|
|
Bloom,
|
|
Gltf,
|
|
Animation,
|
|
Gizmos,
|
|
}
|
|
|
|
impl Next for Scene {
|
|
fn next(&self) -> Self {
|
|
match self {
|
|
Scene::Light => Scene::Bloom,
|
|
Scene::Bloom => Scene::Gltf,
|
|
Scene::Gltf => Scene::Animation,
|
|
Scene::Animation => Scene::Gizmos,
|
|
Scene::Gizmos => Scene::Light,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn switch_scene(
|
|
keyboard: Res<ButtonInput<KeyCode>>,
|
|
scene: Res<State<Scene>>,
|
|
mut next_scene: ResMut<NextState<Scene>>,
|
|
) {
|
|
if keyboard.just_pressed(KeyCode::Space) {
|
|
info!("Switching scene");
|
|
next_scene.set(scene.get().next());
|
|
}
|
|
}
|
|
|
|
mod light {
|
|
use std::f32::consts::PI;
|
|
|
|
use bevy::{
|
|
color::palettes::css::{DEEP_PINK, LIME, RED},
|
|
prelude::*,
|
|
};
|
|
|
|
const CURRENT_SCENE: super::Scene = super::Scene::Light;
|
|
|
|
pub fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
commands.spawn((
|
|
Mesh3d(meshes.add(Plane3d::default().mesh().size(10.0, 10.0))),
|
|
MeshMaterial3d(materials.add(StandardMaterial {
|
|
base_color: Color::WHITE,
|
|
perceptual_roughness: 1.0,
|
|
..default()
|
|
})),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
Mesh3d(meshes.add(Cuboid::default())),
|
|
MeshMaterial3d(materials.add(StandardMaterial {
|
|
base_color: DEEP_PINK.into(),
|
|
..default()
|
|
})),
|
|
Transform::from_xyz(0.0, 1.0, 0.0),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
PointLight {
|
|
intensity: 100_000.0,
|
|
color: RED.into(),
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
Transform::from_xyz(1.0, 2.0, 0.0),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
SpotLight {
|
|
intensity: 100_000.0,
|
|
color: LIME.into(),
|
|
shadows_enabled: true,
|
|
inner_angle: 0.6,
|
|
outer_angle: 0.8,
|
|
..default()
|
|
},
|
|
Transform::from_xyz(-1.0, 2.0, 0.0).looking_at(Vec3::new(-1.0, 0.0, 0.0), Vec3::Z),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
DirectionalLight {
|
|
illuminance: light_consts::lux::OVERCAST_DAY,
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
Transform {
|
|
translation: Vec3::new(0.0, 2.0, 0.0),
|
|
rotation: Quat::from_rotation_x(-PI / 4.),
|
|
..default()
|
|
},
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
}
|
|
}
|
|
|
|
mod bloom {
|
|
use bevy::{
|
|
core_pipeline::{bloom::Bloom, tonemapping::Tonemapping},
|
|
prelude::*,
|
|
};
|
|
|
|
const CURRENT_SCENE: super::Scene = super::Scene::Bloom;
|
|
|
|
pub fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Camera {
|
|
hdr: true,
|
|
..default()
|
|
},
|
|
Tonemapping::TonyMcMapface,
|
|
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
Bloom::NATURAL,
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
let material_emissive1 = materials.add(StandardMaterial {
|
|
emissive: LinearRgba::rgb(13.99, 5.32, 2.0),
|
|
..default()
|
|
});
|
|
let material_emissive2 = materials.add(StandardMaterial {
|
|
emissive: LinearRgba::rgb(2.0, 13.99, 5.32),
|
|
..default()
|
|
});
|
|
|
|
let mesh = meshes.add(Sphere::new(0.5).mesh().ico(5).unwrap());
|
|
|
|
for z in -2..3_i32 {
|
|
let material = match (z % 2).abs() {
|
|
0 => material_emissive1.clone(),
|
|
1 => material_emissive2.clone(),
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
commands.spawn((
|
|
Mesh3d(mesh.clone()),
|
|
MeshMaterial3d(material),
|
|
Transform::from_xyz(z as f32 * 2.0, 0.0, 0.0),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
mod gltf {
|
|
use bevy::prelude::*;
|
|
|
|
const CURRENT_SCENE: super::Scene = super::Scene::Gltf;
|
|
|
|
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
|
|
EnvironmentMapLight {
|
|
diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
|
|
specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
|
|
intensity: 250.0,
|
|
..default()
|
|
},
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
DirectionalLight {
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
commands.spawn((
|
|
SceneRoot(asset_server.load(
|
|
GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
|
|
)),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
}
|
|
}
|
|
|
|
mod animation {
|
|
use std::{f32::consts::PI, time::Duration};
|
|
|
|
use bevy::{prelude::*, scene::SceneInstanceReady};
|
|
|
|
const CURRENT_SCENE: super::Scene = super::Scene::Animation;
|
|
const FOX_PATH: &str = "models/animated/Fox.glb";
|
|
|
|
#[derive(Resource)]
|
|
struct Animation {
|
|
animation: AnimationNodeIndex,
|
|
graph: Handle<AnimationGraph>,
|
|
}
|
|
|
|
pub fn setup(
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut graphs: ResMut<Assets<AnimationGraph>>,
|
|
) {
|
|
let (graph, node) = AnimationGraph::from_clip(
|
|
asset_server.load(GltfAssetLabel::Animation(2).from_asset(FOX_PATH)),
|
|
);
|
|
|
|
let graph_handle = graphs.add(graph);
|
|
commands.insert_resource(Animation {
|
|
animation: node,
|
|
graph: graph_handle,
|
|
});
|
|
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y),
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands.spawn((
|
|
Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)),
|
|
DirectionalLight {
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
StateScoped(CURRENT_SCENE),
|
|
));
|
|
|
|
commands
|
|
.spawn((
|
|
SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(FOX_PATH))),
|
|
StateScoped(CURRENT_SCENE),
|
|
))
|
|
.observe(pause_animation_frame);
|
|
}
|
|
|
|
fn pause_animation_frame(
|
|
trigger: Trigger<SceneInstanceReady>,
|
|
children: Query<&Children>,
|
|
mut commands: Commands,
|
|
animation: Res<Animation>,
|
|
mut players: Query<(Entity, &mut AnimationPlayer)>,
|
|
) {
|
|
for child in children.iter_descendants(trigger.target()) {
|
|
if let Ok((entity, mut player)) = players.get_mut(child) {
|
|
let mut transitions = AnimationTransitions::new();
|
|
transitions
|
|
.play(&mut player, animation.animation, Duration::ZERO)
|
|
.seek_to(0.5)
|
|
.pause();
|
|
|
|
commands
|
|
.entity(entity)
|
|
.insert(AnimationGraphHandle(animation.graph.clone()))
|
|
.insert(transitions);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mod gizmos {
|
|
use bevy::{color::palettes::css::*, prelude::*};
|
|
|
|
pub fn setup(mut commands: Commands) {
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
StateScoped(super::Scene::Gizmos),
|
|
));
|
|
}
|
|
|
|
pub fn draw_gizmos(mut gizmos: Gizmos) {
|
|
gizmos.cuboid(
|
|
Transform::from_translation(Vec3::X * 2.0).with_scale(Vec3::splat(2.0)),
|
|
RED,
|
|
);
|
|
gizmos
|
|
.sphere(Isometry3d::from_translation(Vec3::X * -2.0), 1.0, GREEN)
|
|
.resolution(30_000 / 3);
|
|
}
|
|
}
|