Fix: Deterministic camera transitions
- Refactored setCameraView to use precise lookAt and position calculation instead of accumulating quaternion errors. - Forces camera UP vector (0,1,0) to prevent roll drift during isometric rotation.
This commit is contained in:
51
src/main.js
51
src/main.js
@@ -362,18 +362,16 @@ function setCameraView(direction, animate = true) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcular offset de la vista (diferencia entre posición y target)
|
// Calcular offset de la vista (diferencia entre posición y target definidos en CAMERA_VIEWS)
|
||||||
const viewOffset = view.position.clone().sub(view.target);
|
const viewOffset = view.position.clone().sub(view.target);
|
||||||
|
|
||||||
// Nueva posición de cámara centrada en el jugador
|
// Nueva posición de cámara centrada en el jugador
|
||||||
const newPosition = playerPosition.clone().add(viewOffset);
|
const targetPosition = playerPosition.clone().add(viewOffset);
|
||||||
const newTarget = playerPosition.clone();
|
const targetLookAt = playerPosition.clone();
|
||||||
|
|
||||||
if (animate && SESSION.currentView !== direction) {
|
if (animate && SESSION.currentView !== direction) {
|
||||||
// Animación suave de transición
|
const startPosition = camera.position.clone();
|
||||||
const startPos = camera.position.clone();
|
const startLookAt = controls.target.clone();
|
||||||
const startQuat = camera.quaternion.clone();
|
|
||||||
const startTarget = controls.target.clone();
|
|
||||||
|
|
||||||
const duration = 600; // ms
|
const duration = 600; // ms
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
@@ -382,48 +380,47 @@ function setCameraView(direction, animate = true) {
|
|||||||
const elapsed = Date.now() - startTime;
|
const elapsed = Date.now() - startTime;
|
||||||
const progress = Math.min(elapsed / duration, 1);
|
const progress = Math.min(elapsed / duration, 1);
|
||||||
|
|
||||||
// Easing suave (ease-in-out)
|
// Easing suave
|
||||||
const eased = progress < 0.5
|
const eased = progress < 0.5
|
||||||
? 2 * progress * progress
|
? 2 * progress * progress
|
||||||
: 1 - Math.pow(-2 * progress + 2, 2) / 2;
|
: 1 - Math.pow(-2 * progress + 2, 2) / 2;
|
||||||
|
|
||||||
// Interpolar posición
|
// Interpolación LINEAL de posición y target
|
||||||
camera.position.lerpVectors(startPos, newPosition, eased);
|
const currentPos = new THREE.Vector3().lerpVectors(startPosition, targetPosition, eased);
|
||||||
|
const currentLookAt = new THREE.Vector3().lerpVectors(startLookAt, targetLookAt, eased);
|
||||||
|
|
||||||
// Interpolar quaternion (rotación suave)
|
camera.position.copy(currentPos);
|
||||||
camera.quaternion.slerpQuaternions(startQuat, view.quaternion, eased);
|
camera.up.set(0, 1, 0); // FORZAR UP VECTOR SIEMPRE
|
||||||
|
camera.lookAt(currentLookAt);
|
||||||
|
|
||||||
// Interpolar target
|
controls.target.copy(currentLookAt);
|
||||||
controls.target.lerpVectors(startTarget, newTarget, eased);
|
|
||||||
|
|
||||||
camera.up.copy(view.up);
|
|
||||||
controls.update();
|
controls.update();
|
||||||
|
|
||||||
if (progress < 1) {
|
if (progress < 1) {
|
||||||
requestAnimationFrame(animateTransition);
|
requestAnimationFrame(animateTransition);
|
||||||
} else {
|
} else {
|
||||||
// Asegurar valores finales exactos
|
// Asegurar estado final perfecto
|
||||||
camera.position.copy(newPosition);
|
camera.position.copy(targetPosition);
|
||||||
camera.quaternion.copy(view.quaternion);
|
camera.up.set(0, 1, 0);
|
||||||
camera.up.copy(view.up);
|
camera.lookAt(targetLookAt);
|
||||||
controls.target.copy(newTarget);
|
controls.target.copy(targetLookAt);
|
||||||
controls.update();
|
controls.update();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
animateTransition();
|
animateTransition();
|
||||||
} else {
|
} else {
|
||||||
// Sin animación (cambio instantáneo)
|
// Cambio inmediato
|
||||||
camera.position.copy(newPosition);
|
camera.position.copy(targetPosition);
|
||||||
camera.quaternion.copy(view.quaternion);
|
camera.up.set(0, 1, 0); // FORZAR UP VECTOR
|
||||||
camera.up.copy(view.up);
|
camera.lookAt(targetLookAt);
|
||||||
controls.target.copy(newTarget);
|
controls.target.copy(targetLookAt);
|
||||||
controls.update();
|
controls.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
SESSION.currentView = direction;
|
SESSION.currentView = direction;
|
||||||
updateCompassUI();
|
updateCompassUI();
|
||||||
updateWallOpacities(); // Actualizar opacidades de paredes según nueva vista
|
updateWallOpacities();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establecer vista inicial
|
// Establecer vista inicial
|
||||||
|
|||||||
Reference in New Issue
Block a user