From 2f84b94227b6840326d4661e272a2bc2f0c7f2e3 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Tue, 20 Oct 2020 18:36:20 +0200
Subject: [PATCH] Basic stereo rendering support
---
src/mol-canvas3d/camera.ts | 42 +++++--
src/mol-canvas3d/camera/stereo.ts | 105 ++++++++++++++++++
src/mol-canvas3d/canvas3d.ts | 26 ++++-
src/mol-canvas3d/helper/camera-helper.ts | 4 +-
src/mol-canvas3d/passes/draw.ts | 39 +++++--
src/mol-canvas3d/passes/image.ts | 2 +-
src/mol-canvas3d/passes/multi-sample.ts | 3 +-
src/mol-canvas3d/passes/pick.ts | 56 +++++++---
src/mol-canvas3d/passes/postprocessing.ts | 1 +
src/mol-gl/renderer.ts | 6 +-
.../viewport/simple-settings.tsx | 3 +
11 files changed, 239 insertions(+), 48 deletions(-)
create mode 100644 src/mol-canvas3d/camera/stereo.ts
diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
index 01d54d6de..2a0792fd5 100644
--- a/src/mol-canvas3d/camera.ts
+++ b/src/mol-canvas3d/camera.ts
@@ -10,9 +10,21 @@ import { Viewport, cameraProject, cameraUnproject } from './camera/util';
import { CameraTransitionManager } from './camera/transition';
import { BehaviorSubject } from 'rxjs';
-export { Camera };
+export { ICamera, Camera };
+
+interface ICamera {
+ readonly viewport: Viewport,
+ readonly view: Mat4,
+ readonly projection: Mat4,
+ readonly state: Readonly<Camera.Snapshot>,
+ readonly viewOffset: Camera.ViewOffset,
+ readonly far: number,
+ readonly near: number,
+ readonly fogFar: number,
+ readonly fogNear: number,
+}
-class Camera {
+class Camera implements ICamera {
readonly view: Mat4 = Mat4.identity();
readonly projection: Mat4 = Mat4.identity();
readonly projectionView: Mat4 = Mat4.identity();
@@ -26,12 +38,7 @@ class Camera {
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 viewOffset = Camera.ViewOffset();
near = 1
far = 10000
@@ -157,6 +164,15 @@ namespace Camera {
height: number
}
+ export function ViewOffset(): ViewOffset {
+ return {
+ enabled: false,
+ fullWidth: 1, fullHeight: 1,
+ offsetX: 0, offsetY: 0,
+ width: 1, height: 1
+ };
+ }
+
export function setViewOffset(out: ViewOffset, fullWidth: number, fullHeight: number, offsetX: number, offsetY: number, width: number, height: number) {
out.fullWidth = fullWidth;
out.fullHeight = fullHeight;
@@ -166,6 +182,16 @@ namespace Camera {
out.height = height;
}
+ export function copyViewOffset(out: ViewOffset, view: ViewOffset) {
+ out.enabled = view.enabled;
+ out.fullWidth = view.fullWidth;
+ out.fullHeight = view.fullHeight;
+ out.offsetX = view.offsetX;
+ out.offsetY = view.offsetY;
+ out.width = view.width;
+ out.height = view.height;
+ }
+
export function createDefaultSnapshot(): Snapshot {
return {
mode: 'perspective',
diff --git a/src/mol-canvas3d/camera/stereo.ts b/src/mol-canvas3d/camera/stereo.ts
new file mode 100644
index 000000000..8aa206b48
--- /dev/null
+++ b/src/mol-canvas3d/camera/stereo.ts
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ *
+ * Adapted from three.js, The MIT License, Copyright © 2010-2020 three.js authors
+ */
+
+import { Mat4 } from '../../mol-math/linear-algebra';
+import { ParamDefinition } from '../../mol-util/param-definition';
+import { Camera, ICamera } from '../camera';
+import { Viewport } from './util';
+
+export class StereoCamera {
+ readonly left: ICamera = new EyeCamera();
+ readonly right: ICamera = new EyeCamera();
+
+ update(camera: Camera, params: StereoCameraParams) {
+ update(camera, params, this.left as EyeCamera, this.right as EyeCamera);
+ }
+}
+
+class EyeCamera implements ICamera {
+ viewport = Viewport.create(0, 0, 0, 0);
+ view = Mat4();
+ projection = Mat4();
+ state: Readonly<Camera.Snapshot> = Camera.createDefaultSnapshot();
+ viewOffset: Readonly<Camera.ViewOffset> = Camera.ViewOffset();
+ far: number = 0;
+ near: number = 0;
+ fogFar: number = 0;
+ fogNear: number = 0;
+}
+
+export const StereoCameraParams = {
+ aspect: ParamDefinition.Numeric(1, { min: 0.1, max: 3, step: 0.01 }),
+ eyeSeparation: ParamDefinition.Numeric(0.064, { min: 0.01, max: 0.5, step: 0.001 }),
+ focus: ParamDefinition.Numeric(10, { min: 1, max: 100, step: 0.01 }),
+};
+export type StereoCameraParams = ParamDefinition.Values<typeof StereoCameraParams>
+
+const eyeLeft = Mat4.identity(), eyeRight = Mat4.identity();
+
+function update(camera: ICamera, params: StereoCameraParams, left: EyeCamera, right: EyeCamera) {
+ // Copy the states
+
+ Viewport.copy(left.viewport, camera.viewport);
+ Mat4.copy(left.view, camera.view);
+ Mat4.copy(left.projection, camera.projection);
+ Camera.copySnapshot(left.state, camera.state);
+ Camera.copyViewOffset(left.viewOffset, camera.viewOffset);
+ left.far = camera.far;
+ left.near = camera.near;
+ left.fogFar = camera.fogFar;
+ left.fogNear = camera.fogNear;
+
+ Viewport.copy(right.viewport, camera.viewport);
+ Mat4.copy(right.view, camera.view);
+ Mat4.copy(right.projection, camera.projection);
+ Camera.copySnapshot(right.state, camera.state);
+ Camera.copyViewOffset(right.viewOffset, camera.viewOffset);
+ right.far = camera.far;
+ right.near = camera.near;
+ right.fogFar = camera.fogFar;
+ right.fogNear = camera.fogNear;
+
+ // update the view offsets
+ let w = (camera.viewport.width / 2) | 0;
+
+ left.viewport.width = w;
+ right.viewport.x = w;
+ right.viewport.width -= w;
+
+ // update the projection and view matrices
+
+ const eyeSepHalf = params.eyeSeparation / 2;
+ const eyeSepOnProjection = eyeSepHalf * camera.near / params.focus;
+ const ymax = (camera.near * Math.tan(camera.state.fov * 0.5)) / /* cache.zoom */ 1;
+ let xmin, xmax;
+
+ // translate xOffset
+
+ eyeLeft[12] = - eyeSepHalf;
+ eyeRight[12] = eyeSepHalf;
+
+ // for left eye
+
+ xmin = - ymax * params.aspect + eyeSepOnProjection;
+ xmax = ymax * params.aspect + eyeSepOnProjection;
+
+ left.projection[0] = 2 * camera.near / (xmax - xmin);
+ left.projection[8] = (xmax + xmin) / (xmax - xmin);
+
+ Mat4.mul(left.view, left.view, eyeLeft);
+
+ // for right eye
+
+ xmin = - ymax * params.aspect - eyeSepOnProjection;
+ xmax = ymax * params.aspect - eyeSepOnProjection;
+
+ right.projection[0] = 2 * camera.near / (xmax - xmin);
+ right.projection[8] = (xmax + xmin) / (xmax - xmin);
+
+ Mat4.mul(right.view, right.view, eyeRight);
+}
\ No newline at end of file
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 2a76be15e..325eb6a90 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -34,6 +34,7 @@ import { isDebugMode } from '../mol-util/debug';
import { CameraHelperParams } from './helper/camera-helper';
import { produce } from 'immer';
import { HandleHelper, HandleHelperParams } from './helper/handle-helper';
+import { StereoCamera, StereoCameraParams } from './camera/stereo';
export const Canvas3DParams = {
camera: PD.Group({
@@ -60,6 +61,10 @@ export const Canvas3DParams = {
height: PD.Numeric(128)
})
}),
+ stereo: PD.MappedStatic('off', {
+ on: PD.Group(StereoCameraParams),
+ off: PD.Group({})
+ }, { cycle: true }),
cameraResetDurationMs: PD.Numeric(250, { min: 0, max: 1000, step: 1 }, { description: 'The time it takes to reset the camera.' }),
transparentBackground: PD.Boolean(false),
@@ -207,6 +212,7 @@ namespace Canvas3D {
fog: p.cameraFog.name === 'on' ? p.cameraFog.params.intensity : 0,
clipFar: p.cameraClipping.far
}, { x, y, width, height }, { pixelScale: attribs.pixelScale });
+ const stereoCamera = new StereoCamera();
const controls = TrackballControls.create(input, camera, p.trackball);
const renderer = Renderer.create(webgl, p.renderer);
@@ -214,10 +220,13 @@ namespace Canvas3D {
const handleHelper = new HandleHelper(webgl, p.handle);
const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input, camera);
- const drawPass = new DrawPass(webgl, renderer, scene, camera, debugHelper, handleHelper, {
+ const drawPass = new DrawPass(webgl, renderer, scene, { standard: camera, stereo: stereoCamera }, debugHelper, handleHelper, {
cameraHelper: p.camera.helper
});
- const pickPass = new PickPass(webgl, renderer, scene, camera, handleHelper, attribs.pickScale || 0.25, drawPass);
+ drawPass.isStereo = p.stereo.name === 'on';
+ const pickPass = new PickPass(webgl, renderer, scene, camera, stereoCamera, handleHelper, attribs.pickScale || 0.25, drawPass);
+ pickPass.isStereo = p.stereo.name === 'on';
+
const postprocessing = new PostprocessingPass(webgl, camera, drawPass, p.postprocessing);
const multiSample = new MultiSamplePass(webgl, camera, drawPass, postprocessing, p.multiSample);
@@ -275,9 +284,14 @@ namespace Canvas3D {
const cameraChanged = camera.update();
const multiSampleChanged = multiSample.update(force || cameraChanged);
+ const isStereo = p.stereo.name === 'on';
+
if (force || cameraChanged || multiSampleChanged) {
+ if ((force || cameraChanged) && p.stereo.name === 'on') stereoCamera.update(camera, p.stereo.params);
+
renderer.setViewport(x, y, width, height);
- if (multiSample.enabled) {
+ // TODO: support stereo rendering in multisampling
+ if (!isStereo && multiSample.enabled) {
multiSample.render(true, p.transparentBackground);
} else {
const toDrawingBuffer = !postprocessing.enabled && scene.volumes.renderables.length === 0;
@@ -490,6 +504,7 @@ namespace Canvas3D {
cameraResetDurationMs: p.cameraResetDurationMs,
transparentBackground: p.transparentBackground,
viewport: p.viewport,
+ stereo: p.stereo,
postprocessing: { ...postprocessing.props },
multiSample: { ...multiSample.props },
@@ -595,6 +610,11 @@ namespace Canvas3D {
p.viewport = props.viewport;
handleResize();
}
+ if (props.stereo !== undefined) {
+ p.stereo = props.stereo;
+ pickPass.isStereo = p.stereo.name === 'on';
+ drawPass.isStereo = p.stereo.name === 'on';
+ }
if (props.postprocessing) postprocessing.setProps(props.postprocessing);
if (props.multiSample) multiSample.setProps(props.multiSample);
diff --git a/src/mol-canvas3d/helper/camera-helper.ts b/src/mol-canvas3d/helper/camera-helper.ts
index 7b5d40521..2640a24f5 100644
--- a/src/mol-canvas3d/helper/camera-helper.ts
+++ b/src/mol-canvas3d/helper/camera-helper.ts
@@ -6,7 +6,7 @@
import { WebGLContext } from '../../mol-gl/webgl/context';
import Scene from '../../mol-gl/scene';
-import { Camera } from '../camera';
+import { Camera, ICamera } from '../camera';
import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
import { addSphere } from '../../mol-geo/geometry/mesh/builder/sphere';
@@ -86,7 +86,7 @@ export class CameraHelper {
return this.props.axes.name === 'on';
}
- update(camera: Camera) {
+ update(camera: ICamera) {
if (!this.renderObject) return;
updateCamera(this.camera, camera.viewport, camera.viewOffset);
diff --git a/src/mol-canvas3d/passes/draw.ts b/src/mol-canvas3d/passes/draw.ts
index 9db4b9477..aabc49352 100644
--- a/src/mol-canvas3d/passes/draw.ts
+++ b/src/mol-canvas3d/passes/draw.ts
@@ -10,7 +10,7 @@ import Renderer from '../../mol-gl/renderer';
import Scene from '../../mol-gl/scene';
import { BoundingSphereHelper } from '../helper/bounding-sphere-helper';
import { Texture } from '../../mol-gl/webgl/texture';
-import { Camera } from '../camera';
+import { ICamera } from '../camera';
import { CameraHelper, CameraHelperParams } from '../helper/camera-helper';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { HandleHelper } from '../helper/handle-helper';
@@ -21,6 +21,7 @@ import { ShaderCode } from '../../mol-gl/shader-code';
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
import { ValueCell } from '../../mol-util';
import { Vec2 } from '../../mol-math/linear-algebra';
+import { StereoCamera } from '../camera/stereo';
import quad_vert from '../../mol-gl/shader/quad.vert';
import depthMerge_frag from '../../mol-gl/shader/depth-merge.frag';
@@ -70,9 +71,11 @@ export class DrawPass {
private depthTextureVolumes: Texture
private depthMerge: DepthMergeRenderable
- constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private debugHelper: BoundingSphereHelper, private handleHelper: HandleHelper, props: Partial<DrawPassProps> = {}) {
+ isStereo = false
+
+ constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: { standard: ICamera, stereo?: StereoCamera }, private debugHelper: BoundingSphereHelper, private handleHelper: HandleHelper, props: Partial<DrawPassProps> = {}) {
const { extensions, resources } = webgl;
- const { width, height } = camera.viewport;
+ const { width, height } = camera.standard.viewport;
this.colorTarget = webgl.createRenderTarget(width, height);
this.packedDepth = !extensions.depthTexture;
@@ -125,25 +128,35 @@ export class DrawPass {
}
render(toDrawingBuffer: boolean, transparentBackground: boolean) {
- const { x, y, width, height } = this.camera.viewport;
+ if (this.isStereo && this.camera.stereo) {
+ this._render(this.camera.stereo.left, toDrawingBuffer, transparentBackground);
+ this._render(this.camera.stereo.right, toDrawingBuffer, transparentBackground);
+ } else {
+ this._render(this.camera.standard, toDrawingBuffer, transparentBackground);
+ }
+ }
+
+ private _render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean) {
+ const { x, y, width, height } = camera.viewport;
if (toDrawingBuffer) {
this.webgl.unbindFramebuffer();
this.renderer.setViewport(x, y, width, height);
} else {
this.colorTarget.bind();
- this.renderer.setViewport(0, 0, width, height);
+ this.renderer.setViewport(x, y, width, height);
if (!this.packedDepth) {
this.depthTexturePrimitives.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
}
}
- this.renderer.render(this.scene.primitives, this.camera, 'color', true, transparentBackground, null);
+ this.renderer.render(this.scene.primitives, camera, 'color', true, transparentBackground, null);
// do a depth pass if not rendering to drawing buffer and
// extensions.depthTexture is unsupported (i.e. depthTarget is set)
if (!toDrawingBuffer && this.depthTargetPrimitives) {
this.depthTargetPrimitives.bind();
- this.renderer.render(this.scene.primitives, this.camera, 'depth', true, transparentBackground, null);
+ this.renderer.setViewport(x, y, width, height);
+ this.renderer.render(this.scene.primitives, camera, 'depth', true, transparentBackground, null);
this.colorTarget.bind();
}
@@ -154,12 +167,12 @@ export class DrawPass {
this.webgl.state.depthMask(true);
this.webgl.gl.clear(this.webgl.gl.DEPTH_BUFFER_BIT);
}
- this.renderer.render(this.scene.volumes, this.camera, 'color', false, transparentBackground, this.depthTexturePrimitives);
+ this.renderer.render(this.scene.volumes, camera, 'color', false, transparentBackground, this.depthTexturePrimitives);
// do volume depth pass if extensions.depthTexture is unsupported (i.e. depthTarget is set)
if (this.depthTargetVolumes) {
this.depthTargetVolumes.bind();
- this.renderer.render(this.scene.volumes, this.camera, 'depth', true, transparentBackground, this.depthTexturePrimitives);
+ this.renderer.render(this.scene.volumes, camera, 'depth', true, transparentBackground, this.depthTexturePrimitives);
this.colorTarget.bind();
}
}
@@ -168,6 +181,7 @@ export class DrawPass {
if (!toDrawingBuffer) {
this.depthMerge.update();
this.depthTarget.bind();
+ this.renderer.setViewport(x, y, width, height);
this.webgl.state.disable(this.webgl.gl.SCISSOR_TEST);
this.webgl.state.disable(this.webgl.gl.BLEND);
this.webgl.state.disable(this.webgl.gl.DEPTH_TEST);
@@ -176,17 +190,18 @@ export class DrawPass {
this.webgl.gl.clear(this.webgl.gl.COLOR_BUFFER_BIT);
this.depthMerge.render();
this.colorTarget.bind();
+ this.renderer.setViewport(x, y, width, height);
}
if (this.debugHelper.isEnabled) {
this.debugHelper.syncVisibility();
- this.renderer.render(this.debugHelper.scene, this.camera, 'color', false, transparentBackground, null);
+ this.renderer.render(this.debugHelper.scene, camera, 'color', false, transparentBackground, null);
}
if (this.handleHelper.isEnabled) {
- this.renderer.render(this.handleHelper.scene, this.camera, 'color', false, transparentBackground, null);
+ this.renderer.render(this.handleHelper.scene, camera, 'color', false, transparentBackground, null);
}
if (this.cameraHelper.isEnabled) {
- this.cameraHelper.update(this.camera);
+ this.cameraHelper.update(camera);
this.renderer.render(this.cameraHelper.scene, this.cameraHelper.camera, 'color', false, transparentBackground, null);
}
}
diff --git a/src/mol-canvas3d/passes/image.ts b/src/mol-canvas3d/passes/image.ts
index 41d9b1432..f3a833987 100644
--- a/src/mol-canvas3d/passes/image.ts
+++ b/src/mol-canvas3d/passes/image.ts
@@ -47,7 +47,7 @@ export class ImagePass {
this._transparentBackground = p.transparentBackground;
- this.drawPass = new DrawPass(webgl, renderer, scene, this._camera, debugHelper, handleHelper, p.drawPass);
+ this.drawPass = new DrawPass(webgl, renderer, scene, { standard: this._camera }, debugHelper, handleHelper, p.drawPass);
this.postprocessing = new PostprocessingPass(webgl, this._camera, this.drawPass, p.postprocessing);
this.multiSample = new MultiSamplePass(webgl, this._camera, this.drawPass, this.postprocessing, p.multiSample);
diff --git a/src/mol-canvas3d/passes/multi-sample.ts b/src/mol-canvas3d/passes/multi-sample.ts
index d75964b41..f8670a50f 100644
--- a/src/mol-canvas3d/passes/multi-sample.ts
+++ b/src/mol-canvas3d/passes/multi-sample.ts
@@ -133,7 +133,8 @@ export class MultiSamplePass {
for (let i = 0; i < offsetList.length; ++i) {
const offset = offsetList[i];
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height);
- camera.update();
+ // TODO: this should not be needed
+ // camera.update();
this.drawPass.cameraHelper.update(camera);
// the theory is that equal weights for each sample lead to an accumulation of rounding
diff --git a/src/mol-canvas3d/passes/pick.ts b/src/mol-canvas3d/passes/pick.ts
index ea33d8a17..004d003e1 100644
--- a/src/mol-canvas3d/passes/pick.ts
+++ b/src/mol-canvas3d/passes/pick.ts
@@ -4,13 +4,15 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
-import { WebGLContext } from '../../mol-gl/webgl/context';
-import { RenderTarget } from '../../mol-gl/webgl/render-target';
+import { PickingId } from '../../mol-geo/geometry/picking';
import Renderer from '../../mol-gl/renderer';
import Scene from '../../mol-gl/scene';
-import { PickingId } from '../../mol-geo/geometry/picking';
+import { WebGLContext } from '../../mol-gl/webgl/context';
+import { GraphicsRenderVariant } from '../../mol-gl/webgl/render-item';
+import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { decodeFloatRGB } from '../../mol-util/float-packing';
-import { Camera } from '../camera';
+import { Camera, ICamera } from '../camera';
+import { StereoCamera } from '../camera/stereo';
import { HandleHelper } from '../helper/handle-helper';
import { DrawPass } from './draw';
@@ -23,6 +25,8 @@ export class PickPass {
instancePickTarget: RenderTarget
groupPickTarget: RenderTarget
+ isStereo = false
+
private objectBuffer: Uint8Array
private instanceBuffer: Uint8Array
private groupBuffer: Uint8Array
@@ -31,7 +35,7 @@ export class PickPass {
private pickWidth: number
private pickHeight: number
- constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private handleHelper: HandleHelper, private pickBaseScale: number, private drawPass: DrawPass) {
+ constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private stereoCamera: StereoCamera, private handleHelper: HandleHelper, private pickBaseScale: number, private drawPass: DrawPass) {
this.pickScale = pickBaseScale / webgl.pixelRatio;
this.pickWidth = Math.ceil(camera.viewport.width * this.pickScale);
this.pickHeight = Math.ceil(camera.viewport.height * this.pickScale);
@@ -69,25 +73,39 @@ export class PickPass {
}
}
- render() {
- const { renderer, scene, camera, handleHelper: { scene: handleScene } } = this;
+ private renderVariant(variant: GraphicsRenderVariant) {
+ if (this.isStereo) {
+ const w = (this.pickWidth / 2) | 0;
+
+ this.renderer.setViewport(0, 0, w, this.pickHeight);
+ this._renderVariant(this.stereoCamera.left, variant);
+
+ this.renderer.setViewport(w, 0, this.pickWidth - w, this.pickHeight);
+ this._renderVariant(this.stereoCamera.right, variant);
+ } else {
+ this.renderer.setViewport(0, 0, this.pickWidth, this.pickHeight);
+ this._renderVariant(this.camera, variant);
+ }
+ }
+
+ private _renderVariant(camera: ICamera, variant: GraphicsRenderVariant) {
+ const { renderer, scene, handleHelper: { scene: handleScene } } = this;
const depth = this.drawPass.depthTexturePrimitives;
- renderer.setViewport(0, 0, this.pickWidth, this.pickHeight);
+ renderer.render(scene.primitives, camera, variant, true, false, null);
+ renderer.render(scene.volumes, camera, variant, false, false, depth);
+ renderer.render(handleScene, camera, variant, false, false, null);
+ }
+
+ render() {
this.objectPickTarget.bind();
- renderer.render(scene.primitives, camera, 'pickObject', true, false, null);
- renderer.render(scene.volumes, camera, 'pickObject', false, false, depth);
- renderer.render(handleScene, camera, 'pickObject', false, false, null);
+ this.renderVariant('pickObject');
this.instancePickTarget.bind();
- renderer.render(scene.primitives, camera, 'pickInstance', true, false, null);
- renderer.render(scene.volumes, camera, 'pickInstance', false, false, depth);
- renderer.render(handleScene, camera, 'pickInstance', false, false, null);
+ this.renderVariant('pickInstance');
this.groupPickTarget.bind();
- renderer.render(scene.primitives, camera, 'pickGroup', true, false, null);
- renderer.render(scene.volumes, camera, 'pickGroup', false, false, depth);
- renderer.render(handleScene, camera, 'pickGroup', false, false, null);
+ this.renderVariant('pickGroup');
this.pickDirty = false;
}
@@ -123,7 +141,9 @@ export class PickPass {
gl.drawingBufferHeight - y < viewport.y ||
x > viewport.x + viewport.width ||
gl.drawingBufferHeight - y > viewport.y + viewport.height
- ) return;
+ ) {
+ return;
+ }
if (this.pickDirty) {
this.render();
diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts
index 5f1279e42..1825cb24d 100644
--- a/src/mol-canvas3d/passes/postprocessing.ts
+++ b/src/mol-canvas3d/passes/postprocessing.ts
@@ -167,6 +167,7 @@ export class PostprocessingPass {
}
const { x, y, width, height } = this.camera.viewport;
+
const { gl, state } = this.webgl;
if (toDrawingBuffer) {
this.webgl.unbindFramebuffer();
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
index f0a66e82a..dedea00b3 100644
--- a/src/mol-gl/renderer.ts
+++ b/src/mol-gl/renderer.ts
@@ -5,7 +5,7 @@
*/
import { Viewport } from '../mol-canvas3d/camera/util';
-import { Camera } from '../mol-canvas3d/camera';
+import { ICamera } from '../mol-canvas3d/camera';
import Scene from './scene';
import { WebGLContext } from './webgl/context';
@@ -43,7 +43,7 @@ interface Renderer {
readonly props: Readonly<RendererProps>
clear: (transparentBackground: boolean) => void
- render: (group: Scene.Group, camera: Camera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, depthTexture: Texture | null) => void
+ render: (group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, depthTexture: Texture | null) => void
setProps: (props: Partial<RendererProps>) => void
setViewport: (x: number, y: number, width: number, height: number) => void
dispose: () => void
@@ -300,7 +300,7 @@ namespace Renderer {
r.render(variant);
};
- const render = (group: Scene.Group, camera: Camera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, depthTexture: Texture | null) => {
+ const render = (group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, depthTexture: Texture | null) => {
ValueCell.update(globalUniforms.uModel, group.view);
ValueCell.update(globalUniforms.uView, camera.view);
ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view));
diff --git a/src/mol-plugin-ui/viewport/simple-settings.tsx b/src/mol-plugin-ui/viewport/simple-settings.tsx
index cf72e5002..fe30c31eb 100644
--- a/src/mol-plugin-ui/viewport/simple-settings.tsx
+++ b/src/mol-plugin-ui/viewport/simple-settings.tsx
@@ -62,6 +62,7 @@ const SimpleSettingsParams = {
outline: Canvas3DParams.postprocessing.params.outline,
fog: Canvas3DParams.cameraFog,
}, { pivot: 'renderStyle' }),
+ stereo: Canvas3DParams.stereo,
clipping: PD.Group<any>({
...Canvas3DParams.cameraClipping.params,
...(Canvas3DParams.renderer.params.clip as any).params as any
@@ -111,6 +112,7 @@ const SimpleSettingsMapping = ParamMapping({
outline: canvas.postprocessing.outline,
fog: canvas.cameraFog
},
+ stereo: canvas.stereo,
clipping: {
...canvas.cameraClipping,
...canvas.renderer.clip
@@ -136,6 +138,7 @@ const SimpleSettingsMapping = ParamMapping({
variant: s.clipping.variant,
objects: s.clipping.objects,
};
+ canvas.stereo = s.stereo;
props.layout = s.layout;
},
--
GitLab