//! 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::{math::ops, 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 writer: TextUiWriter, text: Single>, ) { 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 { 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; *writer.text(*text, 1) = 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>, text: Single>, mut writer: TextUiWriter, mut current: Local, ) { if input.just_pressed(KeyCode::Space) { current.next_method(); } else { return; } let text_entity = *text; *writer.text(text_entity, 3) = 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, text: Single>, mut writer: TextUiWriter, ) { 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 = ops::exp2(target_layers.0); let text_entity = *text; *writer.text(text_entity, 2) = format!("Layers: {layer_count:.0}\n"); for (_, mat) in materials.iter_mut() { mat.max_parallax_layer_count = layer_count; } } fn spin(time: Res