Initial WebXR position same as camera position

I found a problem where the WebXR position doesn’t match the camera position when launching. Its facing to the left or right. There seems to be noway to reset it. Any ideas ? Its working on the stereo vr example but not the equi example.

Another example without camera position code. It defaults to this tilted view like in the webxr session. My own videos have the same problem when orbitcontrols is disabled. How to correct this ?

I believe this is what I need to do. Ive tried everything including something like this

renderer.xr.addEventListener(‘sessionstart’, () => {

                renderer.xr.getCamera().position.copy( camera.position);

                renderer.xr.getCamera().lookAt( );


                console.log("pos", renderer.xr.getCamera().position);


This is very strange, without a position set, the video starts 90 degrees to the real front of the camera. but in webxr it starts 180 degrees from that position. WebXR camera really needs to take the initial position from the non webxr camera. Even if I shift the geometry instead. It will show flipped in webxr and you need to turn the headset to the left.

Another test with a rotated mesh. WebXR starts in the opposite direction.

Does this code need an offset added to get the front of the camera ?

camera.matrix.fromArray( view.transform.matrix );
camera.projectionMatrix.fromArray( view.projectionMatrix );

I made another test that provides a quick fix. I position the camera to the front. Then I have to flip the mesh in webXR and the opposite direction. Then move it back.

renderer.xr.addEventListener('sessionstart', () => {

                mesh.rotation.y =  -pos;


                renderer.xr.getCamera().lookAt( );



            renderer.xr.addEventListener('sessionend', () => {

                mesh.rotation.y =  0;

                camera.position.x = pos;


Did you find a solution @danrossi?

yes on session start it needs an offset set. But there is bugs like with the non webxr camera initial x position needs to be set. It doesnt show exactly centre without fractions added.

const xrManager = this.renderer.xr,
    camera =,
    baseReferenceSpace = xrManager.getReferenceSpace(),
    offsetPosition = camera.position,
    offsetRotation = camera.rotation;

    const transform = new XRRigidTransform( offsetPosition, { x: this.config.xrTiltOffset ? offsetRotation.x : 0, y: -(offsetRotation.y - this.config.xrPanOffset), z: offsetRotation.z, w: offsetRotation.w } ),
    //const transform = new XRRigidTransform( offsetPosition, { x: offsetRotation.x, y: -(offsetRotation.y - 0.5) , z: offsetRotation.z, w: offsetRotation.w } ),
    teleportSpaceOffset = baseReferenceSpace.getOffsetReferenceSpace( transform );

    xrManager.setReferenceSpace( teleportSpaceOffset );
1 Like

how do you get offsetRotation.w from the camera rotation ?

camera rotation is vec3,

const xrManager = renderer.xr,
    baseReferenceSpace = xrManager.getReferenceSpace(),
    offsetPosition = camera!.position,
    offsetRotation = camera!.rotation

const transform = new XRRigidTransform(offsetPosition, {
        x: offsetRotation.x,
        y: -offsetRotation.y,
        z: offsetRotation.z,
        w: offsetRotation.w,

this is giving me error, I want to start with my xr camera in same position as by camera is

I’m sorry I don’t use bloaty transpiling ts. So don’t get that error. Maybe have to leave it off ? I just rollup raw es6 and don’t get any undefined error. It works for me. But initial camera rotation for non webXR is still a problem where I have to force an x position to face the front of the camera for some reason. That is what I need to figure out now.

I had a requirement to tilt up to match camera rotation and sometimes that is off. Sometimes centre position facing the front of the camera is off with this offset code also. Its different for every video for some reason so I need this

y: -(offsetRotation.y - this.config.xrPanOffset). y is left / right position. x is up and down.

This is actually a use-case for using bloaty transpiling. The error is a genuine pointer to a problem: namely that the camera rotation is a Vector3 “Euler” and the XRRRigidTransformation requires a Vector4 “Quaternion”. You can’t mix the two successfully. It’s easily solved though by retrieving camera.quaternion rather than camera.rotation.

are you suggesting I should try and use camera.quaternion to setup the offset ? I have found I need to tweak it for different videos hence the xrPanOffset config

this works better for the transform. I dont need an offset to force it center !

renderer.xr.addEventListener('sessionstart', (e) => {


                const baseReferenceSpace = renderer.xr.getReferenceSpace();
                const offsetPosition = camera.position;

                //const offsetRotation = camera.rotation;
				const offsetRotation = camera.quaternion;

                const transform = new XRRigidTransform( offsetPosition, { x: offsetRotation.x, y: -(offsetRotation.y), z: offsetRotation.z, w: offsetRotation.w } ); 
				//const transform = new XRRigidTransform( offsetPosition, { x: offsetRotation.x, y: -(offsetRotation.y - 0.85), z: offsetRotation.z, w: offsetRotation.w } ); 
                const teleportSpaceOffset = baseReferenceSpace.getOffsetReferenceSpace( transform );

	            renderer.xr.setReferenceSpace( teleportSpaceOffset );


Great. Give Typescript a try someday. I was a sceptic but am now a convert. It does come with some pain but the gains much outweigh it :slightly_smiling_face:

In the console log below you’ll see a snapshot of the rotation and quaternion for my camera taken from a VR session. You’ll see just how “apples and pears” the two are.

You can’t interchange the two just by copying their attributes from one to the other, though you can use myQuaternion.setFromRotationMatrix(myRotation) or myRotation.setFromQuaternion(myQuaternion).

I love typed language , well coming from Actionscript, Java, C# and even python. But Babel is extremely bloaty. I bundle es6 to iife directly.

It might be good to have that offset setup as standard. It even offsets the x correctly up and down. I had a use case for that, for when lying down in a chair. The offset is needed to be corrected when lying down.