Proper way to extend OrbitControls to support camera roll

Hello everyone, I’m attempting to implement a simple touch rotate gesture that extends the OrbitControls allowing for the camera to be rolled to the left and to the right.

Rolling the camera based on event.touches is simple, just a matter of applying camera.rotation.set, but I’m struggling to understand how to keep the camera in the new roll position since OrbitControls take over and reset the rotation at any subsequent interaction.

Is the only way to implement a new method in the OrbitControls to handle roll and create a new camera roll state alongside all the other states of OrbitControls so the rotation is not overwritten? Or is there something simpler?

Simple JSFiddle that shows what I want to do: https://jsfiddle.net/jacopocolo/eb95zg7m/10/ (the code is pretty simple so maybe this is not necessary but: the effect is only visible on touch devices and with multitouch gestures)

Thanks!

Did you try changing camera.up ? OrbitControls resets rotation to always fit the upwards vector (src), so this may be an easier workaround.

1 Like

Adjusting the camera.up works somewhat but not as well as I’d like. What I’m doing is very simply:

camera.up = new THREE.Vector3(camera.up.x, camera.up.y, camera.up.z).applyMatrix4(new THREE.Matrix4().makeRotationX(rotation)).

this approach works okay almost everywhere except when the camera is perfectly aligned with one axis, which is a case that is very common in the work I’m doing. When the camera is aligned with one axis there’s no visible rotation, just a “snap” between the two values. Not really sure why, but it seems like the closer you are to an axis the more the rotation is applied exponentially. I’m also using an orthographic camera which might have an impact on this.