Bladeren bron

made cameraHelper part of drawPass, screenshot improvements

Alexander Rose 5 jaren geleden
bovenliggende
commit
cc0ccd7830

+ 8 - 7
src/mol-canvas3d/canvas3d.ts

@@ -34,7 +34,7 @@ import { PickPass } from './passes/pick';
 import { ImagePass, ImageProps } from './passes/image';
 import { Sphere3D } from '../mol-math/geometry';
 import { isDebugMode } from '../mol-util/debug';
-import { CameraHelper, CameraHelperParams } from './helper/camera-helper';
+import { CameraHelperParams } from './helper/camera-helper';
 
 export const Canvas3DParams = {
     camera: PD.Group({
@@ -96,7 +96,7 @@ interface Canvas3D {
     downloadScreenshot(): void
     getPixelData(variant: GraphicsRenderVariant): PixelData
     setProps(props: Partial<Canvas3DProps>): void
-    getImagePass(): ImagePass
+    getImagePass(props: Partial<ImageProps>): ImagePass
 
     /** Returns a copy of the current Canvas3D instance props */
     readonly props: Readonly<Canvas3DProps>
@@ -189,9 +189,10 @@ namespace Canvas3D {
         const renderer = Renderer.create(webgl, p.renderer)
         const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug);
         const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input);
-        const cameraHelper = new CameraHelper(webgl, p.camera.helper);
 
-        const drawPass = new DrawPass(webgl, renderer, scene, camera, debugHelper, cameraHelper)
+        const drawPass = new DrawPass(webgl, renderer, scene, camera, debugHelper, {
+            cameraHelper: p.camera.helper
+        })
         const pickPass = new PickPass(webgl, renderer, scene, camera, 0.5)
         const postprocessing = new PostprocessingPass(webgl, camera, drawPass, p.postprocessing)
         const multiSample = new MultiSamplePass(webgl, camera, drawPass, postprocessing, p.multiSample)
@@ -499,7 +500,7 @@ namespace Canvas3D {
                 }
                 if (Object.keys(cameraState).length > 0) camera.setState(cameraState)
 
-                if (props.camera?.helper) cameraHelper.setProps(props.camera.helper)
+                if (props.camera?.helper) drawPass.setProps({ cameraHelper: props.camera.helper })
                 if (props.cameraResetDurationMs !== undefined) p.cameraResetDurationMs = props.cameraResetDurationMs
                 if (props.transparentBackground !== undefined) p.transparentBackground = props.transparentBackground
 
@@ -512,7 +513,7 @@ namespace Canvas3D {
                 requestDraw(true)
             },
             getImagePass: (props: Partial<ImageProps> = {}) => {
-                return new ImagePass(webgl, renderer, scene, camera, debugHelper, cameraHelper, props)
+                return new ImagePass(webgl, renderer, scene, camera, debugHelper, props)
             },
 
             get props() {
@@ -523,7 +524,7 @@ namespace Canvas3D {
                 return {
                     camera: {
                         mode: camera.state.mode,
-                        helper: { ...cameraHelper.props }
+                        helper: { ...drawPass.props.cameraHelper }
                     },
                     cameraFog: camera.state.fog > 0
                         ? { name: 'on' as const, params: { intensity: camera.state.fog } }

+ 24 - 2
src/mol-canvas3d/passes/draw.ts

@@ -11,16 +11,25 @@ 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 { CameraHelper } from '../helper/camera-helper';
+import { CameraHelper, CameraHelperParams } from '../helper/camera-helper';
+import { ParamDefinition as PD } from '../../mol-util/param-definition';
+
+export const DrawPassParams = {
+    cameraHelper: PD.Group(CameraHelperParams)
+}
+export const DefaultDrawPassProps = PD.getDefaultValues(DrawPassParams);
+export type DrawPassProps = PD.Values<typeof DrawPassParams>
 
 export class DrawPass {
     colorTarget: RenderTarget
     depthTexture: Texture
     packedDepth: boolean
 
+    cameraHelper: CameraHelper
+
     private depthTarget: RenderTarget | null
 
-    constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private debugHelper: BoundingSphereHelper, private cameraHelper: CameraHelper) {
+    constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private debugHelper: BoundingSphereHelper, props: Partial<DrawPassProps> = {}) {
         const { gl, extensions, resources } = webgl
         const width = gl.drawingBufferWidth
         const height = gl.drawingBufferHeight
@@ -32,6 +41,9 @@ export class DrawPass {
             this.depthTexture.define(width, height)
             this.depthTexture.attachFramebuffer(this.colorTarget.framebuffer, 'depth')
         }
+
+        const p = { ...DefaultDrawPassProps, ...props }
+        this.cameraHelper = new CameraHelper(webgl, p.cameraHelper);
     }
 
     setSize(width: number, height: number) {
@@ -43,6 +55,16 @@ export class DrawPass {
         }
     }
 
+    setProps(props: Partial<DrawPassProps>) {
+        if (props.cameraHelper) this.cameraHelper.setProps(props.cameraHelper)
+    }
+
+    get props(): DrawPassProps {
+        return {
+            cameraHelper: { ...this.cameraHelper.props }
+        }
+    }
+
     render(toDrawingBuffer: boolean, transparentBackground: boolean) {
         const { webgl, renderer, colorTarget, depthTarget } = this
         if (toDrawingBuffer) {

+ 15 - 5
src/mol-canvas3d/passes/image.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -10,17 +10,17 @@ import Renderer from '../../mol-gl/renderer';
 import Scene from '../../mol-gl/scene';
 import { BoundingSphereHelper } from '../helper/bounding-sphere-helper';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
-import { DrawPass } from './draw'
+import { DrawPass, DrawPassParams } from './draw'
 import { PostprocessingPass, PostprocessingParams } from './postprocessing'
 import { MultiSamplePass, MultiSampleParams } from './multi-sample'
 import { Camera } from '../camera';
 import { Viewport } from '../camera/util';
-import { CameraHelper } from '../helper/camera-helper';
 
 export const ImageParams = {
     transparentBackground: PD.Boolean(false),
     multiSample: PD.Group(MultiSampleParams),
     postprocessing: PD.Group(PostprocessingParams),
+    drawPass: PD.Group(DrawPassParams),
 }
 export type ImageProps = PD.Values<typeof ImageParams>
 
@@ -40,12 +40,12 @@ export class ImagePass {
     get width() { return this._width }
     get height() { return this._height }
 
-    constructor(webgl: WebGLContext, private renderer: Renderer, scene: Scene, private camera: Camera, debugHelper: BoundingSphereHelper, cameraHelper: CameraHelper, props: Partial<ImageProps>) {
+    constructor(webgl: WebGLContext, private renderer: Renderer, scene: Scene, private camera: Camera, debugHelper: BoundingSphereHelper, props: Partial<ImageProps>) {
         const p = { ...PD.getDefaultValues(ImageParams), ...props }
 
         this._transparentBackground = p.transparentBackground
 
-        this.drawPass = new DrawPass(webgl, renderer, scene, this._camera, debugHelper, cameraHelper)
+        this.drawPass = new DrawPass(webgl, renderer, scene, this._camera, debugHelper, 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)
 
@@ -67,6 +67,16 @@ export class ImagePass {
         if (props.transparentBackground !== undefined) this._transparentBackground = props.transparentBackground
         if (props.postprocessing) this.postprocessing.setProps(props.postprocessing)
         if (props.multiSample) this.multiSample.setProps(props.multiSample)
+        if (props.drawPass) this.drawPass.setProps(props.drawPass)
+    }
+
+    get props(): ImageProps {
+        return {
+            transparentBackground: this._transparentBackground,
+            postprocessing: this.postprocessing.props,
+            multiSample: this.multiSample.props,
+            drawPass: this.drawPass.props
+        }
     }
 
     render() {

+ 11 - 12
src/mol-plugin-ui/viewport/screenshot.tsx

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -13,21 +13,24 @@ import { debounceTime } from 'rxjs/operators';
 import { Subject } from 'rxjs';
 import { ViewportScreenshotHelper } from '../../mol-plugin/util/viewport-screenshot';
 import { Button } from '../controls/common';
+import { CameraHelperProps } from '../../mol-canvas3d/helper/camera-helper';
 
 interface ImageControlsState {
     showPreview: boolean
+    isDisabled: boolean
 
     resolution?: ViewportScreenshotHelper.ResolutionSettings,
     transparent?: boolean,
-    isDisabled: boolean
+    axes?: CameraHelperProps['axes']
 }
 
 export class DownloadScreenshotControls extends PluginUIComponent<{ close: () => void }, ImageControlsState> {
     state: ImageControlsState = {
         showPreview: true,
+        isDisabled: false,
         resolution: this.plugin.helpers.viewportScreenshot?.currentResolution,
         transparent: this.plugin.helpers.viewportScreenshot?.transparent,
-        isDisabled: false
+        axes: this.plugin.helpers.viewportScreenshot?.axes
     } as ImageControlsState
 
     private imgRef = React.createRef<HTMLImageElement>()
@@ -103,18 +106,14 @@ export class DownloadScreenshotControls extends PluginUIComponent<{ close: () =>
 
     private setProps = (p: { param: PD.Base<any>, name: string, value: any }) => {
         if (p.name === 'resolution') {
-            const resolution = p.value as ViewportScreenshotHelper.ResolutionSettings
-            if (resolution.name === 'custom') {
-                this.plugin.helpers.viewportScreenshot!.currentResolution.type = 'custom';
-                this.plugin.helpers.viewportScreenshot!.currentResolution.width = resolution.params.width;
-                this.plugin.helpers.viewportScreenshot!.currentResolution.height = resolution.params.height;
-            } else {
-                this.plugin.helpers.viewportScreenshot!.currentResolution.type = resolution.name;
-            }
-            this.setState({ resolution });
+            this.plugin.helpers.viewportScreenshot!.currentResolution = p.value;
+            this.setState({ resolution: p.value });
         } else if (p.name === 'transparent') {
             this.plugin.helpers.viewportScreenshot!.transparent = p.value;
             this.setState({ transparent: p.value });
+        } else if (p.name === 'axes') {
+            this.plugin.helpers.viewportScreenshot!.axes = p.value;
+            this.setState({ axes: p.value });
         }
     }
 

+ 22 - 20
src/mol-plugin/util/viewport-screenshot.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 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>
@@ -14,6 +14,8 @@ import { canvasToBlob } from '../../mol-canvas3d/util';
 import { download } from '../../mol-util/download';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { SyncRuntimeContext } from '../../mol-task/execution/synchronous';
+import { CameraHelperParams, CameraHelperProps } from '../../mol-canvas3d/helper/camera-helper';
+import { SetUtils } from '../../mol-util/set';
 
 export { ViewportScreenshotHelper }
 
@@ -26,8 +28,7 @@ class ViewportScreenshotHelper {
     private createParams() {
         const max = Math.min(this.plugin.canvas3d ? this.plugin.canvas3d.webgl.maxRenderbufferSize : 4096, 4096)
         return {
-            transparent: PD.Boolean(false),
-            resolution: PD.MappedStatic('full-hd', {
+            resolution: PD.MappedStatic('viewport', {
                 viewport: PD.Group({}),
                 hd: PD.Group({}),
                 'full-hd': PD.Group({}),
@@ -44,7 +45,9 @@ class ViewportScreenshotHelper {
                     ['ultra-hd', 'Ultra HD (3840 x 2160)'],
                     ['custom', 'Custom']
                 ]
-            })
+            }),
+            transparent: PD.Boolean(false),
+            axes: CameraHelperParams.axes,
         }
     }
     private _params: ReturnType<ViewportScreenshotHelper['createParams']> = void 0 as any;
@@ -54,9 +57,11 @@ class ViewportScreenshotHelper {
     }
 
     get values() {
-        return this.currentResolution.type === 'custom'
-            ? { transparent: this.transparent, resolution: { name: 'custom', params: { width: this.currentResolution.width, height: this.currentResolution.height } } }
-            : { transparent: this.transparent, resolution: { name: this.currentResolution.type, params: { } } };
+        return {
+            transparent: this.transparent,
+            axes: this.axes,
+            resolution: this.currentResolution
+        };
     }
 
     private getCanvasSize() {
@@ -66,21 +71,17 @@ class ViewportScreenshotHelper {
         };
     }
 
-    transparent = false
-
-    currentResolution = {
-        type: 'full-hd' as ViewportScreenshotHelper.ResolutionTypes,
-        width: 1920,
-        height: 1080
-    };
+    transparent = this.params.transparent.defaultValue
+    axes: CameraHelperProps['axes'] = { name: 'off', params: {} }
+    currentResolution = this.params.resolution.defaultValue
 
     private getSize() {
-        switch (this.currentResolution.type ) {
+        switch (this.currentResolution.name ) {
             case 'viewport': return this.getCanvasSize();
             case 'hd': return { width: 1280, height: 720 };
             case 'full-hd': return { width: 1920, height: 1080 };
             case 'ultra-hd': return { width: 3840, height: 2160 };
-            default: return { width: this.currentResolution.width, height: this.currentResolution.height }
+            default: return { width: this.currentResolution.params.width, height: this.currentResolution.params.height }
         }
     }
 
@@ -89,12 +90,12 @@ class ViewportScreenshotHelper {
     get imagePass() {
         if (this._imagePass) return this._imagePass;
 
-        this._imagePass = this.plugin.canvas3d!.getImagePass()
-        this._imagePass.setProps({
+        this._imagePass = this.plugin.canvas3d!.getImagePass({
             transparentBackground: this.transparent,
+            drawPass: { cameraHelper: { axes: this.axes } },
             multiSample: { mode: 'on', sampleLevel: 2 },
             postprocessing: this.plugin.canvas3d!.props.postprocessing
-        });
+        })
         return this._imagePass;
     }
 
@@ -102,7 +103,7 @@ class ViewportScreenshotHelper {
         const models = this.plugin.state.data.select(StateSelection.Generators.rootsOfType(PluginStateObject.Molecule.Model)).map(s => s.obj!.data)
         const uniqueIds = new Set<string>()
         models.forEach(m => uniqueIds.add(m.entryId.toUpperCase()))
-        const idString = Array.from(uniqueIds.values()).join('-')
+        const idString = SetUtils.toArray(uniqueIds).join('-')
         return `${idString || 'molstar-image'}.png`
     }
 
@@ -139,6 +140,7 @@ class ViewportScreenshotHelper {
 
         await ctx.update('Rendering image...')
         this.imagePass.setProps({
+            drawPass: { cameraHelper: { axes: this.axes } },
             transparentBackground: this.transparent,
             postprocessing: this.plugin.canvas3d!.props.postprocessing // TODO this line should not be required, updating should work by listening to this.plugin.events.canvas3d.settingsUpdated
         });