viewport_node/
viewport_node.rs1use bevy::{
5 camera::RenderTarget, picking::pointer::PointerInteraction, prelude::*,
6 render::render_resource::TextureFormat, ui::widget::ViewportNode,
7};
8
9fn main() {
10 App::new()
11 .add_plugins((DefaultPlugins, MeshPickingPlugin))
12 .add_systems(Startup, test)
13 .add_systems(Update, draw_mesh_intersections)
14 .run();
15}
16
17#[derive(Component, Reflect, Debug)]
18#[reflect(Component)]
19struct Shape;
20
21fn test(
22 mut commands: Commands,
23 mut images: ResMut<Assets<Image>>,
24 mut meshes: ResMut<Assets<Mesh>>,
25 mut materials: ResMut<Assets<StandardMaterial>>,
26) {
27 commands.spawn(Camera3d::default());
29
30 let image = Image::new_target_texture(0, 0, TextureFormat::Bgra8UnormSrgb, None);
33 let image_handle = images.add(image);
34
35 let camera = commands
37 .spawn((
38 Camera3d::default(),
39 Camera {
40 order: -1,
42 ..default()
43 },
44 RenderTarget::Image(image_handle.clone().into()),
45 ))
46 .id();
47
48 commands
50 .spawn((
51 Mesh3d(meshes.add(Cuboid::new(5.0, 5.0, 5.0))),
52 MeshMaterial3d(materials.add(Color::WHITE)),
53 Transform::from_xyz(0.0, 0.0, -10.0),
54 Shape,
55 ))
56 .observe(on_drag_cuboid);
60
61 commands
63 .spawn((
64 Node {
65 position_type: PositionType::Absolute,
66 top: px(50),
67 left: px(50),
68 width: px(200),
69 height: px(200),
70 border: UiRect::all(px(5)),
71 ..default()
72 },
73 BorderColor::all(Color::WHITE),
74 ViewportNode::new(camera),
75 ))
76 .observe(on_drag_viewport);
77}
78
79fn on_drag_viewport(drag: On<PointerDrag>, mut node_query: Query<&mut Node>) {
80 if matches!(drag.button, PointerButton::Secondary) {
81 let mut node = node_query.get_mut(drag.entity).unwrap();
82
83 if let (Val::Px(top), Val::Px(left)) = (node.top, node.left) {
84 node.left = px(left + drag.delta.x);
85 node.top = px(top + drag.delta.y);
86 };
87 }
88}
89
90fn on_drag_cuboid(drag: On<PointerDrag>, mut transform_query: Query<&mut Transform>) {
91 if matches!(drag.button, PointerButton::Primary) {
92 let mut transform = transform_query.get_mut(drag.entity).unwrap();
93 transform.rotate_y(drag.delta.x * 0.02);
94 transform.rotate_x(drag.delta.y * 0.02);
95 }
96}
97
98fn draw_mesh_intersections(
99 pointers: Query<&PointerInteraction>,
100 untargetable: Query<Entity, Without<Shape>>,
101 mut gizmos: Gizmos,
102) {
103 for (point, normal) in pointers
104 .iter()
105 .flat_map(|interaction| interaction.iter())
106 .filter_map(|(entity, hit)| {
107 if !untargetable.contains(*entity) {
108 hit.position.zip(hit.normal)
109 } else {
110 None
111 }
112 })
113 {
114 gizmos.arrow(point, point + normal.normalize() * 0.5, Color::WHITE);
115 }
116}