Gamepad Camera Rotation Issue

Hi All,

I’m pretty new to babylon.js and learning all the features. I’m in the process of building a space scene with Planets, a ship, asteroid fields etc. All is going well apart from an issue with the camera now I’ve hooked it up to my gamepad.

The problem I am having is, once I have pressed button 5 or 6 and rotated the ship 90 degrees to the left or right using camera.rotation.z, the issue happens where camera.rotation.x and camera.rotation.y are now not relative to the camera rotation, they are still relative to the world.

So when I then use my left stick to rotate left for example, the ship rotates up instead of left and vice versa if I rotate right the ship rotates down.

I solved this on strafing Left, Right, Up, Down using addInPlace:
camera.cameraDirection.addInPlace(camera.getDirection(BABYLON.Vector3.Right()).scale(Math.abs(gamepad.rightStick.x / 100)));

However there doesn’t seem to be an equivalent to use once the camera has rotated around the Z axis. camera.rotation.x is always relative to the world and not the camera. What do i need to add to this to make X relative to the camera or at least when i push left to rotate left it goes left and not up?

I’m sure i’m missing something simple here, but i’m lost and going round in circles and nothing works.

Any help is much appreciated.

I don’t have a playground at the moment as I’ve just signed up, but ill create one if needed.

Thanks in advance.

gamepadManager.onGamepadConnectedObservable.add((gamepad, state) => {
gamepad.onButtonDownObservable.add((button, state) => {
//BUTTON PRESSED

                if (button == 5) {                        
                   camera.rotation.z += -0.01;                    
                }
                if (button == 4) {                       
                   camera.rotation.z += 0.01;                 
                }

            })
            scene.registerBeforeRender(function () {
                if (gamepad instanceof BABYLON.DualShockPad) {
                                            
                    if (gamepad.rightStick.y > 0.1 || gamepad.rightStick.y < -0.1) {
                        
                        setVal("control_thrusterXstate", (parseFloat(checkVal("control_thrusterXstate")) + gamepad.rightStick.y / (5000 / (parseFloat(checkVal("control_afterburner"))))));                            
                    }

                    if (gamepad.rightStick.x > 0.1) {                           
                        camera.cameraDirection.addInPlace(camera.getDirection(BABYLON.Vector3.Right()).scale(Math.abs(gamepad.rightStick.x / 100)));                            
                    }

                    if (gamepad.rightStick.x < -0.1) {                            
                        camera.cameraDirection.addInPlace(camera.getDirection(BABYLON.Vector3.Left()).scale(Math.abs(gamepad.rightStick.x / 100)));                                                        
                    }
                    
                    ****THIS IS WHERE I HAVE THE ISSUE
                    if (gamepad.leftStick.y > 0.2 || gamepad.leftStick.y < -0.2) {                                                                                  
                        camera.rotation.x += (gamepad.leftStick.y / 500) * -1; 
                    }

                    if (gamepad.leftStick.x > 0.1 || gamepad.leftStick.x < -0.1) {                            
                        camera.rotation.y += (gamepad.leftStick.x / 500);                            
                    }
                                            
                }
            });

Hello! It is a bit hard to say without a playground, but it sounds like you’re getting gimbal lock issues? This can happen when rotating a model by using euler angles (which is what rotation uses)


To avoid these issues, you can use quaternions instead (Babylon has methods for converting Quaternions to Euler angles and vice versa so no need to do the calculations yourself)

Hi Carol,

Thanks this does make a bit more sense, but i’m not sure where to start to correct it.

I’ve created a playground here so you can see it. If you rotate when it initially loads the Z rotation is 0 so everything is ok. However once you have rolled left or right the controls are skewed.

To recreate, roll to the left or right 90 degrees and use the left controls to move in a direction and you will see the camera follows the world X,Y,Z not the current camera orientation. When i rotate the camera on the Z axis, i always want rotation to be equivalent to the current camera Z rotation not the world, so left is left and right is right.

The right stick works as expected because its using the following methods to move Left, Right, Up or Down so Vector3.Left is calculated.

camera.cameraDirection.addInPlace(camera.getDirection(BABYLON.Vector3.Left()))

Is there an equivalent method for rotate up, down, left right? for example:

camera.cameraRotation.addInPlace(camera.getRotation(BABYLON.Vector3.Left()))

I know the above doesn’t exist, but is there something similar which will achieve the same?

I’m sure i’m missing something simple but i dont know what. :slight_smile:

Here are some images of what ive got so far:

Sorry, I think I misunderstood your issue then. Just to clarify, what you want is something like this?


So, you start like (1), where pressing the “right” button takes you to the camera -Z (which is the right), and pressing the roll and then the “right” button will now take you in the rotated camera -Z direction.

I’ll also tag @PolygonalSun here who knows a lot about cameras.

Basically yes. The camera is the view out of the front window of the ship, so I want left to always be left when I’m doing a rotation and right to be right.

Roll will always be Z so that’s fine, but when I rotate left it needs to account for the roll position I’m currently in and calculate left.

Thanks for your help so far.

1 Like

If you want to move relative to the camera space, then you add the camera’s position to the result of camera.getDirection. If you want to move relative to world space, then you just add the camera position: Babylon.js Playground (babylonjs.com)

For the camera rotation, I’d recommend trying the following:

let currentRotation;

if (gamepad.leftStick.y > 0.2 || gamepad.leftStick.y < -0.2) {
    // If we detect vertical movement, first get the current rotation, with respect to the camera's Yaw, Pitch, and Roll
    currentRotation = BABYLON.Quaternion.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, camera.rotation.z);
    // Next, create your rotation change quaternion
    let rotationChange = BABYLON.Quaternion.RotationAxis(BABYLON.Axis.X, ((gamepad.leftStick.y / 500) * -1));
    // Finally, apply your change to the currentRotation quaternion
    currentRotation.multiplyInPlace(rotationChange);
}

if (currentRotation) {
    currentRotation.toEulerAnglesToRef(camera.rotation); 
}

This code is essentially a slightly modified form of the rotation code that we use for mouse rotation. You can see this in action in this updated form of your PG: Camera Rotation Issue | Babylon.js Playground (babylonjs.com). Is this closer to what you were looking for?

1 Like

Hi Poly,

This is perfect, thank you. Works exactly as expected.

I would have never worked that out myself :slight_smile:

Thanks
Simon

1 Like