//! This example showcases different blend modes. //! //! ## Controls //! //! | Key Binding | Action | //! |:-------------------|:------------------------------------| //! | `Up` / `Down` | Increase / Decrease Alpha | //! | `Left` / `Right` | Rotate Camera | //! | `H` | Toggle HDR | //! | `Spacebar` | Toggle Unlit | //! | `C` | Randomize Colors | use bevy::{color::palettes::css::ORANGE, prelude::*}; use rand::random; fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, example_control_system); // Unfortunately, MSAA and HDR are not supported simultaneously under WebGL. // Since this example uses HDR, we must disable MSAA for Wasm builds, at least // until WebGPU is ready and no longer behind a feature flag in Web browsers. #[cfg(target_arch = "wasm32")] app.insert_resource(Msaa::Off); app.run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, asset_server: Res, ) { let base_color = Color::srgb(0.9, 0.2, 0.3); let icosphere_mesh = meshes.add(Sphere::new(0.9).mesh().ico(7).unwrap()); // Opaque let opaque = commands .spawn(( Mesh3d(icosphere_mesh.clone()), MeshMaterial3d(materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Opaque, ..default() })), Transform::from_xyz(-4.0, 0.0, 0.0), ExampleControls { unlit: true, color: true, }, )) .id(); // Blend let blend = commands .spawn(( Mesh3d(icosphere_mesh.clone()), MeshMaterial3d(materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Blend, ..default() })), Transform::from_xyz(-2.0, 0.0, 0.0), ExampleControls { unlit: true, color: true, }, )) .id(); // Premultiplied let premultiplied = commands .spawn(( Mesh3d(icosphere_mesh.clone()), MeshMaterial3d(materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Premultiplied, ..default() })), Transform::from_xyz(0.0, 0.0, 0.0), ExampleControls { unlit: true, color: true, }, )) .id(); // Add let add = commands .spawn(( Mesh3d(icosphere_mesh.clone()), MeshMaterial3d(materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Add, ..default() })), Transform::from_xyz(2.0, 0.0, 0.0), ExampleControls { unlit: true, color: true, }, )) .id(); // Multiply let multiply = commands .spawn(( Mesh3d(icosphere_mesh), MeshMaterial3d(materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Multiply, ..default() })), Transform::from_xyz(4.0, 0.0, 0.0), ExampleControls { unlit: true, color: true, }, )) .id(); // Chessboard Plane let black_material = materials.add(Color::BLACK); let white_material = materials.add(Color::WHITE); let plane_mesh = meshes.add(Plane3d::default().mesh().size(2.0, 2.0)); for x in -3..4 { for z in -3..4 { commands.spawn(( Mesh3d(plane_mesh.clone()), MeshMaterial3d(if (x + z) % 2 == 0 { black_material.clone() } else { white_material.clone() }), Transform::from_xyz(x as f32 * 2.0, -1.0, z as f32 * 2.0), ExampleControls { unlit: false, color: true, }, )); } } // Light commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 8.0, 4.0))); // Camera commands.spawn(( Camera3d::default(), Transform::from_xyz(0.0, 2.5, 10.0).looking_at(Vec3::ZERO, Vec3::Y), )); // Controls Text // We need the full version of this font so we can use box drawing characters. let text_style = TextFont { font: asset_server.load("fonts/FiraMono-Medium.ttf"), ..default() }; let label_text_style = (text_style.clone(), TextColor(ORANGE.into())); commands.spawn((Text::new("Up / Down — Increase / Decrease Alpha\nLeft / Right — Rotate Camera\nH - Toggle HDR\nSpacebar — Toggle Unlit\nC — Randomize Colors"), text_style.clone(), Style { position_type: PositionType::Absolute, top: Val::Px(12.0), left: Val::Px(12.0), ..default() }) ); commands.spawn(( Text::default(), text_style, Style { position_type: PositionType::Absolute, top: Val::Px(12.0), right: Val::Px(12.0), ..default() }, ExampleDisplay, )); let mut label = |entity: Entity, label: &str| { commands .spawn(( NodeBundle { style: Style { position_type: PositionType::Absolute, ..default() }, ..default() }, ExampleLabel { entity }, )) .with_children(|parent| { parent.spawn(( Text::new(label), label_text_style.clone(), Style { position_type: PositionType::Absolute, bottom: Val::ZERO, ..default() }, TextLayout::default().with_no_wrap(), )); }); }; label(opaque, "┌─ Opaque\n│\n│\n│\n│"); label(blend, "┌─ Blend\n│\n│\n│"); label(premultiplied, "┌─ Premultiplied\n│\n│"); label(add, "┌─ Add\n│"); label(multiply, "┌─ Multiply"); } #[derive(Component)] struct ExampleControls { unlit: bool, color: bool, } #[derive(Component)] struct ExampleLabel { entity: Entity, } struct ExampleState { alpha: f32, unlit: bool, } #[derive(Component)] struct ExampleDisplay; impl Default for ExampleState { fn default() -> Self { ExampleState { alpha: 0.9, unlit: false, } } } #[allow(clippy::too_many_arguments)] fn example_control_system( mut materials: ResMut>, controllable: Query<(&MeshMaterial3d, &ExampleControls)>, mut camera: Query<(&mut Camera, &mut Transform, &GlobalTransform), With>, mut labels: Query<(&mut Style, &ExampleLabel)>, mut display: Query<&mut Text, With>, labelled: Query<&GlobalTransform>, mut state: Local, time: Res