I have a task that I need to animate camera position and direction from current values to target values.
These target values are stored in a json format (I’ve verified they are correctly being fetched from the json file)
This code correctly animates the position from the current to the target position via tween.js , but not the target direction. The final direction never matches the target direction, and the final direction always depends on the starting conditions. (this should not be - desired behavior is for the direction to always match the target direction found in the json file, no matter the starting direction)
I have this working without animation as well
The animation code is below, with the working (non animated) code below it.
fetch('source.json')
.then(response => response.json())
.then(data => {
// Populate the menu buttons
data.menuItems.forEach(item => {
const menuButton = document.createElement('button');
menuButton.textContent = item.title;
menuButton.addEventListener('click', () => {
const { x: initialX, y: initialY, z: initialZ } = camera.position; // this is the intial camera position
const { x: finalX, y: finalY, z: finalZ } = item.cameraPosition; // this is the target camera position from json file
console.log("camera position(" + camera.position.x +","+camera.position.y+","+camera.position.z+")")
console.log("item.camera position (" +item.cameraPosition.x +","+item.cameraPosition.y+","+item.cameraPosition.z+")")
// Extract initial and final camera directions
const initialDirection = camera.getWorldDirection(new THREE.Vector3()); // this is the intial camera direction
const finalDirection = item.cameraDirection; // this is the final camera direction
console.log("camera direction(" + initialDirection.x +","+initialDirection.y+","+initialDirection.z+")")
console.log("finaldirection(" + finalDirection.x +","+finalDirection.y+","+finalDirection.z+")")
console.log("item.camera direction(" +item.cameraDirection.x +","+item.cameraDirection.y+","+item.cameraDirection.z+")")
controls.enabled = false;
const startTime = performance.now(); // Record start time
const tween = new TWEEN.Tween({ x: initialX, y: initialY, z: initialZ })
.to({ x: finalX, y: finalY, z: finalZ }, 1000)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(() => {
const currentTime = performance.now(); // Get current time
const elapsed = currentTime - startTime; // Calculate elapsed time
const progress = Math.min(elapsed / 500, 1); // Calculate progress (500 is the duration)
const interpolatedDirection = new THREE.Vector3().lerpVectors(initialDirection, finalDirection, progress);
// Log interpolated direction values to the console
console.log("Interpolated Direction:", interpolatedDirection.x, interpolatedDirection.y, interpolatedDirection.z);
camera.position.set(tween._object.x, tween._object.y, tween._object.z);
const targetPosition = interpolatedDirection.add(camera.position);
camera.lookAt(targetPosition);
//camera.lookAt(interpolatedDirection.add(camera.position)); //
})
.onComplete(() => {
//camera.lookAt(interpolatedDirection);
controls.enabled = true;
})
.start();
});
menuButtonsContainer.appendChild(menuButton);
});
})
.catch(error => console.error('Error fetching menu data:', error));
// Render loop
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
controls.update();
renderer.render(scene, camera);
}
animate();
working, non animated code:
fetch('source.json')
.then(response => response.json())
.then(data => {
// Populate the menu buttons
data.menuItems.forEach(item => {
const menuButton = document.createElement('button');
menuButton.textContent = item.title;
menuButton.addEventListener('click', () => {
const { x, y, z } = item.cameraPosition;
const { x: dirX, y: dirY, z: dirZ } = item.cameraDirection;
camera.position.set(x, y, z);
const direction = new THREE.Vector3(dirX, dirY, dirZ);
camera.lookAt(direction.add(camera.position));
});
menuButtonsContainer.appendChild(menuButton);
});
})
.catch(error => console.error('Error fetching menu data:', error));