Skip to content
Permalink
Browse files

Auto merge of #23159 - Manishearth:rigid-transforms, r=asajeffrey

Update XR code to use rigid transforms and new pose/transform stuff from the spec

This updates our XR code to use euclid's new [RigidTransform3D type](servo/euclid#328), which is more efficent and convenient to work with.

It additionally brings us up to speed with the spec:

 - `XRViewerPose` was made a subclass of `XRPose` (immersive-web/webxr#496)
 - `XRView.viewMatrix` was removed in favor of `XRRigidTransform.inverse.matrix` (immersive-web/webxr#531)
 - `XRRigidTransform.inverse` is an attribute (immersive-web/webxr#560)
 - `XRRigidTransform` now validates positions in its constructor (immersive-web/webxr#568)

Furthermore, it adds support for `XRRigidTransform.matrix`.

While fixing this I also noticed that our view matrix code was incorrect, we calculated view matrices as `pose.to_column_major_array()`, whereas it *should* be `pose.inverse().to_row_major_array()` (since Euclid uses row vectors, whenever the spec says it wants a column major array we should use `.to_row_major_array()` since all web specs implicitly use column vectors). For 3DOF devices poses are mostly rotations anyway, so the effective transpose behaved _like_ an inversion, but was incorrect.

This PR gets rid of `view.viewMatrix` anyway, however I felt like I should mention this discrepancy, since otherwise the replacement of `view.viewMatrix` with `view.transform.inverse.matrix` doesn't make sense

r? @jdm

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23159)
<!-- Reviewable:end -->
  • Loading branch information...
bors-servo committed Apr 4, 2019
2 parents 3e86aec + e055884 commit 709cfebfb69c136ce05c4e51a42c4db8fedd1417

Large diffs are not rendered by default.

@@ -50,7 +50,7 @@ domobject_derive = {path = "../domobject_derive"}
embedder_traits = {path = "../embedder_traits"}
encoding_rs = "0.8"
enum-iterator = "0.2.0"
euclid = "0.19"
euclid = "0.19.7"
fnv = "1.0"
gleam = "0.6"
headers-core = "0.0.1"
@@ -57,7 +57,8 @@ use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
use encoding_rs::{Decoder, Encoding};
use euclid::Length as EuclidLength;
use euclid::{
Point2D, Rect, Rotation3D, Transform2D, Transform3D, TypedScale, TypedSize2D, Vector2D,
Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedScale, TypedSize2D,
Vector2D,
};
use html5ever::buffer_queue::BufferQueue;
use html5ever::{LocalName, Namespace, Prefix, QualName};
@@ -494,7 +495,8 @@ unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
unsafe_no_jsmanaged_fields!(Timespec);
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
unsafe_no_jsmanaged_fields!(Rotation3D<f64>, Transform2D<f32>, Transform3D<f64>);
unsafe_no_jsmanaged_fields!(Point2D<f32>, Vector2D<f32>, Rect<Au>, Rect<f32>);
unsafe_no_jsmanaged_fields!(Point2D<f32>, Vector2D<f32>, Rect<Au>);
unsafe_no_jsmanaged_fields!(Rect<f32>, RigidTransform3D<f64>);

unsafe impl<'a> JSTraceable for &'a str {
#[inline]
@@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::{
DOMPointReadOnlyMethods, Wrap,
};
@@ -51,10 +50,6 @@ impl DOMPointReadOnly {
) -> Fallible<DomRoot<DOMPointReadOnly>> {
Ok(DOMPointReadOnly::new(global, x, y, z, w))
}

pub fn new_from_init(global: &GlobalScope, p: &DOMPointInit) -> DomRoot<DOMPointReadOnly> {
DOMPointReadOnly::new(global, p.x, p.y, p.z, p.w)
}
}

impl DOMPointReadOnlyMethods for DOMPointReadOnly {
@@ -537,6 +537,7 @@ pub mod xmlserializer;
pub mod xr;
pub mod xrframe;
pub mod xrlayer;
pub mod xrpose;
pub mod xrreferencespace;
pub mod xrrenderstate;
pub mod xrrigidtransform;
@@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

// https://immersive-web.github.io/webxr/#xrpose-interface

[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
interface XRPose {
readonly attribute XRRigidTransform transform;
// readonly attribute boolean emulatedPosition;
};
@@ -9,6 +9,6 @@
interface XRRigidTransform {
readonly attribute DOMPointReadOnly position;
readonly attribute DOMPointReadOnly orientation;
// readonly attribute Float32Array matrix;
XRRigidTransform inverse();
readonly attribute Float32Array matrix;
readonly attribute XRRigidTransform inverse;
};
@@ -13,6 +13,5 @@ enum XREye {
interface XRView {
readonly attribute XREye eye;
readonly attribute Float32Array projectionMatrix;
readonly attribute Float32Array viewMatrix;
// readonly attribute XRRigidTransform transform;
readonly attribute XRRigidTransform transform;
};
@@ -5,8 +5,7 @@
// https://immersive-web.github.io/webxr/#xrviewerpose-interface

[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
interface XRViewerPose {
// readonly attribute XRRigidTransform transform;
interface XRViewerPose : XRPose {
// readonly attribute FrozenArray<XRView> views;
// workaround until we have FrozenArray
// see https://github.com/servo/servo/issues/10427#issuecomment-449593626
@@ -4,13 +4,11 @@

use crate::dom::bindings::codegen::Bindings::XRFrameBinding;
use crate::dom::bindings::codegen::Bindings::XRFrameBinding::XRFrameMethods;
use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::XRSession;
use crate::dom::xrview::XRView;
use crate::dom::xrviewerpose::XRViewerPose;
use dom_struct::dom_struct;
use webvr_traits::WebVRFrameData;
@@ -54,20 +52,11 @@ impl XRFrameMethods for XRFrame {
/// https://immersive-web.github.io/webxr/#dom-xrframe-getviewerpose
fn GetViewerPose(&self, reference: &XRReferenceSpace) -> Option<DomRoot<XRViewerPose>> {
let pose = reference.get_viewer_pose(&self.data);
let left = XRView::new(
Some(XRViewerPose::new(
&self.global(),
&self.session,
XREye::Left,
&pose,
pose,
&self.data,
);
let right = XRView::new(
&self.global(),
&self.session,
XREye::Right,
&pose,
&self.data,
);
Some(XRViewerPose::new(&self.global(), &left, &right))
))
}
}
@@ -0,0 +1,44 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::XRPoseBinding;
use crate::dom::bindings::codegen::Bindings::XRPoseBinding::XRPoseMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrrigidtransform::XRRigidTransform;
use dom_struct::dom_struct;
use euclid::RigidTransform3D;

#[dom_struct]
pub struct XRPose {
reflector_: Reflector,
transform: Dom<XRRigidTransform>,
}

impl XRPose {
pub fn new_inherited(transform: &XRRigidTransform) -> XRPose {
XRPose {
reflector_: Reflector::new(),
transform: Dom::from_ref(transform),
}
}

#[allow(unused)]
pub fn new(global: &GlobalScope, transform: RigidTransform3D<f64>) -> DomRoot<XRPose> {
let transform = XRRigidTransform::new(global, transform);
reflect_dom_object(
Box::new(XRPose::new_inherited(&transform)),
global,
XRPoseBinding::Wrap,
)
}
}

impl XRPoseMethods for XRPose {
/// https://immersive-web.github.io/webxr/#dom-xrpose-transform
fn Transform(&self) -> DomRoot<XRRigidTransform> {
DomRoot::from_ref(&self.transform)
}
}
@@ -7,14 +7,13 @@ use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenc
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::{DomRoot, MutDom};
use crate::dom::dompointreadonly::DOMPointReadOnly;
use crate::dom::window::Window;
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrrigidtransform::XRRigidTransform;
use crate::dom::xrsession::XRSession;
use crate::dom::xrspace::XRSpace;
use crate::dom::xrstationaryreferencespace::XRStationaryReferenceSpace;
use dom_struct::dom_struct;
use euclid::Transform3D;
use euclid::RigidTransform3D;
use webvr_traits::WebVRFrameData;

#[dom_struct]
@@ -32,22 +31,7 @@ impl XRReferenceSpace {
}

#[allow(unused)]
pub fn new(
global: &Window,
session: &XRSession,
position: &DOMPointReadOnly,
orientation: &DOMPointReadOnly,
) -> DomRoot<XRReferenceSpace> {
let transform = XRRigidTransform::new(global, position, orientation);
reflect_dom_object(
Box::new(XRReferenceSpace::new_inherited(session, &transform)),
global,
XRReferenceSpaceBinding::Wrap,
)
}

#[allow(unused)]
pub fn identity(global: &Window, session: &XRSession) -> DomRoot<XRReferenceSpace> {
pub fn identity(global: &GlobalScope, session: &XRSession) -> DomRoot<XRReferenceSpace> {
let transform = XRRigidTransform::identity(global);
reflect_dom_object(
Box::new(XRReferenceSpace::new_inherited(session, &transform)),
@@ -71,30 +55,25 @@ impl XRReferenceSpaceMethods for XRReferenceSpace {

impl XRReferenceSpace {
/// Gets viewer pose represented by this space
pub fn get_viewer_pose(&self, base_pose: &WebVRFrameData) -> Transform3D<f64> {
pub fn get_viewer_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> {
let pose = self.get_pose(base_pose);

// This may change, see https://github.com/immersive-web/webxr/issues/567
let offset = self.transform.get().matrix();
// XXXManishearth we can directly compute the inverse from the transform parameters
// (and perhaps cache it)
// XXXManishearth we can also optimize for the unset/identity offset case
let inverse = offset
.inverse()
.expect("rigid transforms are always invertible");
let offset = self.transform.get().transform();
let inverse = offset.inverse();
inverse.pre_mul(&pose)
}

/// Gets pose represented by this space
///
/// Does not apply originOffset, use get_viewer_pose instead if you need it
pub fn get_pose(&self, base_pose: &WebVRFrameData) -> Transform3D<f64> {
pub fn get_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> {
if let Some(stationary) = self.downcast::<XRStationaryReferenceSpace>() {
stationary.get_pose(base_pose)
} else {
// non-subclassed XRReferenceSpaces exist, obtained via the "identity"
// type. The pose does not depend on the base pose.
Transform3D::identity()
RigidTransform3D::identity()
}
}
}

1 comment on commit 709cfeb

@taskcluster

This comment has been minimized.

Copy link

commented on 709cfeb Apr 4, 2019

Submitting the task to Taskcluster failed. Details

InterpreterError at template.tasks[0]: object keys must be strings

Please sign in to comment.
You can’t perform that action at this time.