Camera focus while orbiting as well

var CameraViewHandler = pc.createScript('cameraViewHandler');

CameraViewHandler.attributes.add('rearViewBtn', { type: 'entity' });
CameraViewHandler.attributes.add('glassBtn', { type: 'entity' });
CameraViewHandler.attributes.add('bumperBtn', { type: 'entity' });
CameraViewHandler.attributes.add('bodyBtn', { type: 'entity' });
CameraViewHandler.attributes.add('camera', { type: 'entity' });

CameraViewHandler.prototype.initialize = function() {
    this._orbitCamera = this.camera.script.orbitCamera;
    

    this._transitioning = false;
    this._transitionDuration = 1;
    this._elapsedTime = 0;

    // Store initial camera transform when transition starts
    this._startPosition = new pc.Vec3();
    this._startRotation = new pc.Quat();

    this._setupButtonListeners();
};

CameraViewHandler.prototype._setupButtonListeners = function() {
    const buttons = [
        { btn: this.rearViewBtn, fn: this.moveToRearView },
        { btn: this.glassBtn, fn: this.moveToGlassView },
        { btn: this.bumperBtn, fn: this.moveToBumperView },
        { btn: this.bodyBtn, fn: this.moveToBodyView }
    ];

    buttons.forEach(({ btn, fn }) => {
        if (btn && btn.button) {
            btn.button.on('click', () => {
                if (!this._transitioning) fn.call(this);
            });
        }
    });
};

// View configuration objects
const VIEWS = {
    rear: {
        pos: new pc.Vec3(-16, 3, 2.5),
        rot: new pc.Vec3(-0.6, -82, 0)
    },
    glass: {
        pos: new pc.Vec3(-19, 4, 1),
        rot: new pc.Vec3(357, -90, 0)
    },
    bumper: {
        pos: new pc.Vec3(0.56, 0.575, -35),
        rot: new pc.Vec3(-180, 0, -180)
    },
    body: {
        pos: new pc.Vec3(-20, 3.5, 17.7),
        rot: new pc.Vec3(-5.8, -27.2, 0)
    }
};

CameraViewHandler.prototype.moveToRearView = function() { this._startTransition(VIEWS.rear); };
CameraViewHandler.prototype.moveToGlassView = function() { this._startTransition(VIEWS.glass); };
CameraViewHandler.prototype.moveToBumperView = function() { this._startTransition(VIEWS.bumper); };
CameraViewHandler.prototype.moveToBodyView = function() { this._startTransition(VIEWS.body); };

CameraViewHandler.prototype._startTransition = function(viewConfig) {
    if (this._transitioning) return;

    // Store initial transform at transition start
    this._startPosition.copy(this.camera.getLocalPosition());
    this._startRotation.copy(this.camera.getRotation());

    // Convert target rotation to quaternion
    this._targetRotation = new pc.Quat().setFromEulerAngles(
        viewConfig.rot.x,
        viewConfig.rot.y,
        viewConfig.rot.z
    );
    this._targetPosition = viewConfig.pos.clone();

    this._orbitCamera.enabled = false; // Disable orbit camera to control transition manually
    this._transitioning = true;
    this._elapsedTime = 0;
};

CameraViewHandler.prototype.update = function(dt) {
    if (!this._transitioning) return;

    this._elapsedTime += dt;
    const t = Math.min(this._elapsedTime / this._transitionDuration, 1);

    // Smoothly interpolate position and rotation
    const newPos = new pc.Vec3().lerp(this._startPosition, this._targetPosition, t);
    const newRot = new pc.Quat().slerp(this._startRotation, this._targetRotation, t);

    // Apply new transforms
    this.camera.setLocalPosition(newPos);
    this.camera.setRotation(newRot);

    // Finalize transition when complete
    if (t >= 1) {
        this._transitioning = false;

        // Ensure exact final position/rotation and apply
        this.camera.setLocalPosition(this._targetPosition);
        this.camera.setRotation(this._targetRotation);

        // After the transition, lock the camera in place at the final position and rotation
        this._orbitCamera.enabled = true;  // Enable orbit camera for rotation only (position is fixed)

        // Optionally, you can use resetAndLookAtPoint here to ensure the camera stays locked at the final position
        this._resetAndLookAtFinalPosition();
    }
};

// This function resets the camera and makes sure it stays at the desired position and rotation
CameraViewHandler.prototype._resetAndLookAtFinalPosition = function() {
    if (this._targetPosition && this._targetRotation) {
        const targetPos = new pc.Vec3(this._targetPosition.x, this._targetPosition.y, this._targetPosition.z);
        const targetRot = new pc.Quat(this._targetRotation.x, this._targetRotation.y, this._targetRotation.z, this._targetRotation.w);

        // Reset the orbit camera and make it look at the final position
        this._orbitCamera.resetAndLookAtPoint(targetPos, targetRot);
    }
};

Hey i got this code for my playcanvas project

Project Overview: I have a PlayCanvas project with a 3D car model and UI buttons that let users switch between different views (e.g., Rear View, Glass View, etc.). When a button is clicked, the camera animates smoothly to the selected view. I also have an Orbit Camera script that allows the user to rotate the car, which gets disabled during the animation and re-enabled once it finishes.

Problem: While the camera transitions smoothly to the target view, the issue occurs after the animation finishes:

  1. The camera feels like it jerks or snaps when it reaches the target position, instead of smoothly locking into place.
  2. There’s a discrepancy between the intended final position and where the camera actually settles.

Expected Behavior:

  • Camera smoothly locks in place at the target position after the animation.
  • Orbit camera is re-enabled once the animation completes without any jerking or snapping.

Attempts to Fix:

  • I’ve tried using lerp and slerp for smooth transitions, locking the camera after the animation, and disabling/enabling the Orbit Camera during the transition. Despite these fixes, the camera still doesn’t settle smoothly at the target position.

Request: Any suggestions on how to fix the smooth transition and ensure the camera locks in place without snapping after the animation?

https://playcanvas.com/editor/scene/2192101