//! A simple 3D scene with light shining over a cube sitting on a plane. mod kneeboardplugin; mod vrcontrollerplugin; mod vrplugin; use bevy_cef::prelude::{Browsers, MeshAabb, WebviewSize, WebviewSource}; use bevy_mod_openxr::openxr_session_running; use bevy_mod_xr::camera::XrCamera; use vrplugin::VrPlugin; use bevy::prelude::*; use crate::{ kneeboardplugin::{Kneeboard, KneeboardPlugin, LookedAt}, vrcontrollerplugin::VrControllersPlugin, }; fn main() { App::new() .add_plugins((VrPlugin, MeshPickingPlugin)) .add_plugins(VrControllersPlugin) .add_plugins(KneeboardPlugin) .insert_resource(ClearColor(Color::NONE)) .add_systems(Update, head_pointer.run_if(openxr_session_running)) .run(); } #[allow(clippy::type_complexity)] fn head_pointer( browsers: NonSend, webviews: Query<(Entity, &WebviewSize), With>, headset: Query<&GlobalTransform, With>, kneeboard: Query<(&GlobalTransform, Option<&LookedAt>), With>, aabb: MeshAabb, ) { let Ok((webview, size)) = webviews.single() else { return; }; let tex_size = size.0; if let Some(gt) = headset.into_iter().next() { let Ok((plane_tf, looked_at)) = kneeboard.single() else { return; }; if looked_at.is_some() { // this is inverted for some reason wtf return; } let (min, max) = aabb.calculate_local(webview); let plane_size = Vec2::new(max.x - min.x, max.y - min.y); let ray = Ray3d::new(gt.translation(), gt.forward()); let n = plane_tf.forward().as_vec3(); let Some(t) = ray.intersect_plane( plane_tf.translation(), InfinitePlane3d::new(plane_tf.forward()), ) else { return; }; let hit_world = ray.origin + ray.direction * t; let local_hit = plane_tf.affine().inverse().transform_point(hit_world); let local_normal = plane_tf.affine().inverse().transform_vector3(n).normalize(); let abs_normal = local_normal.abs(); let (u_coord, v_coord) = if abs_normal.z > abs_normal.x && abs_normal.z > abs_normal.y { (local_hit.x, local_hit.y) } else if abs_normal.y > abs_normal.x { (local_hit.x, local_hit.z) } else { (local_hit.y, local_hit.z) }; let w = plane_size.x; let h = plane_size.y; let u = (u_coord + w * 0.5) / w; let v = (v_coord + h * 0.5) / h; if !(0.0..=1.0).contains(&u) || !(0.0..=1.0).contains(&v) { // outside plane bounds return; } let px = (1.0 - u) * tex_size.x; let py = (1.0 - v) * tex_size.y; let pos = Vec2::new(px, py); browsers.send_mouse_move(&webview, &[], pos, false); } }