mirror of https://github.com/wayvr-org/wayvr.git
wayvr: Space gravity (wip)
This commit is contained in:
parent
1591466a8d
commit
c7037f8941
|
|
@ -103,6 +103,9 @@
|
||||||
"SETS_ON_WATCH": "Sets on watch",
|
"SETS_ON_WATCH": "Sets on watch",
|
||||||
"SKYBOX": "Skybox",
|
"SKYBOX": "Skybox",
|
||||||
"SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.",
|
"SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.",
|
||||||
|
"SPACE_DRAG_FLING_STRENGTH": "Fling strength",
|
||||||
|
"SPACE_DRAG_DAMPING": "Damping",
|
||||||
|
"SPACE_DRAG_GRAVITY": "Gravity",
|
||||||
"SPACE_DRAG_MULTIPLIER": "Space drag multiplier",
|
"SPACE_DRAG_MULTIPLIER": "Space drag multiplier",
|
||||||
"SPACE_DRAG_UNLOCKED": "Allow space drag on all axes",
|
"SPACE_DRAG_UNLOCKED": "Allow space drag on all axes",
|
||||||
"SPACE_ROTATE_UNLOCKED": "Allow space rotate on all axes",
|
"SPACE_ROTATE_UNLOCKED": "Allow space rotate on all axes",
|
||||||
|
|
|
||||||
|
|
@ -275,6 +275,9 @@ enum SettingType {
|
||||||
ScreenRenderDown,
|
ScreenRenderDown,
|
||||||
ScrollSpeed,
|
ScrollSpeed,
|
||||||
SetsOnWatch,
|
SetsOnWatch,
|
||||||
|
SpaceDragFlingStrength,
|
||||||
|
SpaceDragDamping,
|
||||||
|
SpaceDragGravity,
|
||||||
SpaceDragMultiplier,
|
SpaceDragMultiplier,
|
||||||
SpaceDragUnlocked,
|
SpaceDragUnlocked,
|
||||||
SpaceRotateUnlocked,
|
SpaceRotateUnlocked,
|
||||||
|
|
@ -339,6 +342,9 @@ impl SettingType {
|
||||||
Self::LongPressDuration => &mut config.long_press_duration,
|
Self::LongPressDuration => &mut config.long_press_duration,
|
||||||
Self::XrClickSensitivity => &mut config.xr_click_sensitivity,
|
Self::XrClickSensitivity => &mut config.xr_click_sensitivity,
|
||||||
Self::XrClickSensitivityRelease => &mut config.xr_click_sensitivity_release,
|
Self::XrClickSensitivityRelease => &mut config.xr_click_sensitivity_release,
|
||||||
|
Self::SpaceDragFlingStrength => &mut config.space_drag_fling_strength,
|
||||||
|
Self::SpaceDragDamping => &mut config.space_drag_damping,
|
||||||
|
Self::SpaceDragGravity => &mut config.space_drag_gravity,
|
||||||
Self::SpaceDragMultiplier => &mut config.space_drag_multiplier,
|
Self::SpaceDragMultiplier => &mut config.space_drag_multiplier,
|
||||||
Self::PointerLerpFactor => &mut config.pointer_lerp_factor,
|
Self::PointerLerpFactor => &mut config.pointer_lerp_factor,
|
||||||
Self::GridOpacity => &mut config.grid_opacity,
|
Self::GridOpacity => &mut config.grid_opacity,
|
||||||
|
|
@ -436,6 +442,9 @@ impl SettingType {
|
||||||
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
||||||
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
||||||
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
||||||
|
Self::SpaceDragFlingStrength => Ok("APP_SETTINGS.SPACE_DRAG_FLING_STRENGTH"),
|
||||||
|
Self::SpaceDragDamping => Ok("APP_SETTINGS.SPACE_DRAG_DAMPING"),
|
||||||
|
Self::SpaceDragGravity => Ok("APP_SETTINGS.SPACE_DRAG_GRAVITY"),
|
||||||
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
||||||
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
||||||
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::tab::settings::{
|
use crate::tab::settings::{
|
||||||
macros::{options_category, options_checkbox, options_range_f32, options_slider_f32},
|
|
||||||
SettingType, SettingsMountParams, SettingsTab,
|
SettingType, SettingsMountParams, SettingsTab,
|
||||||
|
macros::{options_category, options_checkbox, options_range_f32, options_slider_f32},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct State {}
|
pub struct State {}
|
||||||
|
|
@ -17,6 +17,9 @@ impl State {
|
||||||
// monado or openvr
|
// monado or openvr
|
||||||
options_checkbox(par.mp, c, SettingType::SpaceDragUnlocked)?;
|
options_checkbox(par.mp, c, SettingType::SpaceDragUnlocked)?;
|
||||||
options_slider_f32(par.mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5)?;
|
options_slider_f32(par.mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5)?;
|
||||||
|
options_slider_f32(par.mp, c, SettingType::SpaceDragGravity, 0.0, 10.0, 0.5)?;
|
||||||
|
options_slider_f32(par.mp, c, SettingType::SpaceDragDamping, 0.1, 1.0, 0.01)?;
|
||||||
|
options_slider_f32(par.mp, c, SettingType::SpaceDragFlingStrength, 0.0, 3.0, 0.1)?;
|
||||||
}
|
}
|
||||||
if par.feats.monado {
|
if par.feats.monado {
|
||||||
// openvr can only ever rotate yaw
|
// openvr can only ever rotate yaw
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod playspace_common;
|
||||||
|
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
pub mod openvr;
|
pub mod openvr;
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,12 @@ pub fn openvr_run(
|
||||||
let mut lines = LinePool::new(app.gfx.clone())?;
|
let mut lines = LinePool::new(app.gfx.clone())?;
|
||||||
let pointer_lines = [lines.allocate(), lines.allocate()];
|
let pointer_lines = [lines.allocate(), lines.allocate()];
|
||||||
let mut current_lines = Vec::with_capacity(2);
|
let mut current_lines = Vec::with_capacity(2);
|
||||||
|
let mut last_frame_time = Instant::now();
|
||||||
|
|
||||||
'main_loop: loop {
|
'main_loop: loop {
|
||||||
|
let now = Instant::now();
|
||||||
|
app.delta_time = (now.duration_since(last_frame_time).as_secs_f32()).clamp(0.001, 0.2); // 5 - 1000 fps
|
||||||
|
last_frame_time = now;
|
||||||
let _ = overlay_mgr.wait_frame_sync(frame_timeout);
|
let _ = overlay_mgr.wait_frame_sync(frame_timeout);
|
||||||
|
|
||||||
if !RUNNING.load(Ordering::Relaxed) {
|
if !RUNNING.load(Ordering::Relaxed) {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ pub fn openxr_run(
|
||||||
|
|
||||||
app.monado_state_init();
|
app.monado_state_init();
|
||||||
|
|
||||||
let mut playspace = app.monado_state.as_mut().and_then(|m| {
|
let mut playspace_mover = app.monado_state.as_mut().and_then(|m| {
|
||||||
playspace::PlayspaceMover::new(&mut m.ipc)
|
playspace::PlayspaceMover::new(&mut m.ipc)
|
||||||
.map_err(|e| log::warn!("Will not use Monado playspace mover: {e}"))
|
.map_err(|e| log::warn!("Will not use Monado playspace mover: {e}"))
|
||||||
.ok()
|
.ok()
|
||||||
|
|
@ -155,8 +155,12 @@ pub fn openxr_run(
|
||||||
|
|
||||||
let mut main_session_visible = false;
|
let mut main_session_visible = false;
|
||||||
let mut environment_blend_mode = modes[0];
|
let mut environment_blend_mode = modes[0];
|
||||||
|
let mut last_frame_time = Instant::now();
|
||||||
|
|
||||||
'main_loop: loop {
|
'main_loop: loop {
|
||||||
|
let now = Instant::now();
|
||||||
|
app.delta_time = (now.duration_since(last_frame_time).as_secs_f32()).clamp(0.001, 0.2); // 5 - 1000 fps
|
||||||
|
last_frame_time = now;
|
||||||
let cur_frame = FRAME_COUNTER.fetch_add(1, Ordering::Relaxed);
|
let cur_frame = FRAME_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
if !RUNNING.load(Ordering::Relaxed) {
|
if !RUNNING.load(Ordering::Relaxed) {
|
||||||
|
|
@ -296,8 +300,8 @@ pub fn openxr_run(
|
||||||
.enqueue(TaskType::Overlay(OverlayTask::ToggleDashboard));
|
.enqueue(TaskType::Overlay(OverlayTask::ToggleDashboard));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref mut space_mover) = playspace {
|
if let Some(ref mut playspace_mover) = playspace_mover {
|
||||||
space_mover.update(&mut overlays, &mut app);
|
playspace_mover.update(&mut overlays, &mut app);
|
||||||
}
|
}
|
||||||
|
|
||||||
for o in overlays.values_mut() {
|
for o in overlays.values_mut() {
|
||||||
|
|
@ -481,8 +485,8 @@ pub fn openxr_run(
|
||||||
overlays.handle_task(&mut app, task)?;
|
overlays.handle_task(&mut app, task)?;
|
||||||
}
|
}
|
||||||
TaskType::Playspace(task) => {
|
TaskType::Playspace(task) => {
|
||||||
if let Some(playspace) = playspace.as_mut() {
|
if let Some(playspace_mover) = playspace_mover.as_mut() {
|
||||||
playspace.handle_task(&mut app, task);
|
playspace_mover.handle_task(&mut app, task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TaskType::OpenXR(task) => {
|
TaskType::OpenXR(task) => {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ use libmonado::{MndResult, Monado, Pose, ReferenceSpaceType};
|
||||||
use wgui::log::LogErr;
|
use wgui::log::LogErr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{input::InputState, task::PlayspaceTask},
|
backend::{
|
||||||
|
input::InputState,
|
||||||
|
playspace_common::{SpaceGravity, SpaceGravityUpdateParams},
|
||||||
|
task::PlayspaceTask,
|
||||||
|
},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
windowing::manager::OverlayWindowManager,
|
windowing::manager::OverlayWindowManager,
|
||||||
};
|
};
|
||||||
|
|
@ -19,6 +23,7 @@ struct MoverData<T> {
|
||||||
pub(super) struct PlayspaceMover {
|
pub(super) struct PlayspaceMover {
|
||||||
drag: Option<MoverData<Vec3A>>,
|
drag: Option<MoverData<Vec3A>>,
|
||||||
rotate: Option<MoverData<Quat>>,
|
rotate: Option<MoverData<Quat>>,
|
||||||
|
gravity: SpaceGravity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayspaceMover {
|
impl PlayspaceMover {
|
||||||
|
|
@ -35,6 +40,7 @@ impl PlayspaceMover {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
drag: None,
|
drag: None,
|
||||||
rotate: None,
|
rotate: None,
|
||||||
|
gravity: SpaceGravity::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,21 +146,27 @@ impl PlayspaceMover {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut data) = self.drag.take() {
|
if let Some(mut data) = self.drag.take() {
|
||||||
let pointer = &app.input_state.pointers[data.hand];
|
|
||||||
if !pointer.now.space_drag {
|
|
||||||
log::info!("End space drag");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_hand = data
|
let new_hand = data
|
||||||
.pose
|
.pose
|
||||||
.transform_point3a(app.input_state.pointers[data.hand].raw_pose.translation);
|
.transform_point3a(app.input_state.pointers[data.hand].raw_pose.translation);
|
||||||
|
|
||||||
let relative_pos = if app.session.config.space_drag_unlocked {
|
let relative_pos = if app.session.config.space_drag_unlocked {
|
||||||
new_hand - data.hand_pose
|
new_hand - data.hand_pose
|
||||||
} else {
|
} else {
|
||||||
vec3a(0., new_hand.y - data.hand_pose.y, 0.)
|
vec3a(0., new_hand.y - data.hand_pose.y, 0.)
|
||||||
} * app.session.config.space_drag_multiplier;
|
} * app.session.config.space_drag_multiplier;
|
||||||
|
let pointer = &app.input_state.pointers[data.hand];
|
||||||
|
|
||||||
|
if !pointer.now.space_drag {
|
||||||
|
self.gravity.mark_end_drag(
|
||||||
|
&app.session.config,
|
||||||
|
relative_pos,
|
||||||
|
data.pose.translation,
|
||||||
|
app.delta_time,
|
||||||
|
);
|
||||||
|
|
||||||
|
log::info!("End space drag");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if relative_pos.length_squared() > 1000.0 {
|
if relative_pos.length_squared() > 1000.0 {
|
||||||
log::warn!("Space drag too fast, ignoring");
|
log::warn!("Space drag too fast, ignoring");
|
||||||
|
|
@ -207,6 +219,17 @@ impl PlayspaceMover {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(playspace_pos) = self.gravity.update(SpaceGravityUpdateParams {
|
||||||
|
dt: app.delta_time,
|
||||||
|
dragging: self.drag.is_some(),
|
||||||
|
config: &app.session.config,
|
||||||
|
}) {
|
||||||
|
apply_offset(
|
||||||
|
Affine3A::from_translation(playspace_pos.into()),
|
||||||
|
&mut monado.ipc,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recenter(&mut self, input: &InputState, monado: &mut Monado) {
|
pub fn recenter(&mut self, input: &InputState, monado: &mut Monado) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
use glam::Vec3A;
|
||||||
|
use wlx_common::config::GeneralConfig;
|
||||||
|
|
||||||
|
pub struct SpaceGravityUpdateParams<'a> {
|
||||||
|
pub dt: f32,
|
||||||
|
pub dragging: bool,
|
||||||
|
pub config: &'a GeneralConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SpaceGravity {
|
||||||
|
velocity: Vec3A,
|
||||||
|
space_pos: Vec3A,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpaceGravity {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
velocity: Vec3A::default(),
|
||||||
|
space_pos: Vec3A::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_end_drag(
|
||||||
|
&mut self,
|
||||||
|
config: &GeneralConfig,
|
||||||
|
hand_pos_diff: Vec3A,
|
||||||
|
space_pos: Vec3A,
|
||||||
|
dt: f32,
|
||||||
|
) {
|
||||||
|
self.velocity = hand_pos_diff * config.space_drag_fling_strength / dt;
|
||||||
|
self.space_pos = space_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, par: SpaceGravityUpdateParams) -> Option<Vec3A> {
|
||||||
|
if !par.dragging {
|
||||||
|
self.velocity.y += par.config.space_drag_gravity * par.dt;
|
||||||
|
// terminal velocity
|
||||||
|
self.velocity.y = self.velocity.y.min(200.0);
|
||||||
|
|
||||||
|
self.velocity *= (par.config.space_drag_damping).powf(par.dt * 10.0);
|
||||||
|
self.space_pos += self.velocity * par.dt;
|
||||||
|
|
||||||
|
self.space_pos.y = self.space_pos.y.min(0.0);
|
||||||
|
|
||||||
|
if self.velocity.length_squared() > 0.00003 {
|
||||||
|
// log::info!("velocity {}", self.velocity);
|
||||||
|
return Some(self.space_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -166,6 +166,9 @@ pub struct AutoSettings {
|
||||||
pub pointer_lerp_factor: f32,
|
pub pointer_lerp_factor: f32,
|
||||||
pub space_drag_unlocked: bool,
|
pub space_drag_unlocked: bool,
|
||||||
pub space_rotate_unlocked: bool,
|
pub space_rotate_unlocked: bool,
|
||||||
|
pub space_drag_gravity: f32,
|
||||||
|
pub space_drag_damping: f32,
|
||||||
|
pub space_drag_fling_strength: f32,
|
||||||
pub clock_12h: bool,
|
pub clock_12h: bool,
|
||||||
pub hide_username: bool,
|
pub hide_username: bool,
|
||||||
pub opaque_background: bool,
|
pub opaque_background: bool,
|
||||||
|
|
@ -221,6 +224,9 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
||||||
pointer_lerp_factor: config.pointer_lerp_factor,
|
pointer_lerp_factor: config.pointer_lerp_factor,
|
||||||
space_drag_unlocked: config.space_drag_unlocked,
|
space_drag_unlocked: config.space_drag_unlocked,
|
||||||
space_rotate_unlocked: config.space_rotate_unlocked,
|
space_rotate_unlocked: config.space_rotate_unlocked,
|
||||||
|
space_drag_gravity: config.space_drag_gravity,
|
||||||
|
space_drag_damping: config.space_drag_damping,
|
||||||
|
space_drag_fling_strength: config.space_drag_fling_strength,
|
||||||
clock_12h: config.clock_12h,
|
clock_12h: config.clock_12h,
|
||||||
hide_username: config.hide_username,
|
hide_username: config.hide_username,
|
||||||
opaque_background: config.opaque_background,
|
opaque_background: config.opaque_background,
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,15 @@
|
||||||
## can rotate in any axis. Imagine horizon mode².
|
## can rotate in any axis. Imagine horizon mode².
|
||||||
#space_rotate_unlocked: false
|
#space_rotate_unlocked: false
|
||||||
|
|
||||||
|
## Space gravity: downward acceleration speed
|
||||||
|
#space_drag_gravity: 2.0
|
||||||
|
|
||||||
|
## Space gravity: velocity damping (0.98 = gentle slowdown, 0.5 = heavy drag)
|
||||||
|
#space_drag_damping: 0.98
|
||||||
|
|
||||||
|
## Space gravity: multiplier for "throwing" yourself via space drag momentum
|
||||||
|
#space_drag_fling_strength: 1.0
|
||||||
|
|
||||||
## Monado/WiVRn only. Use passthrough camera if the headset supports it.
|
## Monado/WiVRn only. Use passthrough camera if the headset supports it.
|
||||||
## If disabled, the skybox will be shown.
|
## If disabled, the skybox will be shown.
|
||||||
#use_passthrough: true
|
#use_passthrough: true
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ pub struct AppState {
|
||||||
|
|
||||||
#[cfg(feature = "openxr")]
|
#[cfg(feature = "openxr")]
|
||||||
pub monado_state: Option<backend::openxr::monado_state::MonadoState>,
|
pub monado_state: Option<backend::openxr::monado_state::MonadoState>,
|
||||||
|
|
||||||
|
pub delta_time: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
|
@ -188,6 +190,8 @@ impl AppState {
|
||||||
|
|
||||||
#[cfg(feature = "openxr")]
|
#[cfg(feature = "openxr")]
|
||||||
monado_state: None,
|
monado_state: None,
|
||||||
|
|
||||||
|
delta_time: 1.0 / 120.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(error_toast) = hid_error {
|
if let Some(error_toast) = hid_error {
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,10 @@ const fn def_point3() -> f32 {
|
||||||
0.3
|
0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn def_point98() -> f32 {
|
||||||
|
0.98
|
||||||
|
}
|
||||||
|
|
||||||
const fn def_osc_port() -> u16 {
|
const fn def_osc_port() -> u16 {
|
||||||
9000
|
9000
|
||||||
}
|
}
|
||||||
|
|
@ -336,6 +340,15 @@ pub struct GeneralConfig {
|
||||||
#[serde(default = "def_false")]
|
#[serde(default = "def_false")]
|
||||||
pub space_rotate_unlocked: bool,
|
pub space_rotate_unlocked: bool,
|
||||||
|
|
||||||
|
#[serde(default = "def_one")]
|
||||||
|
pub space_drag_gravity: f32,
|
||||||
|
|
||||||
|
#[serde(default = "def_point98")]
|
||||||
|
pub space_drag_damping: f32,
|
||||||
|
|
||||||
|
#[serde(default = "def_one")]
|
||||||
|
pub space_drag_fling_strength: f32,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub alt_click_down: Vec<String>,
|
pub alt_click_down: Vec<String>,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue