Skip to content
Snippets Groups Projects
Commit 21ce146d authored by Alexander Rose's avatar Alexander Rose
Browse files

unified perpective/orthographic matrix creation signature

parent e70f62af
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* 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>
......@@ -25,6 +25,12 @@ class Camera implements Object3D {
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);
......@@ -143,6 +149,30 @@ namespace Camera {
fogFar: number
}
/**
* Sets an offseted view in a larger frustum. This is useful for
* - multi-window or multi-monitor/multi-machine setups
* - jittering the camera position for
*/
export interface ViewOffset {
enabled: boolean,
fullWidth: number,
fullHeight: number,
offsetX: number,
offsetY: number,
width: number,
height: number
}
export function setViewOffset(out: ViewOffset, fullWidth: number, fullHeight: number, offsetX: number, offsetY: number, width: number, height: number) {
out.fullWidth = fullWidth
out.fullHeight = fullHeight
out.offsetX = offsetX
out.offsetY = offsetY
out.width = width
out.height = height
}
export function createDefaultSnapshot(): Snapshot {
return {
mode: 'perspective',
......@@ -159,7 +189,7 @@ namespace Camera {
fogFar: 10000,
fov: Math.PI / 4,
zoom: 1
zoom: 1,
};
}
......@@ -178,7 +208,7 @@ namespace Camera {
fogFar: number,
fov: number,
zoom: number
zoom: number,
}
export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
......@@ -231,10 +261,22 @@ function updateOrtho(camera: Camera) {
function updatePers(camera: Camera) {
const aspect = camera.viewport.width / camera.viewport.height
const { fov, near, far } = camera.state;
const { state: { fov, near, far }, viewOffset } = camera;
let top = near * Math.tan(0.5 * fov)
let height = 2 * top
let width = aspect * height
let left = -0.5 * width
if (viewOffset && viewOffset.enabled) {
left += viewOffset.offsetX * width / viewOffset.fullWidth
top -= viewOffset.offsetY * height / viewOffset.fullHeight
width *= viewOffset.width / viewOffset.fullWidth
height *= viewOffset.height / viewOffset.fullHeight
}
// build projection matrix
Mat4.perspective(camera.projection, fov, aspect, Math.abs(near), Math.abs(far))
Mat4.perspective(camera.projection, left, left + width, top, top - height, near, far)
// build view matrix
Vec3.add(_center, camera.position, camera.direction)
......
......@@ -806,51 +806,62 @@ namespace Mat4 {
/**
* Generates a perspective projection matrix with the given bounds
*/
export function perspective(out: Mat4, fovy: number, aspect: number, near: number, far: number) {
const f = 1.0 / Math.tan(fovy / 2);
const nf = 1 / (near - far);
out[0] = f / aspect;
export function perspective(out: Mat4, left: number, right: number, top: number, bottom: number, near: number, far: number) {
const x = 2 * near / (right - left);
const y = 2 * near / (top - bottom);
const a = (right + left) / (right - left);
const b = (top + bottom) / (top - bottom);
const c = - (far + near) / (far - near);
const d = - 2 * far * near / (far - near);
out[0] = x;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = f;
out[5] = y;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = (far + near) * nf;
out[8] = a;
out[9] = b;
out[10] = c;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = (2 * far * near) * nf;
out[15] = 0;
out[ 12 ] = 0;
out[ 13 ] = 0;
out[ 14 ] = d;
out[ 15 ] = 0;
return out;
}
/**
* Generates a orthogonal projection matrix with the given bounds
*/
export function ortho(out: Mat4, left: number, right: number, bottom: number, top: number, near: number, far: number) {
const lr = 1 / (left - right);
const bt = 1 / (bottom - top);
const nf = 1 / (near - far);
out[0] = -2 * lr;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = -2 * bt;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 2 * nf;
out[11] = 0;
out[12] = (left + right) * lr;
out[13] = (top + bottom) * bt;
out[14] = (far + near) * nf;
out[15] = 1;
const w = 1.0 / (right - left);
const h = 1.0 / (top - bottom);
const p = 1.0 / (far - near);
const x = (right + left) * w;
const y = (top + bottom) * h;
const z = (far + near) * p;
out[ 0 ] = 2 * w;
out[ 1 ] = 0;
out[ 2 ] = 0;
out[ 3 ] = 0;
out[ 4 ] = 0;
out[ 5 ] = 2 * h;
out[ 6 ] = 0;
out[ 7 ] = 0;
out[ 8 ] = 0;
out[ 9 ] = 0;
out[ 10 ] = - 2 * p;
out[ 11 ] = 0;
out[ 12 ] = - x;
out[ 13 ] = - y;
out[ 14 ] = - z;
out[ 15 ] = 1;
return out;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment