//! Demonstrates anisotropy with the glTF sample barn lamp model. use bevy::{ color::palettes::css::WHITE, core_pipeline::Skybox, math::vec3, prelude::*, time::Stopwatch, }; /// The initial position of the camera. const CAMERA_INITIAL_POSITION: Vec3 = vec3(-0.4, 0.0, 0.0); /// The current settings of the app, as chosen by the user. #[derive(Resource)] struct AppStatus { /// Which type of light is in the scene. light_mode: LightMode, /// Whether anisotropy is enabled. anisotropy_enabled: bool, } /// Which type of light we're using: a directional light, a point light, or an /// environment map. #[derive(Clone, Copy, PartialEq, Default)] enum LightMode { /// A rotating directional light. #[default] Directional, /// A rotating point light. Point, /// An environment map (image-based lighting, including skybox). EnvironmentMap, } /// A component that stores the version of the material with anisotropy and the /// version of the material without it. /// /// This is placed on each mesh with a material. It exists so that the /// appropriate system can replace the materials when the user presses Enter to /// turn anisotropy on and off. #[derive(Component)] struct MaterialVariants { /// The version of the material in the glTF file, with anisotropy. anisotropic: Handle, /// The version of the material with anisotropy removed. isotropic: Handle, } /// The application entry point. fn main() { App::new() .init_resource::() .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { title: "Bevy Anisotropy Example".into(), ..default() }), ..default() })) .add_systems(Startup, setup) .add_systems(Update, create_material_variants) .add_systems(Update, animate_light) .add_systems(Update, rotate_camera) .add_systems(Update, (handle_input, update_help_text).chain()) .run(); } /// Creates the initial scene. fn setup(mut commands: Commands, asset_server: Res, app_status: Res) { commands.spawn(Camera3dBundle { transform: Transform::from_translation(CAMERA_INITIAL_POSITION) .looking_at(Vec3::ZERO, Vec3::Y), ..default() }); spawn_directional_light(&mut commands); commands.spawn(SceneBundle { scene: asset_server.load("models/AnisotropyBarnLamp/AnisotropyBarnLamp.gltf#Scene0"), transform: Transform::from_xyz(0.0, 0.07, -0.13), ..default() }); spawn_text(&mut commands, &app_status); } /// Spawns the help text. fn spawn_text(commands: &mut Commands, app_status: &AppStatus) { commands.spawn( TextBundle { text: app_status.create_help_text(), ..default() } .with_style(Style { position_type: PositionType::Absolute, bottom: Val::Px(10.0), left: Val::Px(10.0), ..default() }), ); } /// For each material, creates a version with the anisotropy removed. /// /// This allows the user to press Enter to toggle anisotropy on and off. fn create_material_variants( mut commands: Commands, mut materials: ResMut>, new_meshes: Query< (Entity, &Handle), (Added>, Without), >, ) { for (entity, anisotropic_material_handle) in new_meshes.iter() { let Some(anisotropic_material) = materials.get(anisotropic_material_handle).cloned() else { continue; }; commands.entity(entity).insert(MaterialVariants { anisotropic: anisotropic_material_handle.clone(), isotropic: materials.add(StandardMaterial { anisotropy_texture: None, anisotropy_strength: 0.0, anisotropy_rotation: 0.0, ..anisotropic_material }), }); } } /// A system that animates the light every frame, if there is one. fn animate_light( mut lights: Query<&mut Transform, Or<(With, With)>>, time: Res