Update rotation of an object with orbit controls

Hello ThreeJS Community!

I am currently working on a clone of three js editor and recently I updated the EditorControls.js script to add damping in rotation and panning, to give the user a better experience while working with the camera in Editor. This script now resembles the OrbitControls.js script and implements rotation in same way as OrbitControls does.

I want to allow the user to be able to set the rotation vector of the camera that is active in the editor such as [x: 10, y: -5, z: 4] but whenever I try to update the rotation, it gets overridden by the EditorControls, similarly as it does in OrbitControls, and the values are reset by the update function in the script. I’ve tried the following approach:

  • Disable the update function by setting this.enabled = false
  • Resetting the values used by the update function
  • Setting the rotation
  • Enabling the update function

Below are the code snippets:
Code to be run when user update the rotation values from editor:

editor.signals.objectChanged.add(function (object, newRotation) {

		if (object.uuid !== scope.camera.uuid || newRotation == undefined)
			return;
		console.log("object: ", object);
		scope.enabled = false;
		reset();
		console.log("newRotation: ", newRotation);
		scope.camera.rotation.copy(newRotation);
		scope.camera.updateMatrixWorld( true );

		scope.enabled = true;
		// scope.update();
		// controller.updateObject( object );

	});

Reset function:

function reset() {
		center = new THREE.Vector3();
		scope.rotateDelta = new THREE.Vector2();
		scope.rotateEnd = new THREE.Vector2();
		scope.rotateStart = new THREE.Vector2();
		scope.sphericalDelta = new THREE.Spherical();
		quat = new Quaternion().setFromUnitVectors(scope.camera.up, new THREE.Vector3(0, 1, 0));
		quatInverse = quat.clone().invert();

		lastPosition = new THREE.Vector3();
		lastQuaternion = new Quaternion();
		vector = new THREE.Vector3();
		scope.camera.updateProjectionMatrix();

		// scope.update();

		state = STATE.NONE;
	}

rotate function:

this.rotate = function (event) {

		this.rotateEnd.set(event.clientX, event.clientY);

		this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart).multiplyScalar(this.rotationSpeed);

		var element = domElement;

		rotateLeft(2 * Math.PI * this.rotateDelta.x / element.clientHeight); // yes, height

		rotateUp(2 * Math.PI * this.rotateDelta.y / element.clientHeight);

		this.rotateStart.copy(this.rotateEnd);

		scope.dispatchEvent(changeEvent);
		setOrientation(this);

	};

Update function:

this.update = function () {



		return function update(delta) {

			if (this.enabled === false) return;

			if (!logicBlockToggle) {
				// var actualMoveSpeed = delta * this.movementSpeed;
				// var prevPos = this.camera.position.clone();

				// if (this.moveForward || (this.autoForward && !this.moveBackward)) this.camera.translateZ(- (actualMoveSpeed + this.autoSpeedFactor));
				// if (this.moveBackward) this.camera.translateZ(actualMoveSpeed);

				// if (this.moveLeft) this.camera.translateX(- actualMoveSpeed);
				// if (this.moveRight) this.camera.translateX(actualMoveSpeed);

				// if (this.moveUp) this.camera.translateY(actualMoveSpeed);
				// if (this.moveDown) this.camera.translateY(- actualMoveSpeed);

				// center.add(this.camera.position.clone().sub(prevPos));

				// if (this.moveForward || this.moveBackward || this.moveLeft || this.moveRight || this.moveUp || this.moveDown) {

				// 	var actualLookSpeed = this.lookSpeed * delta;

				// 	lon -= this.mouseX * actualLookSpeed;
				// 	lat -= this.mouseY * actualLookSpeed;

				// 	lat = Math.max(- 85, Math.min(85, lat));

				// 	var phi = THREE.MathUtils.degToRad(90 - lat);
				// 	var theta = THREE.MathUtils.degToRad(lon);

				// 	vector.setFromSphericalCoords(1, phi, theta).add(this.camera.position);

				// 	this.camera.lookAt(vector);
				// }

				this.applyKeyBoardMovement();

			}

			vector.copy(this.camera.position).sub(center);

			vector.applyQuaternion(quat);

			spherical.setFromVector3(vector);

			if (this.heightSpeed) {

				var y = THREE.MathUtils.clamp(this.camera.position.y, this.heightMin, this.heightMax);
				var heightDelta = y - this.heightMin;

				this.autoSpeedFactor = delta * (heightDelta * this.heightCoef);

			} else {

				this.autoSpeedFactor = 0.0;

			}

			if (this.enableDamping) {
				spherical.theta += sphericalDelta.theta * this.dampingFactor;
				spherical.phi += sphericalDelta.phi * this.dampingFactor
			}

			else {
				spherical.theta += sphericalDelta.theta;
				spherical.phi += sphericalDelta.phi
			}

			spherical.makeSafe();
			if (this.enableDamping === true) {

				center.addScaledVector(panOffset, this.dampingFactor);

			} else {

				center.add(panOffset);

			}
			spherical.radius *= scale;
			spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
			vector.setFromSpherical(spherical);

			vector.applyQuaternion(quatInverse);

			this.camera.position.copy(center).add(vector);

			this.camera.lookAt(center);



			scale = 1;

			if (zoomChanged ||
				lastPosition.distanceToSquared(this.camera.position) > EPS ||
				8 * (1 - lastQuaternion.dot(this.camera.quaternion)) > EPS) {

				// scope.dispatchEvent(changeEvent);

				lastPosition.copy(this.camera.position);
				lastQuaternion.copy(this.camera.quaternion);
				zoomChanged = false;

				// return true;

			}

			if (this.enableDamping) {
				sphericalDelta.theta *= (1 - this.dampingFactor);
				sphericalDelta.phi *= (1 - this.dampingFactor);
				panOffset.multiplyScalar(1 - scope.dampingFactor);
			}
			else {
				sphericalDelta.set(0, 0, 0);
				panOffset.set(0, 0, 0);
			}


			this.smoothZoomUpdate();
		};

	}();

Looking forward to receiving your valuable advice.

1 Like

Yes, while OrbitControls (and possibly your EditorControls) is active, it will override any manual camera modification.

Have you tried to let the EditorControls control the camera, but in a way that you want it. For example, instead of rotating the camera by yourself, you move the target of the EditorControls, and as a result it moves the camera to point to the new target. This is, the EditorControls is used as a fire iron.

That’s a pretty effective solution. Can you guide me on how can I get the point to look at when provided with a rotation vector?

Here is an example. The camera is a 3D object which is rotated randomly every 2 seconds – see function randomizeCamera at lines 82-93. This function also calculates a point along the camera’s forward direction:

forward.set( 0, 10, 0 );
cameraObject.localToWorld( forward );

Note: the demo assumes the forward direction is along Y+ axis. If your EditorCobtrols uses another forward direction, e.g. Z-, then change the initial value, e.g. (0,0,-1).

The main animation loop moves the red object towards the last calculated forward position. This motion is only for visual effect.

https://codepen.io/boytchev/full/qBMwXLM

image

1 Like