Hello, I realise this is solved however I thought I would supply another method as I was told that the up direction is not the “appropriate” way to modify when using ArcBallController. However each to their own I have no motive apart from a code share.
function rollCamera(axis, radians) {
//check the axis and set the vector
let vector = new Vector3(0, 0, 1);
if (axis === "Z") {
vector = new Vector3(0, 0, 1);
} else if (axis === "Y") {
vector = new Vector3(0, 1, 0);
} else if (axis === "X") {
vector = new Vector3(1, 0, 0);
} else {
vector = new Vector3(0, 0, 1);
}
if (controls instanceof ArcballControls) {
// Get the vector from the camera to the target (controls.target)
const direction = new THREE.Vector3().subVectors(camera.position, controls.target).normalize();
// Create a quaternion representing the rotation around the Z axis
const quaternion = new THREE.Quaternion();
quaternion.setFromAxisAngle(vector, radians);
// Rotate the direction vector
direction.applyQuaternion(quaternion);
// Calculate the new position of the camera
const distance = camera.position.distanceTo(controls.target);
const newPosition = new THREE.Vector3().addVectors(controls.target, direction.multiplyScalar(distance));
// Apply the new position and up vector to the camera
camera.position.copy(newPosition);
camera.up.applyQuaternion(quaternion);
// Look at the target
camera.lookAt(controls.target);
// Update the camera's matrix and the controls
camera.updateMatrixWorld();
controls.update();
} else if (controls instanceof TrackballControls) {
//store the current camera position
const position = controls.object.position.clone();
// Store the current look at target
const target = controls.target.clone();
// Get the camera's local Z-axis (up direction)
const cameraMatrix = new THREE.Matrix4();
cameraMatrix.lookAt(position, target, controls.object.up);
const cameraLocalZAxis = vector.applyMatrix4(cameraMatrix);
// Rotate the camera around its local Z-axis (up direction)
controls.object.up.applyAxisAngle(cameraLocalZAxis, radians);
// Update the controls
controls.update();
}
}
I’m calling this function from a lil-gui slider at the moment.
const upOptions = ["X", "Y", "Z"];
gui.add(params, "upDirection", upOptions).name("Up Direction Axis").onChange(function() {
switch (params.upDirection) {
case "Y":
camera.up.set(0, 1, 0);
break;
case "X":
camera.up.set(1, 0, 0);
break;
case "Z":
camera.up.set(0, 0, 1);
break;
}
camera.updateProjectionMatrix();
});
// Store the previous rotation angle
let prevRotationAngle = params.rotationAngle;
// Add a slider for rotation angle in degrees
gui.add(params, "rotationAngle", 0, 360).name("View Angle (°)").onChange(function() {
// Calculate the delta rotation angle
const deltaAngle = params.rotationAngle - prevRotationAngle;
// Convert delta angle to radians
const deltaAngleRad = THREE.MathUtils.degToRad(deltaAngle);
// Update the previous rotation angle
prevRotationAngle = params.rotationAngle;
// Call the rollCamera function with the delta angle in radians
const axis = params.upDirection;
rollCamera(axis, 0);
rollCamera(axis, deltaAngleRad);
});
Hoping this helps others search to do this.
Here is a little GIF that shows it in action.