diff --git a/Cargo.lock b/Cargo.lock index 5bca4f79fd17..01e99beb5d00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6471,7 +6471,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#3f754a11eb3e9771f6020ec5a25ae94ed1e11f07" +source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" dependencies = [ "android_injected_glue", "bindgen", @@ -6494,7 +6494,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#3f754a11eb3e9771f6020ec5a25ae94ed1e11f07" +source = "git+https://github.com/servo/webxr#0d8d2affc4da259b88d251ab49c0bbcbe96acf4d" dependencies = [ "euclid", "ipc-channel", diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index fbb6890baf3f..2381d4864d90 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -80,8 +80,8 @@ impl XRFrameMethods for XRFrame { return Err(Error::InvalidState); } - let pose = if let Some(pose) = reference.get_viewer_pose(&self.data) { - pose + let to_base = if let Some(to_base) = reference.get_base_transform(&self.data) { + to_base } else { return Ok(None); }; @@ -93,7 +93,7 @@ impl XRFrameMethods for XRFrame { Ok(Some(XRViewerPose::new( &self.global(), &self.session, - pose, + to_base, viewer_pose, ))) } diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index 0936b33fe6dc..fb4f890e766a 100644 --- a/components/script/dom/xrreferencespace.rs +++ b/components/script/dom/xrreferencespace.rs @@ -9,11 +9,11 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrrigidtransform::XRRigidTransform; -use crate::dom::xrsession::{cast_transform, ApiPose, ApiViewerPose, XRSession}; +use crate::dom::xrsession::{cast_transform, ApiPose, BaseTransform, XRSession}; use crate::dom::xrspace::XRSpace; use dom_struct::dom_struct; use euclid::RigidTransform3D; -use webxr_api::{BaseSpace, Frame, Space}; +use webxr_api::{self, Frame, Space}; #[dom_struct] pub struct XRReferenceSpace { @@ -60,9 +60,9 @@ impl XRReferenceSpace { pub fn space(&self) -> Space { let base = match self.ty { - XRReferenceSpaceType::Local => BaseSpace::Local, - XRReferenceSpaceType::Viewer => BaseSpace::Viewer, - XRReferenceSpaceType::Local_floor => BaseSpace::Floor, + XRReferenceSpaceType::Local => webxr_api::BaseSpace::Local, + XRReferenceSpaceType::Viewer => webxr_api::BaseSpace::Viewer, + XRReferenceSpaceType::Local_floor => webxr_api::BaseSpace::Floor, _ => panic!("unsupported reference space found"), }; let offset = self.offset.transform(); @@ -85,58 +85,13 @@ impl XRReferenceSpaceMethods for XRReferenceSpace { } impl XRReferenceSpace { - /// Gets pose of the viewer with respect to this space + /// Get a transform that can be used to locate the base space /// - /// This is equivalent to `get_pose(self).inverse() * get_pose(viewerSpace)` (in column vector notation), - /// however we specialize it to be efficient - pub fn get_viewer_pose(&self, base_pose: &Frame) -> Option { - let pose = self.get_unoffset_viewer_pose(base_pose)?; - // in column-vector notation, - // get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space) - // = (get_unoffset_pose(space) * offset).inverse() * get_pose(viewer_space) - // = offset.inverse() * get_unoffset_pose(space).inverse() * get_pose(viewer_space) - // = offset.inverse() * get_unoffset_viewer_pose(space) - let offset = self.offset.transform(); - let inverse = offset.inverse(); - Some(inverse.pre_transform(&pose)) - } - - /// Gets pose of the viewer with respect to this space - /// - /// Does not apply originOffset, use get_viewer_pose instead if you need it - pub fn get_unoffset_viewer_pose(&self, base_pose: &Frame) -> Option { - // all math is in column-vector notation - // we use the following equation to verify correctness here: - // get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space) - match self.ty { - XRReferenceSpaceType::Local => { - // get_viewer_pose(eye_level) = get_pose(eye_level).inverse() * get_pose(viewer_space) - // = I * viewer_pose - // = viewer_pose - let viewer_pose: ApiViewerPose = cast_transform(base_pose.pose.as_ref()?.transform); - - // we get viewer poses in eye-level space by default - Some(viewer_pose) - }, - XRReferenceSpaceType::Local_floor => { - // get_viewer_pose(floor_level) = get_pose(floor_level).inverse() * get_pose(viewer_space) - // = floor_to_native.inverse() * viewer_pose - // = native_to_floor * viewer_pose - let viewer_pose = base_pose.pose.as_ref()?.transform; - let native_to_floor = self - .upcast::() - .session() - .with_session(|s| s.floor_transform())?; - - Some(cast_transform(native_to_floor.pre_transform(&viewer_pose))) - }, - XRReferenceSpaceType::Viewer => { - // This reference space follows the viewer around, so the viewer is - // always at an identity transform with respect to it - Some(RigidTransform3D::identity()) - }, - _ => unimplemented!(), - } + /// This is equivalent to `get_pose(self).inverse()` (in column vector notation), + /// but with better types + pub fn get_base_transform(&self, base_pose: &Frame) -> Option { + let pose = self.get_pose(base_pose)?; + Some(pose.inverse().cast_unit()) } /// Gets pose represented by this space diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 879dff7b6626..3b27b21222de 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -791,11 +791,14 @@ impl XRSessionMethods for XRSession { // The pose of an object in native-space. Should never be exposed. pub type ApiPose = RigidTransform3D; -// The pose of the viewer in some api-space. -pub type ApiViewerPose = RigidTransform3D; // A transform between objects in some API-space pub type ApiRigidTransform = RigidTransform3D; +#[derive(Clone, Copy)] +pub struct BaseSpace; + +pub type BaseTransform = RigidTransform3D; + #[allow(unsafe_code)] pub fn cast_transform( transform: RigidTransform3D, diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 4ec37a7b6b03..55cac600f6b8 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -9,9 +9,10 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::utils::create_typed_array; use crate::dom::globalscope::GlobalScope; use crate::dom::xrrigidtransform::XRRigidTransform; -use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession}; +use crate::dom::xrsession::{cast_transform, BaseSpace, BaseTransform, XRSession}; use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use euclid::RigidTransform3D; use js::jsapi::{Heap, JSObject}; use std::ptr::NonNull; use webxr_api::{ApiSpace, View}; @@ -54,15 +55,9 @@ impl XRView { view: &View, eye: XREye, viewport_index: usize, - pose: &ApiViewerPose, + to_base: &BaseTransform, ) -> DomRoot { - // XXXManishearth compute and cache projection matrices on the Display - - // this transform is the pose of the viewer in the eye space, i.e. it is the transform - // from the viewer space to the eye space. We invert it to get the pose of the eye in the viewer space. - let offset = view.transform.inverse(); - - let transform = pose.pre_transform(&offset); + let transform: RigidTransform3D = to_base.pre_transform(&view.transform); let transform = XRRigidTransform::new(global, cast_transform(transform)); reflect_dom_object( diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 10c212c5ada4..d88eb7ec9c9d 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -9,15 +9,16 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::globalscope::GlobalScope; use crate::dom::xrpose::XRPose; use crate::dom::xrrigidtransform::XRRigidTransform; -use crate::dom::xrsession::{cast_transform, ApiViewerPose, XRSession}; +use crate::dom::xrsession::{cast_transform, BaseSpace, BaseTransform, XRSession}; use crate::dom::xrview::XRView; use crate::realms::enter_realm; use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use euclid::RigidTransform3D; use js::conversions::ToJSValConvertible; use js::jsapi::Heap; use js::jsval::{JSVal, UndefinedValue}; -use webxr_api::{ViewerPose, Views}; +use webxr_api::{Viewer, ViewerPose, Views}; #[dom_struct] pub struct XRViewerPose { @@ -38,7 +39,7 @@ impl XRViewerPose { pub fn new( global: &GlobalScope, session: &XRSession, - pose: ApiViewerPose, + to_base: BaseTransform, viewer_pose: &ViewerPose, ) -> DomRoot { let _ac = enter_realm(&*global); @@ -50,29 +51,64 @@ impl XRViewerPose { &session.inline_view(), XREye::None, 0, - &pose, + &to_base, + )), + Views::Mono(view) => views.push(XRView::new( + global, + session, + &view, + XREye::None, + 0, + &to_base, )), - Views::Mono(view) => { - views.push(XRView::new(global, session, &view, XREye::None, 0, &pose)) - }, Views::Stereo(left, right) => { - views.push(XRView::new(global, session, &left, XREye::Left, 0, &pose)); - views.push(XRView::new(global, session, &right, XREye::Right, 1, &pose)); + views.push(XRView::new( + global, + session, + &left, + XREye::Left, + 0, + &to_base, + )); + views.push(XRView::new( + global, + session, + &right, + XREye::Right, + 1, + &to_base, + )); }, Views::StereoCapture(left, right, third_eye) => { - views.push(XRView::new(global, session, &left, XREye::Left, 0, &pose)); - views.push(XRView::new(global, session, &right, XREye::Right, 1, &pose)); + views.push(XRView::new( + global, + session, + &left, + XREye::Left, + 0, + &to_base, + )); + views.push(XRView::new( + global, + session, + &right, + XREye::Right, + 1, + &to_base, + )); views.push(XRView::new( global, session, &third_eye, XREye::None, 2, - &pose, + &to_base, )); }, }; - let transform = XRRigidTransform::new(global, cast_transform(pose)); + let transform: RigidTransform3D = + to_base.pre_transform(&viewer_pose.transform); + let transform = XRRigidTransform::new(global, cast_transform(transform)); let pose = reflect_dom_object(Box::new(XRViewerPose::new_inherited(&transform)), global); let cx = global.get_cx();