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