Controlling RotationQuaternion via Touch input

I am trying to configure my code so that it works well on IPad in addition to desktop. I am working on creating custom controls based on Device input. When it comes to Touch, I am at a loss for how to create a custom controller for rotating the camera, especially since I am using a rotationQuaternion instead of rotation.

I created this playground to isolate the issue.
The relevant lines are 8, 124, and 128.

https://playground.babylonjs.com/#L92PHY#135

As you can see, if I use the rotationQuaternion and adjust it based on the deviceData.currentState vs deviceData.previousState difference, the camera rotates awkwardly and also hits a rotation limit at about 180 degrees either way.

Does anyone know how I can get around this?

Thanks in advance!

Hi @johntdaly7,

If I understand you correctly, you want camera view to look up and down when a finger is panning vertically, and to rotate around y axis of camera’s current position when finger panning horizontally?

Then you shouldn’t change the rotation of camera. You should change the target of the camera. You can play with the camera target in the babylon inspector.

Hello! Would the TouchCamera work for your use case?

PIP Camera Visual Demo | Babylon.js Playground (babylonjs.com)

@PolygonalSun might also be able to help here ?

Hey @johntdaly7, is there any particular reason why you’re using rotationQuaternion instead of rotation?

Hey @PolygonalSun! Yes, because I am using rotationQuaternion for some animations to seamlessly transition between Universal/Free camera and ArcRotateCamera, aligning them both with camera anchors’ orientations from the glb model.

Yes, that is what I want to do. I tried making use of your tip, but using, for instance, this:

camera.setTarget(camera.getTarget().x + ((deviceData.currentState - deviceData.previousState) * 0.005), camera.getTarget().y, camera.getTarget().z);

throws an error e.subtract is not a function in setTarget.

yet (deviceData.currentState - deviceData.previousState) * 0.005 works fine outside of it.

How do you suggest dynamically adjusting the target?

Thanks for the suggestion, but that actually doesn’t work because it moves the camera forward and back when sliding finger up and down across the screen. I just need rotation across the x axis when moving finger up and down and rotation across the y axis when moving finger left and right. Which seems to mean I need to create my own camera inputs/functions with the device manager, but the rotation controls are a bit weird due to my need to utilizing the rotationQuaternion.

Well, the reason for the behavior that I’m seeing is because you’re changing the rotationQuaternion x and y, which will technically rotate the camera but you’d also need to modify the w (4th) parameter as well. You could probably forego this completely by converting your rotationQuaternion to a vector of Euler angles, modifying them, converting them back to a Quaternion, and copying them back to your rotationQuaternion:

device.onInputChangedObservable.add((deviceData) => {
    let changed = false;
    let rot = camera.rotationQuaternion.toEulerAngles();
    if (deviceData.inputIndex === BABYLON.PointerInput.Horizontal && device.getInput(BABYLON.PointerInput.LeftClick) === 1) {
        rot.y += (deviceData.currentState - deviceData.previousState) * 0.005;
        changed = true;
    }

    if (deviceData.inputIndex === BABYLON.PointerInput.Vertical && device.getInput(BABYLON.PointerInput.LeftClick) === 1) {
        rot.x += (deviceData.currentState - deviceData.previousState) * 0.005;
        changed = true;
    }

    if (changed) {
        camera.rotationQuaternion = rot.toQuaternion();
    }
});

I’m sure that there’s a much more elegant way to do this. This is just the first idea that comes to mind.

Ah, lovely! That’s kind of the solution I was hoping for. (I’m terrible with quaternions and always get confused with the conversions so I’m glad you just introduced me to a built in function that handles that! I’ll give this a shot. Thanks!

Update: Works like a charm. Thanks!

Hi @johntdaly7

You don’t add delta to the target. Take the horizontal move as example. A user action basically trigger a change to the degree around y-axis on camera’s current position. You can imagine your camera position is the center of a circle. Camera target is a position on the circle. Your user action triggers a move of the target from position a to position b on the circle.

Then the problem becomes:

  • You know the center of a circle (your camera position)
  • You know the radius of the circle (you can use a constant value for it)
  • You know the degree d around y axis (you know the initial degree and how much a user action moved it)

You want to calculate the position on the circle that points toward degree d from the center of circle. You can set the this position on the circle as your camera target.