Przeglądaj źródła

unified perpective/orthographic matrix creation signature

Alexander Rose 5 lat temu
rodzic
commit
21ce146d36
2 zmienionych plików z 90 dodań i 37 usunięć
  1. 47 5
      src/mol-canvas3d/camera.ts
  2. 43 32
      src/mol-math/linear-algebra/3d/mat4.ts

+ 47 - 5
src/mol-canvas3d/camera.ts

@@ -1,5 +1,5 @@
 /**
- * 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)

+ 43 - 32
src/mol-math/linear-algebra/3d/mat4.ts

@@ -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;
     }