//! Decal rendering. //! Note: On Wasm, this example only runs on WebGPU use bevy::{ camera_controller::free_camera::{FreeCamera, FreeCameraPlugin}, core_pipeline::prepass::DepthPrepass, pbr::decal::{ForwardDecal, ForwardDecalMaterial, ForwardDecalMaterialExt}, prelude::*, }; use chacha20::ChaCha8Rng; use rand::{RngExt, SeedableRng}; fn main() { App::new() .add_plugins((DefaultPlugins, FreeCameraPlugin)) .add_systems(Startup, setup) .run(); } fn setup( mut commands: Commands, mut meshes: ResMut>, mut standard_materials: ResMut>, mut decal_standard_materials: ResMut>>, asset_server: Res, ) { // Spawn the forward decal commands.spawn(( Name::new("Decal Blue"), ForwardDecal, MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial { base: StandardMaterial { base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")), base_color: Color::srgb(0.3, 0.5, 0.8), alpha_mode: AlphaMode::Opaque, depth_bias: 0.0, ..default() }, extension: ForwardDecalMaterialExt { depth_fade_factor: 1.0, }, })), Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(-1.0, 0.0, -1.0)), )); commands.spawn(( Name::new("Decal Green"), ForwardDecal, MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial { base: StandardMaterial { base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")), base_color: Color::srgba(0.0, 1.0, 0.0, 0.5), alpha_mode: AlphaMode::Blend, depth_bias: 2.0, ..default() }, extension: ForwardDecalMaterialExt { depth_fade_factor: 1.0, }, })), Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(1.0, 0.0, -1.0)), )); commands.spawn(( Name::new("Decal Red"), ForwardDecal, MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial { base: StandardMaterial { base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")), base_color: Color::srgba(1.0, 0.0, 0.0, 0.5), alpha_mode: AlphaMode::Add, depth_bias: 4.0, ..default() }, extension: ForwardDecalMaterialExt { depth_fade_factor: 1.0, }, })), Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(0.0, 0.0, 1.0)), )); commands.spawn(( Name::new("Camera"), Camera3d::default(), FreeCamera::default(), // Must enable the depth prepass to render forward decals DepthPrepass, Transform::from_xyz(2.0, 9.5, 2.5).looking_at(Vec3::ZERO, Vec3::Y), )); let white_material = standard_materials.add(Color::WHITE); commands.spawn(( Name::new("Floor"), Mesh3d(meshes.add(Rectangle::from_length(10.0))), MeshMaterial3d(white_material.clone()), Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)), )); // Spawn a few cube with random rotations to showcase how the decals behave with non-flat geometry let num_obs = 10; let mut rng = ChaCha8Rng::seed_from_u64(19878367467713); for i in 0..num_obs { for j in 0..num_obs { let rotation_axis: [f32; 3] = rng.random(); let rotation_vec: Vec3 = rotation_axis.into(); let rotation: u32 = rng.random_range(0..360); let transform = Transform::from_xyz( (-num_obs + 1) as f32 / 2.0 + i as f32, -0.2, (-num_obs + 1) as f32 / 2.0 + j as f32, ) .with_rotation(Quat::from_axis_angle( rotation_vec.normalize_or_zero(), (rotation as f32).to_radians(), )); commands.spawn(( Mesh3d(meshes.add(Cuboid::from_length(0.6))), MeshMaterial3d(white_material.clone()), transform, )); } } commands.spawn(( Name::new("Light"), PointLight { shadow_maps_enabled: true, ..default() }, Transform::from_xyz(4.0, 8.0, 4.0), )); }