//! Shows how to render UI to a texture. Useful for displaying UI in 3D space. use std::f32::consts::PI; use bevy::picking::PickingSystems; use bevy::{ asset::uuid::Uuid, camera::RenderTarget, color::palettes::css::{BLUE, GRAY, RED}, input::ButtonState, picking::{ backend::ray::RayMap, pointer::{Location, PointerAction, PointerId, PointerInput}, }, prelude::*, render::render_resource::TextureFormat, window::{PrimaryWindow, WindowEvent}, }; const CUBE_POINTER_ID: PointerId = PointerId::Custom(Uuid::from_u128(90870987)); fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, rotator_system) .add_systems(First, drive_diegetic_pointer.in_set(PickingSystems::Input)) .run(); } // Marks the cube, to which the UI texture is applied. #[derive(Component)] struct Cube; fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, mut images: ResMut>, ) { // This is the texture that will be rendered to. let image = Image::new_target_texture(512, 512, TextureFormat::Bgra8UnormSrgb, None); let image_handle = images.add(image); // Light commands.spawn(DirectionalLight::default()); let texture_camera = commands .spawn(( Camera2d, Camera { // render before the "main pass" camera order: -1, ..default() }, RenderTarget::Image(image_handle.clone().into()), )) .id(); commands .spawn(( Node { // Cover the whole image width: percent(100), height: percent(100), flex_direction: FlexDirection::Column, justify_content: JustifyContent::Center, align_items: AlignItems::Center, ..default() }, BackgroundColor(GRAY.into()), UiTargetCamera(texture_camera), )) .with_children(|parent| { parent .spawn(( Node { position_type: PositionType::Absolute, width: auto(), height: auto(), align_items: AlignItems::Center, padding: UiRect::all(px(20.)), border_radius: BorderRadius::all(px(10.)), ..default() }, BackgroundColor(BLUE.into()), )) .observe( |drag: On>, mut nodes: Query<(&mut Node, &ComputedNode)>| { let (mut node, computed) = nodes.get_mut(drag.entity).unwrap(); node.left = px(drag.pointer_location.position.x - computed.size.x / 2.0); node.top = px(drag.pointer_location.position.y - 50.0); }, ) .observe( |over: On>, mut colors: Query<&mut BackgroundColor>| { colors.get_mut(over.entity).unwrap().0 = RED.into(); }, ) .observe( |out: On>, mut colors: Query<&mut BackgroundColor>| { colors.get_mut(out.entity).unwrap().0 = BLUE.into(); }, ) .with_children(|parent| { parent.spawn(( Text::new("Drag Me!"), TextFont { font_size: FontSize::Px(40.0), ..default() }, TextColor::WHITE, )); }); }); let mesh_handle = meshes.add(Cuboid::default()); // This material has the texture that has been rendered. let material_handle = materials.add(StandardMaterial { base_color_texture: Some(image_handle), reflectance: 0.02, unlit: false, ..default() }); // Cube with material containing the rendered UI texture. commands.spawn(( Mesh3d(mesh_handle), MeshMaterial3d(material_handle), Transform::from_xyz(0.0, 0.0, 1.5).with_rotation(Quat::from_rotation_x(PI)), Cube, )); // The main pass camera. commands.spawn(( Camera3d::default(), Transform::from_xyz(0.0, 0.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), )); commands.spawn(CUBE_POINTER_ID); } const ROTATION_SPEED: f32 = 0.1; fn rotator_system(time: Res