Use a tracker coordinate system instead of stage. Update examples so they function but next they need to use the (not yet implemented) floor anchors.

This commit is contained in:
Trevor F. Smith 2017-10-04 16:08:47 -07:00
Родитель a86bafcab0
Коммит 34e88a32ef
16 изменённых файлов: 95 добавлений и 116 удалений

Просмотреть файл

@ -57,9 +57,8 @@ The scene, camera, and renderer objects below are representative APIs that have
// Set up for the next frame
session.requestFrame(frame => { handleFrame(frame) })
// Get the pose for the world coordinate system
let stageCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.STAGE)
let stagePose = frame.getViewPose(stageCoordinateSystem)
// Get the pose for the HMD or handset tracker coordinate system
let trackerCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.TRACKER)
// Get the pose for the head
let headCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.HEAD_MODEL)
@ -126,11 +125,11 @@ You now have a couple of anchored nodes save in `anchoredNodes`, so during each
const anchor = frame.getAnchor(anchoredNode.anchorOffset.anchorUID)
// Get the offset coordinates relative to the anchor
let offsetCoordinates = anchoredNode.anchorOffset.getTransformedCoordinates(anchor)
// Now use the offset coordinates, possibly by converting to the stage coordinate system.
if(offsetCoordinates.coordinateSystem.type === XRCoordinateSystem.STAGE){
// Now use the offset coordinates, possibly by converting to the tracker coordinate system.
if(offsetCoordinates.coordinateSystem.type === XRCoordinateSystem.TRACKER){
anchoredNode.node.matrix = offsetCoordinates.poseMatrix
} else {
anchoredNode.node.matrix = offsetCoordinates.getTransformedCoordinates(stageCoordinateSystem).poseMatrix
anchoredNode.node.matrix = offsetCoordinates.getTransformedCoordinates(trackerCoordinateSystem).poseMatrix
}
}

Просмотреть файл

@ -58,11 +58,11 @@
}
// Called during construction
initializeStageGroup(){
this.stageGroup.add(new THREE.AmbientLight('#FFF', 0.2))
initializeScene(){
this.scene.add(new THREE.AmbientLight('#FFF', 0.2))
let directionalLight = new THREE.DirectionalLight('#FFF', 0.6)
directionalLight.position.set(0, 10, 0)
this.stageGroup.add(directionalLight)
this.scene.add(directionalLight)
}
createSceneGraphNode(){
@ -83,8 +83,9 @@
}
// Called once per frame
updateStageGroup(frame, stageCoordinateSystem, stagePose){
let headCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.HEAD_MODEL)
updateScene(frame){
const headCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.HEAD_MODEL)
const trackerCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.TRACKER)
// Create anchors for newly anchored nodes
for(let anchorToAdd of this.anchorsToAdd){
@ -102,7 +103,7 @@
anchorUID: anchorUID,
node: anchorToAdd.node
})
this.stageGroup.add(anchorToAdd.node)
this.scene.add(anchorToAdd.node)
}
this.anchorsToAdd = []
@ -113,7 +114,7 @@
console.error('Unknown anchor ID', anchoredNode.anchorId)
} else {
anchoredNode.node.matrixAutoUpdate = false
anchoredNode.node.matrix.fromArray(anchor.coordinates.getTransformedCoordinates(stageCoordinateSystem).poseMatrix)
anchoredNode.node.matrix.fromArray(anchor.coordinates.getTransformedCoordinates(trackerCoordinateSystem).poseMatrix)
anchoredNode.node.updateMatrixWorld(true)
}
}

Просмотреть файл

@ -36,45 +36,45 @@
<div id="target" />
<script>
/*
ARSimplestExample shows how to populate the stage group that is rendered on the stage
ARSimplestExample shows how to populate the content scene
*/
class ARSimplestExample extends XRExampleBase {
constructor(domElement){
super(domElement, false)
}
// Called during construction to allow the app to populate this.stageGroup (a THREE.Group)
initializeStageGroup(){
// Called during construction to allow the app to populate the THREE.Scene
initializeScene(){
// Add a teapot at about eye level
var geometry = new THREE.TeapotBufferGeometry(0.1)
let materialColor = new THREE.Color()
const geometry = new THREE.TeapotBufferGeometry(0.1)
const materialColor = new THREE.Color()
materialColor.setRGB(1.0, 1.0, 1.0)
let material = new THREE.MeshLambertMaterial({
const material = new THREE.MeshLambertMaterial({
color: materialColor,
side: THREE.DoubleSide
})
let mesh = new THREE.Mesh(geometry, material)
const mesh = new THREE.Mesh(geometry, material)
mesh.position.set(0, 1.4, -1)
this.stageGroup.add(mesh)
this.scene.add(mesh)
// Add a box at the stage origin
let box = new THREE.Mesh(
// Add a box at the scene origin
const box = new THREE.Mesh(
new THREE.BoxBufferGeometry(0.1, 0.1, 0.1),
new THREE.MeshPhongMaterial({ color: '#DDFFDD' })
)
box.position.set(0, 0, 0)
this.stageGroup.add(box)
this.scene.add(box)
this.stageGroup.add(new THREE.AmbientLight('#FFF', 0.2))
let directionalLight = new THREE.DirectionalLight('#FFF', 0.6)
this.scene.add(new THREE.AmbientLight('#FFF', 0.2))
const directionalLight = new THREE.DirectionalLight('#FFF', 0.6)
directionalLight.position.set(0, 10, 0)
this.stageGroup.add(directionalLight)
this.scene.add(directionalLight)
}
// Called once per frame, before render to give the app a chance to update this.stageGroup (a THREE.Group)
updateStageGroup(frame, stageCoordinateSystem, stagePose){
// Called once per frame, before render to give the app a chance to update the this.scene
updateScene(frame){
// Uncomment the next line to spin the teapot
//this.stageGroup.children[0].rotation.y += 0.01
//this.scene.children[0].rotation.y += 0.01
}
}

Просмотреть файл

@ -26,14 +26,12 @@ class XRExampleBase {
// Create a simple THREE test scene for the layer
this.scene = new THREE.Scene() // The scene will be rotated and oriented around the camera using the head pose
this.stageGroup = new THREE.Group() // The group that stays on the "stage", which is at foot level relative to the head
this.scene.add(this.stageGroup)
this.camera = new THREE.PerspectiveCamera(70, 1024, 1024, 0.1, 1000) // These values will be overwritten by the projection matrix from ARKit or ARCore
this.renderer = null // Set in this.handleNewSession
// Give extending classes the opportunity to initially populate the stage group
this.initializeStageGroup(this.stageGroup)
// Give extending classes the opportunity to initially populate the scene
this.initializeScene()
if(typeof navigator.XR === 'undefined'){
this.showMessage('No WebXR API found, usually because the WebXR polyfill has not loaded')
@ -154,46 +152,27 @@ class XRExampleBase {
handleLayerBlur(ev){}
/*
Extending classes should override this to set up the stageGroup during class construction
Extending classes should override this to set up the scene during class construction
*/
initializeStageGroup(){}
initializeScene(){}
/*
Extending classes that need to update the layer during each frame should override this method
*/
updateStageGroup(frame, stageCoordinateSystem, stagePose){}
updateScene(frame){}
handleFrame(frame){
const nextFrameRequest = this.session.requestFrame(frame => { this.handleFrame(frame) })
let stageCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.STAGE)
if(stageCoordinateSystem === null){
this.showMessage('Could not get a usable stage coordinate system')
this.session.cancelFrame(nextFrameRequest)
this.session.endSession()
// Production apps could render a 'waiting' message and keep checking for an acceptable coordinate system
return
}
// Get the two poses we care about: the foot level stage and head pose which is updated by ARKit, ARCore, or orientation events
let stagePose = frame.getViewPose(stageCoordinateSystem)
let headPose = frame.getViewPose(frame.getCoordinateSystem(XRCoordinateSystem.HEAD_MODEL))
// Let the extending class update the stageGroup before each render
this.updateStageGroup(frame, stageCoordinateSystem, stagePose)
// Update the stage group relative to the current head pose
this.stageGroup.matrixAutoUpdate = false
this.stageGroup.matrix.fromArray(stagePose.poseModelMatrix)
this.stageGroup.updateMatrixWorld(true)
// Let the extending class update the scene before each render
this.updateScene(frame)
// Prep THREE.js for the render of each XRView
//this.renderer.resetGLState()
this.scene.matrixAutoUpdate = false
this.renderer.autoClear = false
this.renderer.setSize(this.session.baseLayer.framebufferWidth, this.session.baseLayer.framebufferHeight, false)
this.renderer.clear()
//this.session.baseLayer.context.bindFramebuffer(this.session.baseLayer.context.FRAMEBUFFER, this.session.baseLayer.framebuffer)
this.scene.matrixAutoUpdate = false
// Render each view into this.session.baseLayer.context
for(const view of frame.views){

Просмотреть файл

@ -47,7 +47,7 @@
class HitTestExample extends XRExampleBase {
constructor(domElement){
super(domElement, false)
this._tapEventData = null // Will be filled in on touch start and used in updateStageGroup
this._tapEventData = null // Will be filled in on touch start and used in updateScene
this.anchoredNodes = [] // { XRAnchorOffset, Three.js Object3D }
@ -63,33 +63,33 @@
this.el.addEventListener('touchstart', this._onTouchStart.bind(this), false)
}
// Called during construction to allow the app to populate this.stageGroup (a THREE.Group)
initializeStageGroup(){
// Add a box at the stage origin to show where the stage group is located
// Called during construction to allow the app to populate this.scene
initializeScene(){
// Add a box at the scene origin
let box = new THREE.Mesh(
new THREE.BoxBufferGeometry(0.1, 0.1, 0.1),
new THREE.MeshPhongMaterial({ color: '#DDFFDD' })
)
box.position.set(0, 0, 0)
this.stageGroup.add(box)
this.scene.add(box)
// Add a box one meter in front of stage origin to show the direction of the Z axis
// Add a box one meter in front of scene origin to show the direction of the Z axis
box = new THREE.Mesh(
new THREE.BoxBufferGeometry(0.1, 0.1, 0.1),
new THREE.MeshPhongMaterial({ color: '#FF0000' })
)
box.position.set(0, 0, -1)
this.stageGroup.add(box)
this.scene.add(box)
// Add a few lights
this.stageGroup.add(new THREE.AmbientLight('#FFF', 0.2))
this.scene.add(new THREE.AmbientLight('#FFF', 0.2))
let directionalLight = new THREE.DirectionalLight('#FFF', 0.6)
directionalLight.position.set(0, 10, 0)
this.stageGroup.add(directionalLight)
this.scene.add(directionalLight)
}
// Called once per frame, before render, to give the app a chance to update this.stageGroup (a THREE.Group)
updateStageGroup(frame, stageCoordinateSystem, stagePose){
// Called once per frame, before render, to give the app a chance to update this.scene
updateScene(frame){
// If we have tap data, attempt a hit test for a surface
if(this._tapEventData !== null){
const x = this._tapEventData[0]
@ -116,13 +116,14 @@
// Add a block to the scene to indicate the position of the XRAnchorOffset
// Its position will be updated below along with the other anchored nodes
this.stageGroup.add(anchorInfo.node)
this.scene.add(anchorInfo.node)
}
}).catch(err => {
console.error('Error in hit test', err)
})
}
const trackerCoordinateSystem = frame.getCoordinateSystem(XRCoordinateSystem.TRACKER)
// Update anchored node positions in the scene graph using updated anchor positions
for(let anchoredNode of this.anchoredNodes){
const anchor = frame.getAnchor(anchoredNode.anchorOffset.anchorUID)
@ -131,17 +132,17 @@
} else {
anchoredNode.node.matrixAutoUpdate = false
let offsetCoordinates = anchoredNode.anchorOffset.getTransformedCoordinates(anchor)
if(offsetCoordinates.coordinateSystem.type === XRCoordinateSystem.STAGE){
if(offsetCoordinates.coordinateSystem.type === XRCoordinateSystem.TRACKER){
anchoredNode.node.matrix.fromArray(offsetCoordinates.poseMatrix)
} else {
anchoredNode.node.matrix.fromArray(offsetCoordinates.getTransformedCoordinates(stageCoordinateSystem).poseMatrix)
anchoredNode.node.matrix.fromArray(offsetCoordinates.getTransformedCoordinates(trackerCoordinateSystem).poseMatrix)
}
anchoredNode.node.updateMatrixWorld(true)
}
}
}
// Save screen taps as normalized coordinates for use in this.updateStageGroup
// Save screen taps as normalized coordinates for use in this.updateScene
_onTouchStart(ev){
if (!ev.touches || ev.touches.length === 0) {
console.error('No touches on touch event', ev)

Просмотреть файл

@ -50,7 +50,7 @@
}
// Called during construction
initializeStageGroup(){
initializeScene(){
// Add a teapot at about eye level
var geometry = new THREE.TeapotBufferGeometry(0.1)
let materialColor = new THREE.Color()
@ -61,26 +61,26 @@
})
let mesh = new THREE.Mesh(geometry, material)
mesh.position.set(0, 1.6, -1)
this.stageGroup.add(mesh)
this.scene.add(mesh)
// Add a box at the stage origin
// Add a box at the scene origin
let box = new THREE.Mesh(
new THREE.BoxBufferGeometry(0.1, 0.1, 0.1),
new THREE.MeshPhongMaterial({ color: '#DDFFDD' })
)
box.position.set(0, 0, 0)
this.stageGroup.add(box)
this.scene.add(box)
this.stageGroup.add(new THREE.AmbientLight('#FFF', 0.2))
this.scene.add(new THREE.AmbientLight('#FFF', 0.2))
let directionalLight = new THREE.DirectionalLight('#FFF', 0.6)
directionalLight.position.set(0, 10, 0)
this.stageGroup.add(directionalLight)
this.scene.add(directionalLight)
}
// Called once per frame
updateStageGroup(frame, stageCoordinateSystem, stagePose){
updateScene(frame){
// Uncomment the next line to spin the box
// this.stageGroup.children[0].rotation.y += 0.01
// this.scene.children[0].rotation.y += 0.01
}
}

Просмотреть файл

@ -7,7 +7,7 @@ The XRCoordinateSystem is a string from XRCoordinateSystem.TYPES:
- XRCoordinateSystem.HEAD_MODEL: origin is aligned with the pose of the head, as sensed by HMD or handset trackers
- XRCoordinateSystem.EYE_LEVEL: origin is at a fixed distance above the ground
- XRCoordinateSystem.STAGE: origin is at ground level
- XRCoordinateSystem.TRACKER: The origin of this coordinate system is at floor level at or below the origin of the HMD or handset provided tracking system
- XRCoordinateSystem.GEOSPATIAL: origin is at the East, Up, South plane tangent to the planet at the latitude, longitude, and altitude represented by the `XRCoordinateSystem.cartographicCoordinates`.
*/
@ -28,8 +28,8 @@ export default class XRCoordinateSystem {
return this._display._headPose.poseModelMatrix
case XRCoordinateSystem.EYE_LEVEL:
return this._display._eyeLevelPose.poseModelMatrix
case XRCoordinateSystem.STAGE:
return this._display._stagePose.poseModelMatrix
case XRCoordinateSystem.TRACKER:
return this._display._trackerPoseModelMatrix
case XRCoordinateSystem.GEOSPATIAL:
throw 'This polyfill does not yet handle geospatial coordinate systems'
default:
@ -60,14 +60,14 @@ export default class XRCoordinateSystem {
}
}
XRCoordinateSystem.HEAD_MODEL = "headModel"
XRCoordinateSystem.EYE_LEVEL = "eyeLevel"
XRCoordinateSystem.STAGE = "stage"
XRCoordinateSystem.GEOSPATIAL = "geospatial"
XRCoordinateSystem.HEAD_MODEL = 'headModel'
XRCoordinateSystem.EYE_LEVEL = 'eyeLevel'
XRCoordinateSystem.TRACKER = 'tracker'
XRCoordinateSystem.GEOSPATIAL = 'geospatial'
XRCoordinateSystem.TYPES = [
XRCoordinateSystem.HEAD_MODEL,
XRCoordinateSystem.EYE_LEVEL,
XRCoordinateSystem.STAGE,
XRCoordinateSystem.TRACKER,
XRCoordinateSystem.GEOSPATIAL
]

Просмотреть файл

@ -18,11 +18,16 @@ export default class XRDisplay extends EventHandlerBase {
this._headModelCoordinateSystem = new XRCoordinateSystem(this, XRCoordinateSystem.HEAD_MODEL)
this._eyeLevelCoordinateSystem = new XRCoordinateSystem(this, XRCoordinateSystem.EYE_LEVEL)
this._stageCoordinateSystem = new XRCoordinateSystem(this, XRCoordinateSystem.STAGE)
this._trackerCoordinateSystem = new XRCoordinateSystem(this, XRCoordinateSystem.TRACKER)
this._headPose = new XRViewPose([0, XRViewPose.SITTING_EYE_HEIGHT, 0])
this._eyeLevelPose = new XRViewPose([0, XRViewPose.SITTING_EYE_HEIGHT, 0])
this._stagePose = new XRViewPose([0, 0, 0])
this._trackerPoseModelMatrix = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
var fov = 50/2;
this._fov = new XRFieldOfView(fov, fov, fov, fov)

Просмотреть файл

@ -86,8 +86,6 @@ export default class XRPresentationFrame {
return this._session._display._headPose
case XRCoordinateSystem.EYE_LEVEL:
return this._session._display._eyeLevelPose
case XRCoordinateSystem.STAGE:
return this._session._display._stagePose
default:
return null
}

Просмотреть файл

@ -75,8 +75,8 @@ export default class XRSession extends EventHandlerBase {
return this._display._headModelCoordinateSystem
case XRCoordinateSystem.EYE_LEVEL:
return this._display._eyeLevelCoordinateSystem
case XRCoordinateSystem.STAGE:
return this._display._stageCoordinateSystem
case XRCoordinateSystem.TRACKER:
return this._display._trackerCoordinateSystem
case XRCoordinateSystem.GEOSPATIAL:
// Not supported yet
default:

Просмотреть файл

@ -6,11 +6,11 @@ Other XR platforms sometimes refer to this concept as "room scale" or "standing
export default class XRStageBounds {
get center(){
//readonly attribute XRCoordinates center;
throw 'Not implemented'
throw new Error('Not implemented')
}
get geometry(){
//readonly attribute FrozenArray<XRStageBoundsPoint>? geometry;
throw 'Not implemented'
throw new Error('Not implemented')
}
}

Просмотреть файл

@ -4,11 +4,11 @@ XRStageBoundPoints represent the offset in meters from the stage origin along th
export default class XRStageBoundsPoint {
get x(){
//readonly attribute double x;
throw 'Not implemented'
throw new Error('Not implemented')
}
get y(){
//readonly attribute double z;
throw 'Not implemented'
throw new Error('Not implemented')
}
}

Просмотреть файл

@ -109,7 +109,6 @@ export default class FlatDisplay extends XRDisplay {
MatrixMath.mat4_fromRotationTranslation(this._deviceWorldMatrix, this._deviceOrientation.toArray(), this._devicePosition.toArray())
this._headPose._setPoseModelMatrix(this._deviceWorldMatrix)
this._eyeLevelPose._position = this._devicePosition.toArray()
this._stagePose._position = [0, 0, 0]
}
_updateFromDeviceOrientationTracker(){
@ -120,7 +119,6 @@ export default class FlatDisplay extends XRDisplay {
MatrixMath.mat4_fromRotationTranslation(this._deviceWorldMatrix, this._deviceOrientation.toArray(), this._devicePosition.toArray())
this._headPose._setPoseModelMatrix(this._deviceWorldMatrix)
this._eyeLevelPose._position = this._devicePosition.toArray()
this._stagePose._position = [0, 0, 0]
}
_handleARKitUpdate(...params){
@ -129,7 +127,6 @@ export default class FlatDisplay extends XRDisplay {
this._headPose._setPoseModelMatrix(cameraTransformMatrix)
this._headPose._poseModelMatrix[13] += XRViewPose.SITTING_EYE_HEIGHT
this._eyeLevelPose._position = this._headPose._position
this._stagePose._position = [0, 0, 0]
} else {
console.log('no camera transform', this._arKitWrapper.rawARData)
}

Просмотреть файл

@ -98,7 +98,6 @@ export default class HeadMountedDisplay extends XRDisplay {
}
this._headPose._setPoseModelMatrix(this._deviceWorldMatrix)
this._eyeLevelPose.position = this._devicePosition.toArray()
this._stagePose._position = [0, 0, 0]
}
}
}

Просмотреть файл

@ -150,13 +150,13 @@ export default class CameraReality extends Reality {
console.log('unknown anchor', anchor)
return
}
// This assumes that the anchor's coordinates are in the stage coordinate system
// This assumes that the anchor's coordinates are in the tracker coordinate system
anchor.coordinates.poseMatrix = anchorInfo.transform
}
_addAnchor(anchor, display){
// Convert coordinates to the stage coordinate system so that updating from ARKit transforms is simple
anchor.coordinates = anchor.coordinates.getTransformedCoordinates(display._stageCoordinateSystem)
// Convert coordinates to the tracker coordinate system so that updating from ARKit transforms is simple
anchor.coordinates = anchor.coordinates.getTransformedCoordinates(display._trackerCoordinateSystem)
if(this._arKitWrapper !== null){
this._arKitWrapper.addAnchor(anchor.uid, anchor.coordinates.poseMatrix).then(
detail => this._handleARKitAddObject(detail)
@ -192,7 +192,7 @@ export default class CameraReality extends Reality {
let anchor = this._getAnchor(hit.uuid)
if(anchor === null){
let anchorCoordinates = new XRCoordinates(display, display._stageCoordinateSystem)
let anchorCoordinates = new XRCoordinates(display, display._trackerCoordinateSystem)
anchorCoordinates.poseMatrix = hit.anchor_transform
anchor = new XRAnchor(anchorCoordinates, hit.uuid)
this._anchors.set(anchor.uid, anchor)
@ -220,7 +220,7 @@ export default class CameraReality extends Reality {
hits.sort((a, b) => a.distance - b.distance)
let anchor = this._getAnchor(hits[0].uuid)
if(anchor === null){
let coordinates = new XRCoordinates(display, display._stageCoordinateSystem)
let coordinates = new XRCoordinates(display, display._trackerCoordinateSystem)
coordinates.poseMatrix = hits[0].modelMatrix
coordinates._poseMatrix[13] += XRViewPose.SITTING_EYE_HEIGHT
anchor = new XRAnchor(coordinates)

Просмотреть файл

@ -9,29 +9,29 @@ import Quaternion from '../polyfill/fill/Quaternion.js'
export default class CoordinatesTest extends Test {
testTransform(){
let display1 = new MockXRDisplay()
let stageCoordinateSystem = new XRCoordinateSystem(display1, XRCoordinateSystem.STAGE)
let trackerCoordinateSystem = new XRCoordinateSystem(display1, XRCoordinateSystem.TRACKER)
let headCoordinateSystem = new XRCoordinateSystem(display1, XRCoordinateSystem.HEAD_MODEL)
let eyeLevelCoordinateSystem = new XRCoordinateSystem(display1, XRCoordinateSystem.EYE_LEVEL)
let headCoordinates = new XRCoordinates(display1, headCoordinateSystem, [0, 0, -0.5])
let stageCoordinates = headCoordinates.getTransformedCoordinates(stageCoordinateSystem)
let trackerCoordinates = headCoordinates.getTransformedCoordinates(trackerCoordinateSystem)
this.assertFloatArraysEqual(
stageCoordinates.position,
trackerCoordinates.position,
[headCoordinates.position[0], XRViewPose.SITTING_EYE_HEIGHT + headCoordinates.position[1], headCoordinates.position[2]]
)
this.assertFloatArraysEqual(stageCoordinates.orientation, headCoordinates.orientation)
this.assertFloatArraysEqual(trackerCoordinates.orientation, headCoordinates.orientation)
// Rotate the head and test the transform
let quat1 = new Quaternion()
quat1.setFromEuler(0, -Math.PI, 0)
display1._headPose._orientation = quat1.toArray()
stageCoordinates = headCoordinates.getTransformedCoordinates(stageCoordinateSystem)
trackerCoordinates = headCoordinates.getTransformedCoordinates(trackerCoordinateSystem)
this.assertFloatArraysEqual(
stageCoordinates.position,
trackerCoordinates.position,
[headCoordinates.position[0], XRViewPose.SITTING_EYE_HEIGHT + headCoordinates.position[1], -1 * headCoordinates.position[2]]
)
quat1.inverse()
this.assertFloatArraysEqual(quat1.toArray(), stageCoordinates.orientation)
this.assertFloatArraysEqual(quat1.toArray(), trackerCoordinates.orientation)
}
}