javascriptrotationthree.jseuler-anglesgamepad-api

Three.js camera rotation order


I'm trying to use a gamepad to rotate a camera in Three.js, using first-person-shooter style controls.

The browser detects the gamepad and recognises it's input, but the camera's order of rotation is wrong. When I rotate on the camera's local Y axis, it takes into account the local X rotation too, which is unwanted.

It seems I'm having the same problem as this guy, but his issue was solved using Three.js r54 and I'm using r60. He set camera.eulerOrder = "YXZ"; to get it working, but the current equivalent camera.rotation.order = "YXZ"; doesn't seem to work for me.

I'm aware of Three.js' built-in "FirstPersonControls" class, but it's not suitable for me as it doesn't accept controller input and it would be messy to shoehorn other non-movement controls in there later. I'm also aware of gamepad.js and have no interest in using it.

Can anyone help?

My rotation code:

function pollGamepad()
{
    gamepad = navigator.webkitGetGamepads()[0];

    //Rotation
    if(gamepad.axes[3] > 0.20)
    {
        camera.rotateX(-gamepad.axes[3] * 0.02);
    }
    if(gamepad.axes[3] < -0.20)
    {
        camera.rotateX(-gamepad.axes[3] * 0.02);
    }

    if(gamepad.axes[2] < -0.20)
    {
        camera.rotateY(-gamepad.axes[2] * 0.02);
    }
    if(gamepad.axes[2] > 0.20)
    {
        camera.rotateY(-gamepad.axes[2] * 0.02);
    }
}

Solution

  • The approach that PointerLockControls uses is to create a hierarchy of objects: yawObject contains pitchObject contains camera. Then horizontal mouse (or joystick) movement would change the Y-rotation of the yaw object, vertical mouse (or joystick) movement would change the X-rotation of the pitch object, and the camera's rotation would stay fixed at the default (0, 0, -1). This just manually simulates Euler YXZ ordering but it may work better for you. It does create some awkwardness if you need to get the overall rotation.

    In a custom controller I wrote recently, I achieved the same result by add()ing the camera to a single parent object and setting the parent object's Euler order to YXZ. I don't remember why this worked better than setting it on the camera directly, but it did.