I am currently trying to move my camera smoothly towards a a 3D Coordinate belonging to a sphere. What I want to achieve is that the camera stops at a certain distance in front of my sphere while directly looking at my sphere. I tried many hours but I couldn´t get it done. It is also import to mention that I am using Orbit Controls in addition. The camera is pretty close but my sphere never appears in the center. I am pretty new when it comes to threejs so I appreciate any help steering me in the right direction.
Here is my code so far:
if (foundElement) {
const [xCoord, yCoord, zCoord] = foundElement["coordinate"];
foundElementCoords.current.set(xCoord, yCoord, zCoord);
controls.enabled = false;
// Define the distance to be away from the sphere
let distance = 0.5;
// Calculate position that's 'distance' units away from the sphere along the line from the camera to the sphere
let direction = new THREE.Vector3().subVectors(
camera.position,
foundElementCoords.current
);
let targetPosition = foundElementCoords.current
.clone()
.add(direction.normalize().multiplyScalar(distance));
// Create a quaternion for the target rotation
let targetQuaternion = new THREE.Quaternion().setFromRotationMatrix(
new THREE.Matrix4().lookAt(
camera.position,
foundElementCoords.current,
camera.up
)
);
let startQuaternion = camera.quaternion.clone();
new TWEEN.Tween(camera.position)
.to(targetPosition, 2000) // Move to the target position in 2000ms
.onUpdate(() => {
camera.lookAt(foundElementCoords.current);
controls.current.update();
})
.onComplete(() => {
camera.lookAt(foundElementCoords.current);
controls.current.update();
})
.start(); // Start the position tween
// new TWEEN.Tween(camera.quaternion)
// .to(targetQuaternion, 2000) // Rotate to target in 2000ms
// .onUpdate(() => {
// camera.lookAt(foundElementCoords.current);
// controls.current.update();
// })
// .onComplete(() => {
// camera.lookAt(foundElementCoords.current);
// controls.current.update();
// })
// .start(); // Start the rotation tween
controls.enabled = true;
}
}
To correct your code and make the camera move smoothly towards the sphere while keeping it centered correctly, you need to ensure that the camera both moves and rotates to face the sphere simultaneously. try this code :
if (foundElement) {
const [xCoord, yCoord, zCoord] = foundElement["coordinate"];
foundElementCoords.current.set(xCoord, yCoord, zCoord);
controls.enabled = false;
// Define the distance to be away from the sphere
let distance = 0.5;
// Calculate position that's 'distance' units away from the sphere along the line from the camera to the sphere
let direction = new THREE.Vector3().subVectors(
camera.position,
foundElementCoords.current
);
let targetPosition = foundElementCoords.current
.clone()
.add(direction.normalize().multiplyScalar(distance));
// Create a quaternion for the target rotation
let targetQuaternion = new THREE.Quaternion().setFromRotationMatrix(
new THREE.Matrix4().lookAt(
targetPosition, // Target position is where the camera should be
foundElementCoords.current, // The point the camera should look at
camera.up
)
);
let startQuaternion = camera.quaternion.clone();
// Move the camera position
new TWEEN.Tween(camera.position)
.to(targetPosition, 2000) // Move to the target position in 2000ms
.easing(TWEEN.Easing.Quadratic.Out) // Smooth easing
.onUpdate(() => {
// This will handle camera lookAt smoothly
camera.lookAt(foundElementCoords.current);
controls.update();
})
.onComplete(() => {
// Make sure camera is still looking at the target when done
camera.lookAt(foundElementCoords.current);
controls.update();
})
.start(); // Start the position tween
// Rotate the camera to look at the target smoothly
new TWEEN.Tween(camera.quaternion)
.to(targetQuaternion, 2000) // Rotate to target in 2000ms
.easing(TWEEN.Easing.Quadratic.Out) // Smooth easing
.onUpdate(() => {
controls.update(); // Ensure controls are updated during rotation
})
.onComplete(() => {
controls.update(); // Ensure controls are updated after rotation
})
.start(); // Start the rotation tween
controls.enabled = true;
}
I already tried to make it work only using controls.target. Nevertheless, I couldn´t make it work past.
If I got you right I need to tween the camera position and the controls.target:
if (foundElement) {
const [xCoord, yCoord, zCoord] = foundElement["coordinate"];
foundElementCoords.current.set(xCoord, yCoord, zCoord);
// Define the distance to be away from the sphere
let distance = 0.5;
// Calculate position that's 'distance' units away from the sphere along the line from the camera to the sphere
let direction = new THREE.Vector3().subVectors(
camera.position,
foundElementCoords.current
);
let targetPosition = foundElementCoords.current
.clone()
.add(direction.normalize().multiplyScalar(distance));
controls.current.disable;
// Move the camera position
new TWEEN.Tween(camera.position)
.to(targetPosition, 2000) // Move camera to target position
.easing(TWEEN.Easing.Quadratic.Out)
.onUpdate(() => {
camera.lookAt(foundElementCoords.current);
})
.onComplete(() => {
camera.lookAt(foundElementCoords.current);
})
.start(); // Start the position tween
// Move the controls target
new TWEEN.Tween(controls.current.target)
.to(foundElementCoords.current, 2000)
.easing(TWEEN.Easing.Quadratic.Out)
.onUpdate(() => {
controls.current.update();
})
.onComplete(() => {
controls.current.update();
})
.start();
controls.current.enable;
}
Again, I end up pretty close but my sphere still does not appear in the center, so that when the distance it set to a too small value my sphere is not in the field of view anymore.
Did I miss something? Really appreciate your help.