anchor grab
This commit is contained in:
@@ -11,7 +11,7 @@ use crate::state::{AppSession, AppState};
|
|||||||
use crate::subsystem::hid::WheelDelta;
|
use crate::subsystem::hid::WheelDelta;
|
||||||
use crate::subsystem::input::KeyboardFocus;
|
use crate::subsystem::input::KeyboardFocus;
|
||||||
use crate::windowing::manager::OverlayWindowManager;
|
use crate::windowing::manager::OverlayWindowManager;
|
||||||
use crate::windowing::window::{OverlayWindowData, OverlayWindowState, Positioning};
|
use crate::windowing::window::{realign, OverlayWindowData, OverlayWindowState, Positioning};
|
||||||
use crate::windowing::{OverlayID, OverlaySelector};
|
use crate::windowing::{OverlayID, OverlaySelector};
|
||||||
|
|
||||||
use super::task::{TaskContainer, TaskType};
|
use super::task::{TaskContainer, TaskType};
|
||||||
@@ -274,8 +274,7 @@ struct RayHit {
|
|||||||
pub struct GrabData {
|
pub struct GrabData {
|
||||||
pub offset: Vec3A,
|
pub offset: Vec3A,
|
||||||
pub grabbed_id: OverlayID,
|
pub grabbed_id: OverlayID,
|
||||||
pub old_curvature: Option<f32>,
|
pub grab_anchor: bool,
|
||||||
pub grab_all: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@@ -327,7 +326,7 @@ where
|
|||||||
let mut pointer = &mut app.input_state.pointers[idx];
|
let mut pointer = &mut app.input_state.pointers[idx];
|
||||||
if let Some(grab_data) = pointer.interaction.grabbed {
|
if let Some(grab_data) = pointer.interaction.grabbed {
|
||||||
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
|
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
|
||||||
Pointer::handle_grabbed(idx, grabbed, app);
|
handle_grabbed(idx, grabbed, app);
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Grabbed overlay {:?} does not exist", grab_data.grabbed_id);
|
log::warn!("Grabbed overlay {:?} does not exist", grab_data.grabbed_id);
|
||||||
pointer.interaction.grabbed = None;
|
pointer.interaction.grabbed = None;
|
||||||
@@ -356,6 +355,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
overlays.edit_overlay(hit.overlay, true, app);
|
overlays.edit_overlay(hit.overlay, true, app);
|
||||||
|
let edit_mode = overlays.get_edit_mode();
|
||||||
|
|
||||||
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
||||||
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
||||||
return (0.0, None); // no hit
|
return (0.0, None); // no hit
|
||||||
@@ -384,7 +385,7 @@ where
|
|||||||
&mut app.hid_provider.keyboard_focus,
|
&mut app.hid_provider.keyboard_focus,
|
||||||
hovered.config.keyboard_focus,
|
hovered.config.keyboard_focus,
|
||||||
);
|
);
|
||||||
pointer.start_grab(hit.overlay, hovered_state, &mut app.tasks);
|
start_grab(idx, hit.overlay, hovered_state, app, edit_mode);
|
||||||
log::debug!("Hand {}: grabbed {}", hit.pointer, hovered.config.name);
|
log::debug!("Hand {}: grabbed {}", hit.pointer, hovered.config.name);
|
||||||
return (
|
return (
|
||||||
hit.dist,
|
hit.dist,
|
||||||
@@ -581,84 +582,128 @@ where
|
|||||||
(None, None)
|
(None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pointer {
|
fn start_grab(
|
||||||
fn start_grab(
|
idx: usize,
|
||||||
&mut self,
|
|
||||||
id: OverlayID,
|
id: OverlayID,
|
||||||
state: &mut OverlayWindowState,
|
state: &mut OverlayWindowState,
|
||||||
tasks: &mut TaskContainer,
|
app: &mut AppState,
|
||||||
) {
|
edit_mode: bool,
|
||||||
let offset = self
|
) {
|
||||||
|
let pointer = &mut app.input_state.pointers[idx];
|
||||||
|
|
||||||
|
// Grab anchor if:
|
||||||
|
// - grabbed overlay is Anchored
|
||||||
|
// - not in editmode
|
||||||
|
// - grabbing with one hand. (grabbing with the 2nd hand will grab the individual overlay instead)
|
||||||
|
let grab_anchor =
|
||||||
|
!edit_mode && !app.anchor_grabbed && matches!(state.positioning, Positioning::Anchored);
|
||||||
|
|
||||||
|
let relative_grab_point = if grab_anchor {
|
||||||
|
app.anchor.translation
|
||||||
|
} else {
|
||||||
|
state.transform.translation
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = pointer
|
||||||
.pose
|
.pose
|
||||||
.inverse()
|
.inverse()
|
||||||
.transform_point3a(state.transform.translation);
|
.transform_point3a(relative_grab_point);
|
||||||
|
|
||||||
self.interaction.grabbed = Some(GrabData {
|
app.anchor_grabbed = grab_anchor;
|
||||||
|
|
||||||
|
pointer.interaction.grabbed = Some(GrabData {
|
||||||
offset,
|
offset,
|
||||||
grabbed_id: id,
|
grabbed_id: id,
|
||||||
old_curvature: state.curvature,
|
grab_anchor,
|
||||||
grab_all: matches!(self.interaction.mode, PointerMode::Right),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
state.positioning = match state.positioning {
|
state.positioning = match state.positioning {
|
||||||
Positioning::FollowHand { hand, lerp } => Positioning::FollowHandPaused { hand, lerp },
|
Positioning::FollowHand { hand, lerp } => Positioning::FollowHandPaused { hand, lerp },
|
||||||
Positioning::FollowHead { lerp } => Positioning::FollowHeadPaused { lerp },
|
Positioning::FollowHead { lerp } => Positioning::FollowHeadPaused { lerp },
|
||||||
|
Positioning::Anchored if !grab_anchor => Positioning::AnchoredPaused,
|
||||||
x => x,
|
x => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Show anchor
|
// Show anchor
|
||||||
tasks.enqueue(TaskType::Overlay(
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
OverlaySelector::Name(ANCHOR_NAME.clone()),
|
OverlaySelector::Name(ANCHOR_NAME.clone()),
|
||||||
Box::new(|app, o| {
|
Box::new(|app, o| {
|
||||||
o.activate_static(app.anchor * Affine3A::from_scale(Vec3::ONE * 0.1));
|
o.activate(app);
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scale(transform: &mut Affine3A, scroll_y: f32) {
|
||||||
|
let cur_scale = transform.x_axis.length();
|
||||||
|
if cur_scale < 0.1 && scroll_y > 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if cur_scale > 20. && scroll_y < 0.0 {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_grabbed<O>(idx: usize, overlay: &mut OverlayWindowData<O>, app: &mut AppState)
|
transform.matrix3 = transform
|
||||||
where
|
.matrix3
|
||||||
|
.mul_scalar(0.025f32.mul_add(-scroll_y, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_grabbed<O>(idx: usize, overlay: &mut OverlayWindowData<O>, app: &mut AppState)
|
||||||
|
where
|
||||||
O: Default,
|
O: Default,
|
||||||
{
|
{
|
||||||
|
let pointer = &mut app.input_state.pointers[idx];
|
||||||
|
let Some(grab_data) = pointer.interaction.grabbed.as_mut() else {
|
||||||
|
log::error!("Grabbed overlay does not exist");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let grab_anchor = grab_data.grab_anchor;
|
||||||
|
|
||||||
let Some(overlay_state) = overlay.config.active_state.as_mut() else {
|
let Some(overlay_state) = overlay.config.active_state.as_mut() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let pointer = &mut app.input_state.pointers[idx];
|
|
||||||
if pointer.now.grab {
|
if pointer.now.grab {
|
||||||
if let Some(grab_data) = pointer.interaction.grabbed.as_mut() {
|
if grab_anchor {
|
||||||
if pointer.now.click {
|
if pointer.now.click {
|
||||||
pointer.interaction.mode = PointerMode::Special;
|
pointer.interaction.mode = PointerMode::Special;
|
||||||
let cur_scale = overlay_state.transform.x_axis.length();
|
handle_scale(&mut app.anchor, pointer.now.scroll_y);
|
||||||
if cur_scale < 0.1 && pointer.now.scroll_y > 0.0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if cur_scale > 20. && pointer.now.scroll_y < 0.0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
overlay_state.transform.matrix3 = overlay_state
|
|
||||||
.transform
|
|
||||||
.matrix3
|
|
||||||
.mul_scalar(0.025f32.mul_add(-pointer.now.scroll_y, 1.0));
|
|
||||||
} else if app.session.config.allow_sliding && pointer.now.scroll_y.is_finite() {
|
} else if app.session.config.allow_sliding && pointer.now.scroll_y.is_finite() {
|
||||||
|
// single grab push/pull
|
||||||
grab_data.offset.z -= pointer.now.scroll_y * 0.05;
|
grab_data.offset.z -= pointer.now.scroll_y * 0.05;
|
||||||
}
|
}
|
||||||
overlay_state.transform.translation =
|
app.anchor.translation = pointer.pose.transform_point3a(grab_data.offset);
|
||||||
pointer.pose.transform_point3a(grab_data.offset);
|
realign(&mut app.anchor, &app.input_state.hmd);
|
||||||
overlay.config.realign(&app.input_state.hmd);
|
|
||||||
} else {
|
} else {
|
||||||
log::error!("Grabbed overlay does not exist");
|
// single grab resize
|
||||||
pointer.interaction.grabbed = None;
|
if pointer.now.click {
|
||||||
|
pointer.interaction.mode = PointerMode::Special;
|
||||||
|
handle_scale(&mut overlay_state.transform, pointer.now.scroll_y);
|
||||||
|
} else if app.session.config.allow_sliding && pointer.now.scroll_y.is_finite() {
|
||||||
|
// single grab push/pull
|
||||||
|
grab_data.offset.z -= pointer.now.scroll_y * 0.05;
|
||||||
|
}
|
||||||
|
overlay_state.transform.translation = pointer.pose.transform_point3a(grab_data.offset);
|
||||||
|
realign(&mut overlay_state.transform, &app.input_state.hmd);
|
||||||
|
overlay.config.dirty = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// not now.grab
|
||||||
|
pointer.interaction.grabbed = None;
|
||||||
|
if grab_anchor {
|
||||||
|
app.anchor_grabbed = false;
|
||||||
|
} else {
|
||||||
|
// single grab released
|
||||||
overlay_state.positioning = match overlay_state.positioning {
|
overlay_state.positioning = match overlay_state.positioning {
|
||||||
Positioning::FollowHandPaused { hand, lerp } => {
|
Positioning::FollowHandPaused { hand, lerp } => {
|
||||||
Positioning::FollowHand { hand, lerp }
|
Positioning::FollowHand { hand, lerp }
|
||||||
}
|
}
|
||||||
Positioning::FollowHeadPaused { lerp } => Positioning::FollowHead { lerp },
|
Positioning::FollowHeadPaused { lerp } => Positioning::FollowHead { lerp },
|
||||||
|
Positioning::AnchoredPaused => Positioning::Anchored,
|
||||||
x => x,
|
x => x,
|
||||||
};
|
};
|
||||||
pointer.interaction.grabbed = None;
|
|
||||||
overlay_state.save_transform(app);
|
overlay_state.save_transform(app);
|
||||||
|
}
|
||||||
|
|
||||||
// Hide anchor
|
// Hide anchor
|
||||||
app.tasks.enqueue(TaskType::Overlay(
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
@@ -669,7 +714,6 @@ impl Pointer {
|
|||||||
));
|
));
|
||||||
log::debug!("Hand {}: dropped {}", idx, overlay.config.name);
|
log::debug!("Hand {}: dropped {}", idx, overlay.config.name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ray_test(
|
fn ray_test(
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use std::sync::{Arc, LazyLock};
|
|||||||
|
|
||||||
use crate::gui::panel::GuiPanel;
|
use crate::gui::panel::GuiPanel;
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
use crate::windowing::Z_ORDER_ANCHOR;
|
|
||||||
use crate::windowing::window::{OverlayWindowConfig, OverlayWindowState, Positioning};
|
use crate::windowing::window::{OverlayWindowConfig, OverlayWindowState, Positioning};
|
||||||
|
use crate::windowing::Z_ORDER_ANCHOR;
|
||||||
|
|
||||||
pub static ANCHOR_NAME: LazyLock<Arc<str>> = LazyLock::new(|| Arc::from("anchor"));
|
pub static ANCHOR_NAME: LazyLock<Arc<str>> = LazyLock::new(|| Arc::from("anchor"));
|
||||||
|
|
||||||
@@ -18,11 +18,11 @@ pub fn create_anchor(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig>
|
|||||||
default_state: OverlayWindowState {
|
default_state: OverlayWindowState {
|
||||||
interactable: false,
|
interactable: false,
|
||||||
grabbable: false,
|
grabbable: false,
|
||||||
positioning: Positioning::Static,
|
positioning: Positioning::Anchored,
|
||||||
transform: Affine3A::from_scale_rotation_translation(
|
transform: Affine3A::from_scale_rotation_translation(
|
||||||
Vec3::ONE * 0.1,
|
Vec3::ONE * 0.1,
|
||||||
Quat::IDENTITY,
|
Quat::IDENTITY,
|
||||||
Vec3::NEG_Z * 0.5,
|
Vec3::ZERO, // Vec3::NEG_Z * 0.5,
|
||||||
),
|
),
|
||||||
..OverlayWindowState::default()
|
..OverlayWindowState::default()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ use wgui::{
|
|||||||
use crate::{backend::task::TaskType, windowing::OverlaySelector};
|
use crate::{backend::task::TaskType, windowing::OverlaySelector};
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{input::HoverResult, task::TaskContainer},
|
backend::{input::HoverResult, task::TaskContainer},
|
||||||
gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS},
|
gui::panel::{button::BUTTON_EVENTS, GuiPanel, NewGuiPanelParams, OnCustomAttribFunc},
|
||||||
overlays::edit::{
|
overlays::edit::{
|
||||||
lock::InteractLockHandler, pos::PositioningHandler, tab::ButtonPaneTabSwitcher,
|
lock::InteractLockHandler, pos::PositioningHandler, tab::ButtonPaneTabSwitcher,
|
||||||
},
|
},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::WheelDelta,
|
subsystem::hid::WheelDelta,
|
||||||
windowing::{
|
windowing::{
|
||||||
OverlayID,
|
|
||||||
backend::{DummyBackend, OverlayBackend, RenderResources, ShouldRender},
|
backend::{DummyBackend, OverlayBackend, RenderResources, ShouldRender},
|
||||||
window::OverlayWindowConfig,
|
window::OverlayWindowConfig,
|
||||||
|
OverlayID,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ fn key_to_pos(key: &str) -> Positioning {
|
|||||||
const fn pos_to_key(pos: Positioning) -> &'static str {
|
const fn pos_to_key(pos: Positioning) -> &'static str {
|
||||||
match pos {
|
match pos {
|
||||||
Positioning::Static => "static",
|
Positioning::Static => "static",
|
||||||
Positioning::Anchored => "anchored",
|
Positioning::Anchored | Positioning::AnchoredPaused => "anchored",
|
||||||
Positioning::Floating => "floating",
|
Positioning::Floating => "floating",
|
||||||
Positioning::FollowHead { .. } | Positioning::FollowHeadPaused { .. } => "hmd",
|
Positioning::FollowHead { .. } | Positioning::FollowHeadPaused { .. } => "hmd",
|
||||||
Positioning::FollowHand {
|
Positioning::FollowHand {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ pub struct AppState {
|
|||||||
pub input_state: InputState,
|
pub input_state: InputState,
|
||||||
pub screens: SmallVec<[ScreenMeta; 8]>,
|
pub screens: SmallVec<[ScreenMeta; 8]>,
|
||||||
pub anchor: Affine3A,
|
pub anchor: Affine3A,
|
||||||
|
pub anchor_grabbed: bool,
|
||||||
pub toast_sound: &'static [u8],
|
pub toast_sound: &'static [u8],
|
||||||
|
|
||||||
pub wgui_globals: WguiGlobals,
|
pub wgui_globals: WguiGlobals,
|
||||||
@@ -94,6 +95,7 @@ impl AppState {
|
|||||||
input_state: InputState::new(),
|
input_state: InputState::new(),
|
||||||
screens: smallvec![],
|
screens: smallvec![],
|
||||||
anchor: Affine3A::IDENTITY,
|
anchor: Affine3A::IDENTITY,
|
||||||
|
anchor_grabbed: false,
|
||||||
toast_sound: toast_sound_wav,
|
toast_sound: toast_sound_wav,
|
||||||
wgui_globals: WguiGlobals::new(
|
wgui_globals: WguiGlobals::new(
|
||||||
Box::new(gui::asset::GuiAsset {}),
|
Box::new(gui::asset::GuiAsset {}),
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ pub enum Positioning {
|
|||||||
/// Stays in place, recenters relative to HMD
|
/// Stays in place, recenters relative to HMD
|
||||||
#[default]
|
#[default]
|
||||||
Floating,
|
Floating,
|
||||||
/// Stays in place, recenters relative to anchor
|
/// Stays in place, recenters relative to anchor. Follows anchor during anchor grab.
|
||||||
Anchored,
|
Anchored,
|
||||||
|
/// Same as anchor but paused due to interaction
|
||||||
|
AnchoredPaused,
|
||||||
/// Stays in place, no recentering
|
/// Stays in place, no recentering
|
||||||
Static,
|
Static,
|
||||||
/// Following HMD
|
/// Following HMD
|
||||||
@@ -151,15 +153,17 @@ impl OverlayWindowConfig {
|
|||||||
.saved_transform
|
.saved_transform
|
||||||
.unwrap_or(self.default_state.transform);
|
.unwrap_or(self.default_state.transform);
|
||||||
|
|
||||||
let (target_transform, lerp) = match state.positioning {
|
let (parent_transform, lerp) = match state.positioning {
|
||||||
Positioning::FollowHead { lerp } => (app.input_state.hmd * cur_transform, lerp),
|
Positioning::FollowHead { lerp } => (app.input_state.hmd, lerp),
|
||||||
Positioning::FollowHand { hand, lerp } => (
|
Positioning::FollowHand { hand, lerp } => {
|
||||||
app.input_state.pointers[hand as usize].pose * cur_transform,
|
(app.input_state.pointers[hand as usize].pose, lerp)
|
||||||
lerp,
|
}
|
||||||
),
|
Positioning::Anchored => (app.anchor, 1.0),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let target_transform = parent_transform * cur_transform;
|
||||||
|
|
||||||
state.transform = match lerp {
|
state.transform = match lerp {
|
||||||
1.0 => target_transform,
|
1.0 => target_transform,
|
||||||
lerp => {
|
lerp => {
|
||||||
@@ -201,7 +205,7 @@ impl OverlayWindowConfig {
|
|||||||
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
|
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
|
||||||
app.input_state.pointers[hand as usize].pose
|
app.input_state.pointers[hand as usize].pose
|
||||||
}
|
}
|
||||||
Positioning::Anchored => app.anchor,
|
Positioning::Anchored | Positioning::AnchoredPaused => app.anchor,
|
||||||
Positioning::Static => return,
|
Positioning::Static => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -212,17 +216,14 @@ impl OverlayWindowConfig {
|
|||||||
state.transform = parent_transform * cur_transform;
|
state.transform = parent_transform * cur_transform;
|
||||||
|
|
||||||
if state.grabbable && hard_reset {
|
if state.grabbable && hard_reset {
|
||||||
self.realign(&app.input_state.hmd);
|
realign(&mut state.transform, &app.input_state.hmd);
|
||||||
}
|
}
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn realign(&mut self, hmd: &Affine3A) {
|
pub fn realign(transform: &mut Affine3A, hmd: &Affine3A) {
|
||||||
let Some(state) = self.active_state.as_mut() else {
|
let to_hmd = hmd.translation - transform.translation;
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_hmd = hmd.translation - state.transform.translation;
|
|
||||||
let up_dir: Vec3A;
|
let up_dir: Vec3A;
|
||||||
|
|
||||||
if hmd.x_axis.dot(Vec3A::Y).abs() > 0.2 {
|
if hmd.x_axis.dot(Vec3A::Y).abs() > 0.2 {
|
||||||
@@ -231,36 +232,33 @@ impl OverlayWindowConfig {
|
|||||||
} else {
|
} else {
|
||||||
let dot = to_hmd.normalize().dot(hmd.z_axis);
|
let dot = to_hmd.normalize().dot(hmd.z_axis);
|
||||||
let z_dist = to_hmd.length();
|
let z_dist = to_hmd.length();
|
||||||
let y_dist = (state.transform.translation.y - hmd.translation.y).abs();
|
let y_dist = (transform.translation.y - hmd.translation.y).abs();
|
||||||
let x_angle = (y_dist / z_dist).asin();
|
let x_angle = (y_dist / z_dist).asin();
|
||||||
|
|
||||||
if dot < -f32::EPSILON {
|
if dot < -f32::EPSILON {
|
||||||
// facing down
|
// facing down
|
||||||
let up_point = hmd.translation + z_dist / x_angle.cos() * Vec3A::Y;
|
let up_point = hmd.translation + z_dist / x_angle.cos() * Vec3A::Y;
|
||||||
up_dir = (up_point - state.transform.translation).normalize();
|
up_dir = (up_point - transform.translation).normalize();
|
||||||
} else if dot > f32::EPSILON {
|
} else if dot > f32::EPSILON {
|
||||||
// facing up
|
// facing up
|
||||||
let dn_point = hmd.translation + z_dist / x_angle.cos() * Vec3A::NEG_Y;
|
let dn_point = hmd.translation + z_dist / x_angle.cos() * Vec3A::NEG_Y;
|
||||||
up_dir = (state.transform.translation - dn_point).normalize();
|
up_dir = (transform.translation - dn_point).normalize();
|
||||||
} else {
|
} else {
|
||||||
// perfectly upright
|
// perfectly upright
|
||||||
up_dir = Vec3A::Y;
|
up_dir = Vec3A::Y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let scale = state.transform.x_axis.length();
|
let scale = transform.x_axis.length();
|
||||||
|
|
||||||
let col_z = (state.transform.translation - hmd.translation).normalize();
|
let col_z = (transform.translation - hmd.translation).normalize();
|
||||||
let col_y = up_dir;
|
let col_y = up_dir;
|
||||||
let col_x = col_y.cross(col_z);
|
let col_x = col_y.cross(col_z);
|
||||||
let col_y = col_z.cross(col_x).normalize();
|
let col_y = col_z.cross(col_x).normalize();
|
||||||
let col_x = col_x.normalize();
|
let col_x = col_x.normalize();
|
||||||
|
|
||||||
let rot = Mat3A::from_quat(Quat::from_axis_angle(Vec3::Y, PI));
|
let rot = Mat3A::from_quat(Quat::from_axis_angle(Vec3::Y, PI));
|
||||||
state.transform.matrix3 = Mat3A::from_cols(col_x, col_y, col_z).mul_scalar(scale) * rot;
|
transform.matrix3 = Mat3A::from_cols(col_x, col_y, col_z).mul_scalar(scale) * rot;
|
||||||
|
|
||||||
self.dirty = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contains the window state for a given set
|
// Contains the window state for a given set
|
||||||
@@ -302,7 +300,9 @@ impl OverlayWindowState {
|
|||||||
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
|
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
|
||||||
app.input_state.pointers[hand as usize].pose
|
app.input_state.pointers[hand as usize].pose
|
||||||
}
|
}
|
||||||
Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y),
|
Positioning::Anchored | Positioning::AnchoredPaused => {
|
||||||
|
snap_upright(app.anchor, Vec3A::Y)
|
||||||
|
}
|
||||||
Positioning::Static => return false,
|
Positioning::Static => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user