From c249b5ec2a039f152c02ad8a246d28ab6e83ab45 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sat, 3 Feb 2024 13:44:21 +0100 Subject: [PATCH] laser billboard & sorting fix --- src/backend/common.rs | 23 ++++++++++++++++++++++- src/backend/input.rs | 18 ++++++------------ src/backend/openvr/lines.rs | 29 +++++++++++++++++++++++++++-- src/backend/openvr/mod.rs | 1 + src/backend/openxr/lines.rs | 29 +++++++++++++++++++++++++++-- src/backend/openxr/mod.rs | 7 ++++++- 6 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/backend/common.rs b/src/backend/common.rs index abd09ee..807c428 100644 --- a/src/backend/common.rs +++ b/src/backend/common.rs @@ -4,7 +4,7 @@ use std::{ time::Instant, }; -use glam::Vec2; +use glam::{Affine3A, Vec2, Vec3A}; use idmap::IdMap; use crate::{ @@ -180,3 +180,24 @@ impl TaskContainer { } } } + +pub fn raycast( + source: &Affine3A, + source_fwd: Vec3A, + plane: &Affine3A, + plane_norm: Vec3A, +) -> Option<(Vec3A, f32)> { + let plane_normal = plane.transform_vector3a(plane_norm); + let ray_dir = source.transform_vector3a(source_fwd); + + let d = plane.translation.dot(-plane_normal); + let dist = -(d + source.translation.dot(plane_normal)) / ray_dir.dot(plane_normal); + + if dist < 0.0 { + // plane is behind the caster + return None; + } + + let hit_pos = source.translation + ray_dir * dist; + Some((hit_pos, dist)) +} diff --git a/src/backend/input.rs b/src/backend/input.rs index 4cfd6b3..8e4ed52 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -8,7 +8,10 @@ use smallvec::{smallvec, SmallVec}; use crate::state::AppState; -use super::{common::OverlayContainer, overlay::OverlayData}; +use super::{ + common::{raycast, OverlayContainer}, + overlay::OverlayData, +}; pub struct TrackedDevice { #[cfg(feature = "openvr")] @@ -437,18 +440,9 @@ impl Pointer { } fn ray_test(&self, overlay: usize, plane: &Affine3A) -> Option { - let plane_normal = plane.transform_vector3a(Vec3A::NEG_Z); - let ray_dir = self.pose.transform_vector3a(Vec3A::NEG_Z); - - let d = plane.translation.dot(-plane_normal); - let dist = -(d + self.pose.translation.dot(plane_normal)) / ray_dir.dot(plane_normal); - - if dist < 0.0 { - // plane is behind the caster + let Some((hit_pos, dist)) = raycast(&self.pose, Vec3A::NEG_Z, plane, Vec3A::NEG_Z) else { return None; - } - - let hit_pos = self.pose.translation + ray_dir * dist; + }; Some(RayHit { overlay, diff --git a/src/backend/openvr/lines.rs b/src/backend/openvr/lines.rs index d537985..6eb9099 100644 --- a/src/backend/openvr/lines.rs +++ b/src/backend/openvr/lines.rs @@ -87,11 +87,36 @@ impl LinePool { id } - pub fn draw_from(&mut self, id: usize, mut from: Affine3A, len: f32, color: usize) { + pub fn draw_from( + &mut self, + id: usize, + mut from: Affine3A, + len: f32, + color: usize, + hmd: &Affine3A, + ) { let rotation = Affine3A::from_axis_angle(Vec3::X, -PI * 0.5); from.translation = from.translation + from.transform_vector3a(Vec3A::NEG_Z) * (len * 0.5); - let transform = from * rotation * Affine3A::from_scale(Vec3::new(1., len / 0.002, 1.)); + let mut transform = from * rotation * Affine3A::from_scale(Vec3::new(1., len / 0.002, 1.)); + + let to_hmd = hmd.translation - from.translation; + let sides = [Vec3A::Z, Vec3A::X, Vec3A::NEG_Z, Vec3A::NEG_X]; + let rotations = [ + Affine3A::IDENTITY, + Affine3A::from_axis_angle(Vec3::Y, PI * 0.5), + Affine3A::from_axis_angle(Vec3::Y, PI * 1.0), + Affine3A::from_axis_angle(Vec3::Y, PI * 1.5), + ]; + let mut closest = (0, 0.0); + for (i, &side) in sides.iter().enumerate() { + let dot = to_hmd.dot(transform.transform_vector3a(side)); + if i == 0 || dot > closest.1 { + closest = (i, dot); + } + } + + transform = transform * rotations[closest.0]; debug_assert!(color < self.colors.len()); diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index 88dd75a..5160b03 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -169,6 +169,7 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { state.input_state.pointers[idx].pose, *len, state.input_state.pointers[idx].interaction.mode as usize + 1, + &state.input_state.hmd, ); } diff --git a/src/backend/openxr/lines.rs b/src/backend/openxr/lines.rs index 73b7ec9..f4d6319 100644 --- a/src/backend/openxr/lines.rs +++ b/src/backend/openxr/lines.rs @@ -68,7 +68,14 @@ impl LinePool { id } - pub(super) fn draw_from(&mut self, id: usize, mut from: Affine3A, len: f32, color: usize) { + pub(super) fn draw_from( + &mut self, + id: usize, + mut from: Affine3A, + len: f32, + color: usize, + hmd: &Affine3A, + ) { if len < 0.01 { return; } @@ -83,7 +90,25 @@ impl LinePool { let rotation = Affine3A::from_axis_angle(Vec3::X, PI * 1.5); from.translation = from.translation + from.transform_vector3a(Vec3A::NEG_Z) * (len * 0.5); - let transform = from * rotation; + let mut transform = from * rotation; + + let to_hmd = hmd.translation - from.translation; + let sides = [Vec3A::Z, Vec3A::X, Vec3A::NEG_Z, Vec3A::NEG_X]; + let rotations = [ + Affine3A::IDENTITY, + Affine3A::from_axis_angle(Vec3::Y, PI * 0.5), + Affine3A::from_axis_angle(Vec3::Y, PI * -1.0), + Affine3A::from_axis_angle(Vec3::Y, PI * 1.5), + ]; + let mut closest = (0, 0.0); + for (i, &side) in sides.iter().enumerate() { + let dot = to_hmd.dot(transform.transform_vector3a(side)); + if i == 0 || dot > closest.1 { + closest = (i, dot); + } + } + + transform = transform * rotations[closest.0]; let posef = transform_to_posef(&transform); diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index 10478f6..491e041 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -230,6 +230,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { app_state.input_state.pointers[idx].pose, *len, app_state.input_state.pointers[idx].interaction.mode as usize + 1, + &app_state.input_state.hmd, ); } @@ -253,6 +254,10 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { let dist_sq = (app_state.input_state.hmd.translation - o.state.transform.translation) .length_squared(); + if !dist_sq.is_normal() { + continue; + } + if let Some(quad) = o.present_xr(&xr_state, &mut command_buffer) { layers.push((dist_sq, quad)); }; @@ -264,7 +269,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { command_buffer.build_and_execute_now(); - layers.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap()); + layers.sort_by(|a, b| b.0.total_cmp(&a.0)); let frame_ref = layers .iter()