Select Git revision
-
David Sehnal authoredDavid Sehnal authored
camera.ts 9.56 KiB
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Mat4, Vec3, Vec4, EPSILON } from '../mol-math/linear-algebra'
import { Viewport, cameraProject, cameraUnproject } from './camera/util';
import { Object3D } from '../mol-gl/object3d';
import { BehaviorSubject } from 'rxjs';
import { CameraTransitionManager } from './camera/transition';
export { Camera }
// TODO: slab controls that modify near/far planes?
class Camera implements Object3D {
readonly updatedViewProjection = new BehaviorSubject<Camera>(this);
readonly view: Mat4 = Mat4.identity();
readonly projection: Mat4 = Mat4.identity();
readonly projectionView: Mat4 = Mat4.identity();
readonly inverseProjectionView: Mat4 = Mat4.identity();
readonly viewport: Viewport;
readonly state: Readonly<Camera.Snapshot> = Camera.createDefaultSnapshot();
readonly viewOffset: Camera.ViewOffset = {
enabled: false,
fullWidth: 1, fullHeight: 1,
offsetX: 0, offsetY: 0,
width: 1, height: 1
}
readonly transition: CameraTransitionManager = new CameraTransitionManager(this);
get position() { return this.state.position; }
set position(v: Vec3) { Vec3.copy(this.state.position, v); }
get direction() { return this.state.direction; }
set direction(v: Vec3) { Vec3.copy(this.state.direction, v); }
get up() { return this.state.up; }
set up(v: Vec3) { Vec3.copy(this.state.up, v); }
get target() { return this.state.target; }
set target(v: Vec3) { Vec3.copy(this.state.target, v); }
private prevProjection = Mat4.identity();
private prevView = Mat4.identity();
private deltaDirection = Vec3.zero();
private newPosition = Vec3.zero();
updateMatrices() {
const snapshot = this.state as Camera.Snapshot;
const height = 2 * Math.tan(snapshot.fov / 2) * Vec3.distance(snapshot.position, snapshot.target);
snapshot.zoom = this.viewport.height / height;
switch (this.state.mode) {
case 'orthographic': updateOrtho(this); break;
case 'perspective': updatePers(this); break;
default: throw new Error('unknown camera mode');
}
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON) || !Mat4.areEqual(this.view, this.prevView, EPSILON);
Mat4.mul(this.projectionView, this.projection, this.view)
Mat4.invert(this.inverseProjectionView, this.projectionView)