//! 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::prelude::*; use rand::random; fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins) .add_startup_system(setup) .add_system(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 { samples: 1 }); // Default is 4 samples (MSAA on) 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::rgba(0.9, 0.2, 0.3, 1.0); let icosphere_mesh = meshes.add( Mesh::try_from(shape::Icosphere { radius: 0.9, subdivisions: 7, }) .unwrap(), ); // Opaque let opaque = commands .spawn(( PbrBundle { mesh: icosphere_mesh.clone(), material: materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Opaque, ..default() }), transform: Transform::from_xyz(-4.0, 0.0, 0.0), ..default() }, ExampleControls { unlit: true, color: true, }, )) .id(); // Blend let blend = commands .spawn(( PbrBundle { mesh: icosphere_mesh.clone(), material: materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Blend, ..default() }), transform: Transform::from_xyz(-2.0, 0.0, 0.0), ..default() }, ExampleControls { unlit: true, color: true, }, )) .id(); // Premultiplied let premultiplied = commands .spawn(( PbrBundle { mesh: icosphere_mesh.clone(), material: materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Premultiplied, ..default() }), transform: Transform::from_xyz(0.0, 0.0, 0.0), ..default() }, ExampleControls { unlit: true, color: true, }, )) .id(); // Add let add = commands .spawn(( PbrBundle { mesh: icosphere_mesh.clone(), material: materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Add, ..default() }), transform: Transform::from_xyz(2.0, 0.0, 0.0), ..default() }, ExampleControls { unlit: true, color: true, }, )) .id(); // Multiply let multiply = commands .spawn(( PbrBundle { mesh: icosphere_mesh, material: materials.add(StandardMaterial { base_color, alpha_mode: AlphaMode::Multiply, ..default() }), transform: Transform::from_xyz(4.0, 0.0, 0.0), ..default() }, ExampleControls { unlit: true, color: true, }, )) .id(); // Chessboard Plane let black_material = materials.add(Color::BLACK.into()); let white_material = materials.add(Color::WHITE.into()); let plane_mesh = meshes.add(shape::Plane { size: 2.0 }.into()); for x in -3..4 { for z in -3..4 { commands.spawn(( PbrBundle { mesh: plane_mesh.clone(), material: if (x + z) % 2 == 0 { black_material.clone() } else { white_material.clone() }, transform: Transform::from_xyz(x as f32 * 2.0, -1.0, z as f32 * 2.0), ..default() }, ExampleControls { unlit: false, color: true, }, )); } } // Light commands.spawn(PointLightBundle { transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() }); // Camera commands.spawn(Camera3dBundle { transform: Transform::from_xyz(0.0, 2.5, 10.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }); // Controls Text let text_style = TextStyle { font: asset_server.load("fonts/FiraMono-Medium.ttf"), font_size: 18.0, color: Color::BLACK, }; let label_text_style = TextStyle { font: asset_server.load("fonts/FiraMono-Medium.ttf"), font_size: 25.0, color: Color::ORANGE, }; commands.spawn( TextBundle::from_section( "Up / Down — Increase / Decrease Alpha\nLeft / Right — Rotate Camera\nH - Toggle HDR\nSpacebar — Toggle Unlit\nC — Randomize Colors", text_style.clone(), ) .with_style(Style { position_type: PositionType::Absolute, position: UiRect { top: Val::Px(10.0), left: Val::Px(10.0), ..default() }, ..default() }), ); commands.spawn(( TextBundle::from_section("", text_style).with_style(Style { position_type: PositionType::Absolute, position: UiRect { top: Val::Px(10.0), right: Val::Px(10.0), ..default() }, ..default() }), ExampleDisplay, )); commands.spawn(( TextBundle::from_section("┌─ Opaque\n│\n│\n│\n│", label_text_style.clone()).with_style( Style { position_type: PositionType::Absolute, ..default() }, ), ExampleLabel { entity: opaque }, )); commands.spawn(( TextBundle::from_section("┌─ Blend\n│\n│\n│", label_text_style.clone()).with_style(Style { position_type: PositionType::Absolute, ..default() }), ExampleLabel { entity: blend }, )); commands.spawn(( TextBundle::from_section("┌─ Premultiplied\n│\n│", label_text_style.clone()).with_style( Style { position_type: PositionType::Absolute, ..default() }, ), ExampleLabel { entity: premultiplied, }, )); commands.spawn(( TextBundle::from_section("┌─ Add\n│", label_text_style.clone()).with_style(Style { position_type: PositionType::Absolute, ..default() }), ExampleLabel { entity: add }, )); commands.spawn(( TextBundle::from_section("┌─ Multiply", label_text_style).with_style(Style { position_type: PositionType::Absolute, ..default() }), ExampleLabel { entity: 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<(&Handle, &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