//! A simple 3D scene with a spinning cube with a normal map and depth map to demonstrate parallax mapping. //! Press left mouse button to cycle through different views. use std::fmt; use bevy::{prelude::*, render::texture::ImageLoaderSettings}; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems( Update, ( spin, move_camera, update_parallax_depth_scale, update_parallax_layers, switch_method, ), ) .run(); } #[derive(Component)] struct Spin { speed: f32, } /// The camera, used to move camera on click. #[derive(Component)] struct CameraController; const DEPTH_CHANGE_RATE: f32 = 0.1; const DEPTH_UPDATE_STEP: f32 = 0.03; const MAX_DEPTH: f32 = 0.3; struct TargetDepth(f32); impl Default for TargetDepth { fn default() -> Self { TargetDepth(0.09) } } struct TargetLayers(f32); impl Default for TargetLayers { fn default() -> Self { TargetLayers(5.0) } } struct CurrentMethod(ParallaxMappingMethod); impl Default for CurrentMethod { fn default() -> Self { CurrentMethod(ParallaxMappingMethod::Relief { max_steps: 4 }) } } impl fmt::Display for CurrentMethod { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { ParallaxMappingMethod::Occlusion => write!(f, "Parallax Occlusion Mapping"), ParallaxMappingMethod::Relief { max_steps } => { write!(f, "Relief Mapping with {max_steps} steps") } } } } impl CurrentMethod { fn next_method(&mut self) { use ParallaxMappingMethod::*; self.0 = match self.0 { Occlusion => Relief { max_steps: 2 }, Relief { max_steps } if max_steps < 3 => Relief { max_steps: 4 }, Relief { max_steps } if max_steps < 5 => Relief { max_steps: 8 }, Relief { .. } => Occlusion, } } } fn update_parallax_depth_scale( input: Res>, mut materials: ResMut>, mut target_depth: Local, mut depth_update: Local, mut text: Query<&mut Text>, ) { if input.just_pressed(KeyCode::Digit1) { target_depth.0 -= DEPTH_UPDATE_STEP; target_depth.0 = target_depth.0.max(0.0); *depth_update = true; } if input.just_pressed(KeyCode::Digit2) { target_depth.0 += DEPTH_UPDATE_STEP; target_depth.0 = target_depth.0.min(MAX_DEPTH); *depth_update = true; } if *depth_update { let mut text = text.single_mut(); for (_, mat) in materials.iter_mut() { let current_depth = mat.parallax_depth_scale; let new_depth = current_depth.lerp(target_depth.0, DEPTH_CHANGE_RATE); mat.parallax_depth_scale = new_depth; text.sections[0].value = format!("Parallax depth scale: {new_depth:.5}\n"); if (new_depth - current_depth).abs() <= 0.000000001 { *depth_update = false; } } } } fn switch_method( input: Res>, mut materials: ResMut>, mut text: Query<&mut Text>, mut current: Local, ) { if input.just_pressed(KeyCode::Space) { current.next_method(); } else { return; } let mut text = text.single_mut(); text.sections[2].value = format!("Method: {}\n", *current); for (_, mat) in materials.iter_mut() { mat.parallax_mapping_method = current.0; } } fn update_parallax_layers( input: Res>, mut materials: ResMut>, mut target_layers: Local, mut text: Query<&mut Text>, ) { if input.just_pressed(KeyCode::Digit3) { target_layers.0 -= 1.0; target_layers.0 = target_layers.0.max(0.0); } else if input.just_pressed(KeyCode::Digit4) { target_layers.0 += 1.0; } else { return; } let layer_count = target_layers.0.exp2(); let mut text = text.single_mut(); text.sections[1].value = format!("Layers: {layer_count:.0}\n"); for (_, mat) in materials.iter_mut() { mat.max_parallax_layer_count = layer_count; } } fn spin(time: Res