UNPKG

threepipe

Version:

A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.

109 lines 4.18 kB
import { Quaternion, Spherical, Vector3 } from 'three'; import { worldToLocalQuaternion } from '../three/utils'; import { lerp, lerpAngle } from './animation'; export function sphericalFromCameraView(view) { const pos = view.position.clone(); pos.sub(view.target); const spherical = new Spherical().setFromVector3(pos); spherical.makeSafe(); // todo: is it needed? return spherical; } export function animateCameraToViewSpherical(camera, view) { // similar to orbit controls const parent = camera.parent; const target = camera.target.clone(); const position = camera.getWorldPosition(new Vector3()); const init = { position, target, zoom: camera.zoom, spherical: sphericalFromCameraView({ position, target }), }; const current = { position: new Vector3(), target: new Vector3(), zoom: 1, spherical: new Spherical(), }; const final = { position: view.position, target: view.target, zoom: view.zoom, spherical: sphericalFromCameraView(view), }; function setter() { camera.position.copy(parent ? parent.worldToLocal(current.position) : current.position); camera.target.copy(current.target); // always in world space camera.zoom = current.zoom; // lookAt in setDirty updates the quaternion camera.setDirty(); // because it has min change distance in setter } return { from: 0, to: 1, onUpdate: (v) => { current.spherical.phi = lerpAngle(init.spherical.phi, final.spherical.phi, v); current.spherical.theta = lerpAngle(init.spherical.theta, final.spherical.theta, v); current.spherical.radius = lerp(init.spherical.radius, final.spherical.radius, v); current.target.copy(init.target).lerp(final.target, v); current.position.setFromSpherical(current.spherical); current.position.add(current.target); current.zoom = lerp(init.zoom, final.zoom, v); setter(); }, onComplete: () => { current.position.copy(final.position); current.target.copy(final.target); current.zoom = final.zoom; setter(); }, onStop: () => { throw new Error('Animation Stopped'); }, }; } export function animateCameraToViewLinear(camera, view) { // similar to orbit controls // so camera.up is the orbit axis const parent = camera.parent; const target = camera.target.clone(); const position = camera.getWorldPosition(new Vector3()); const quaternion = camera.getWorldQuaternion(new Quaternion()); const init = { position, target, quaternion, zoom: camera.zoom, }; const current = { position: new Vector3(), target: new Vector3(), quaternion: new Quaternion(), zoom: 1, }; const final = view; function setter() { camera.position.copy(parent ? parent.worldToLocal(current.position) : current.position); camera.target.copy(current.target); // always in world space camera.quaternion.copy(parent ? worldToLocalQuaternion(parent, current.quaternion, camera.quaternion) : current.quaternion); camera.zoom = current.zoom; camera.setDirty(); // because it has min change distance in setter } return { from: 0, to: 1, onUpdate: (v) => { current.position.lerpVectors(init.position, final.position, v); current.target.lerpVectors(init.target, final.target, v); current.quaternion.slerpQuaternions(init.quaternion, final.quaternion, v); current.zoom = lerp(init.zoom, final.zoom, v); setter(); }, onComplete: () => { current.position.copy(final.position); current.target.copy(final.target); current.quaternion.copy(final.quaternion); current.zoom = final.zoom; setter(); }, onStop: () => { throw new Error('Animation Stopped'); }, }; } //# sourceMappingURL=camera-anim.js.map