Pārlūkot izejas kodu

postprocessing tweaks and fixes/improvements

- AO defaults: darker, larger radius
- handle transparent bg for outlines & AO
- handle fog for AO
- fix fog for outlines
- fragmentDepth for fog (instead of camera distance)
- webgl1 compat
Alexander Rose 4 gadi atpakaļ
vecāks
revīzija
b174fbf0c6

+ 1 - 0
package.json

@@ -80,6 +80,7 @@
     "Alexander Rose <alexander.rose@weirdbyte.de>",
     "David Sehnal <david.sehnal@gmail.com>",
     "Sebastian Bittrich <sebastian.bittrich@rcsb.org>",
+    "Áron Samuel Kovács <aron.kovacs@mail.muni.cz>",
     "Ludovic Autin <autin@scripps.edu>",
     "Michal Malý <michal.maly@ibt.cas.cz>",
     "Jiří Černý <jiri.cerny@ibt.cas.cz>"

+ 1 - 1
src/mol-canvas3d/canvas3d.ts

@@ -310,7 +310,7 @@ namespace Canvas3D {
                 if (MultiSamplePass.isEnabled(p.multiSample)) {
                     multiSampleHelper.render(renderer, cam, scene, helper, true, p.transparentBackground, p);
                 } else {
-                    passes.draw.render(renderer, cam, scene, helper, true, p.renderer.backgroundColor, p.transparentBackground, p.postprocessing);
+                    passes.draw.render(renderer, cam, scene, helper, true, p.transparentBackground, p.postprocessing);
                 }
                 pickHelper.dirty = true;
                 didRender = true;

+ 17 - 18
src/mol-canvas3d/passes/draw.ts

@@ -26,7 +26,6 @@ import copyFbo_frag from '../../mol-gl/shader/copy-fbo.frag';
 import { StereoCamera } from '../camera/stereo';
 import { WboitPass } from './wboit';
 import { AntialiasingPass, PostprocessingPass, PostprocessingProps } from './postprocessing';
-import { Color } from '../../mol-util/color';
 
 const DepthMergeSchema = {
     ...QuadSchema,
@@ -59,7 +58,7 @@ const CopyFboSchema = {
     tDepth: TextureSpec('texture', 'depth', 'ushort', 'nearest'),
     uTexSize: UniformSpec('v2'),
 };
-const  CopyFboShaderCode = ShaderCode('copy-fbo', quad_vert, copyFbo_frag);
+const  CopyFboShaderCode = ShaderCode('copy-fbo', quad_vert, copyFbo_frag, { fragDepth: 'required' });
 type  CopyFboRenderable = ComputeRenderable<Values<typeof CopyFboSchema>>
 
 function getCopyFboRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture): CopyFboRenderable {
@@ -96,7 +95,7 @@ export class DrawPass {
 
     private wboit: WboitPass | undefined
     readonly postprocessing: PostprocessingPass
-    private readonly fxaa: AntialiasingPass
+    private readonly antialiasing: AntialiasingPass
 
     get wboitEnabled() {
         return !!this.wboit?.supported;
@@ -126,7 +125,7 @@ export class DrawPass {
 
         this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined;
         this.postprocessing = new PostprocessingPass(webgl, this);
-        this.fxaa = new AntialiasingPass(webgl, this);
+        this.antialiasing = new AntialiasingPass(webgl, this);
 
         this.copyFboTarget = getCopyFboRenderable(webgl, this.colorTarget.texture, this.depthTarget.texture);
         this.copyFboPostprocessing = getCopyFboRenderable(webgl, this.postprocessing.target.texture, this.depthTarget.texture);
@@ -162,7 +161,7 @@ export class DrawPass {
             }
 
             this.postprocessing.setSize(width, height);
-            this.fxaa.setSize(width, height);
+            this.antialiasing.setSize(width, height);
         }
     }
 
@@ -180,7 +179,7 @@ export class DrawPass {
         this.depthMerge.render();
     }
 
-    private _renderWboit(renderer: Renderer, camera: ICamera, scene: Scene, backgroundColor: Color, postprocessingProps: PostprocessingProps) {
+    private _renderWboit(renderer: Renderer, camera: ICamera, scene: Scene, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
         if (!this.wboit?.supported) throw new Error('expected wboit to be supported');
 
         this.colorTarget.bind();
@@ -202,7 +201,7 @@ export class DrawPass {
         this._depthMerge();
 
         if (PostprocessingPass.isEnabled(postprocessingProps)) {
-            this.postprocessing.render(camera, false, backgroundColor, postprocessingProps);
+            this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
         }
 
         // render transparent primitives and volumes
@@ -221,7 +220,7 @@ export class DrawPass {
         this.wboit.render();
     }
 
-    private _renderBlended(renderer: Renderer, camera: ICamera, scene: Scene, backgroundColor: Color, toDrawingBuffer: boolean, postprocessingProps: PostprocessingProps) {
+    private _renderBlended(renderer: Renderer, camera: ICamera, scene: Scene, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
         if (toDrawingBuffer) {
             this.drawTarget.bind();
         } else {
@@ -264,7 +263,7 @@ export class DrawPass {
             this.colorTarget.bind();
 
             if (PostprocessingPass.isEnabled(postprocessingProps)) {
-                this.postprocessing.render(camera, false, backgroundColor, postprocessingProps);
+                this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
             }
             renderer.renderBlendedVolumeTransparent(scene.volumes, camera, this.depthTexturePrimitives);
 
@@ -284,7 +283,7 @@ export class DrawPass {
         renderer.renderBlendedTransparent(scene.primitives, camera, null);
     }
 
-    private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, backgroundColor: Color, postprocessingProps: PostprocessingProps) {
+    private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
         const volumeRendering = scene.volumes.renderables.length > 0;
         const postprocessingEnabled = PostprocessingPass.isEnabled(postprocessingProps);
         const antialiasingEnabled = AntialiasingPass.isEnabled(postprocessingProps);
@@ -294,9 +293,9 @@ export class DrawPass {
         renderer.update(camera);
 
         if (this.wboitEnabled) {
-            this._renderWboit(renderer, camera, scene, backgroundColor, postprocessingProps);
+            this._renderWboit(renderer, camera, scene, transparentBackground, postprocessingProps);
         } else {
-            this._renderBlended(renderer, camera, scene, backgroundColor, !volumeRendering && !postprocessingEnabled && !antialiasingEnabled && toDrawingBuffer, postprocessingProps);
+            this._renderBlended(renderer, camera, scene, !volumeRendering && !postprocessingEnabled && !antialiasingEnabled && toDrawingBuffer, transparentBackground, postprocessingProps);
         }
 
         if (PostprocessingPass.isEnabled(postprocessingProps)) {
@@ -321,7 +320,7 @@ export class DrawPass {
         }
 
         if (antialiasingEnabled) {
-            this.fxaa.render(camera, toDrawingBuffer, postprocessingProps);
+            this.antialiasing.render(camera, toDrawingBuffer, postprocessingProps);
         } else if (toDrawingBuffer) {
             this.drawTarget.bind();
 
@@ -336,21 +335,21 @@ export class DrawPass {
         this.webgl.gl.flush();
     }
 
-    render(renderer: Renderer, camera: Camera | StereoCamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, backgroundColor: Color, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
+    render(renderer: Renderer, camera: Camera | StereoCamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
         renderer.setTransparentBackground(transparentBackground);
         renderer.setDrawingBufferSize(this.colorTarget.getWidth(), this.colorTarget.getHeight());
 
         if (StereoCamera.is(camera)) {
-            this._render(renderer, camera.left, scene, helper, toDrawingBuffer, backgroundColor, postprocessingProps);
-            this._render(renderer, camera.right, scene, helper, toDrawingBuffer, backgroundColor, postprocessingProps);
+            this._render(renderer, camera.left, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps);
+            this._render(renderer, camera.right, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps);
         } else {
-            this._render(renderer, camera, scene, helper, toDrawingBuffer, backgroundColor, postprocessingProps);
+            this._render(renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps);
         }
     }
 
     getColorTarget(postprocessingProps: PostprocessingProps): RenderTarget {
         if (AntialiasingPass.isEnabled(postprocessingProps)) {
-            return this.fxaa.target;
+            return this.antialiasing.target;
         } else if (PostprocessingPass.isEnabled(postprocessingProps)) {
             return this.postprocessing.target;
         }

+ 26 - 2
src/mol-canvas3d/passes/fxaa.ts

@@ -16,6 +16,8 @@ import { ValueCell } from '../../mol-util';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import quad_vert from '../../mol-gl/shader/quad.vert';
 import fxaa_frag from '../../mol-gl/shader/fxaa.frag';
+import { Viewport } from '../camera/util';
+import { RenderTarget } from '../../mol-gl/webgl/render-target';
 
 export const FxaaParams = {
     edgeThresholdMin: PD.Numeric(0.0312, { min: 0.0312, max: 0.0833, step: 0.0001 }, { description: 'Trims the algorithm from processing darks.' }),
@@ -28,10 +30,26 @@ export type FxaaProps = PD.Values<typeof FxaaParams>
 export class FxaaPass {
     private readonly renderable: FxaaRenderable
 
-    constructor(webgl: WebGLContext, input: Texture) {
+    constructor(private webgl: WebGLContext, input: Texture) {
         this.renderable = getFxaaRenderable(webgl, input);
     }
 
+    private updateState(viewport: Viewport) {
+        const { gl, state } = this.webgl;
+
+        state.enable(gl.SCISSOR_TEST);
+        state.disable(gl.BLEND);
+        state.disable(gl.DEPTH_TEST);
+        state.depthMask(false);
+
+        const { x, y, width, height } = viewport;
+        gl.viewport(x, y, width, height);
+        gl.scissor(x, y, width, height);
+
+        state.clearColor(0, 0, 0, 1);
+        gl.clear(gl.COLOR_BUFFER_BIT);
+    }
+
     setSize(width: number, height: number) {
         ValueCell.update(this.renderable.values.uTexSizeInv, Vec2.set(this.renderable.values.uTexSizeInv.ref.value, 1 / width, 1 / height));
     }
@@ -64,7 +82,13 @@ export class FxaaPass {
         }
     }
 
-    render() {
+    render(viewport: Viewport, target: RenderTarget | undefined) {
+        if (target) {
+            target.bind();
+        } else {
+            this.webgl.unbindFramebuffer();
+        }
+        this.updateState(viewport);
         this.renderable.render();
     }
 }

+ 1 - 2
src/mol-canvas3d/passes/image.ts

@@ -17,7 +17,6 @@ import { Viewport } from '../camera/util';
 import { PixelData } from '../../mol-util/image';
 import { Helper } from '../helper/helper';
 import { CameraHelper, CameraHelperParams } from '../helper/camera-helper';
-import { Color } from '../../mol-util/color';
 
 export const ImageParams = {
     transparentBackground: PD.Boolean(false),
@@ -86,7 +85,7 @@ export class ImagePass {
             this.multiSampleHelper.render(this.renderer, this._camera, this.scene, this.helper, false, this.props.transparentBackground, this.props);
             this._colorTarget = this.multiSamplePass.colorTarget;
         } else {
-            this.drawPass.render(this.renderer, this._camera, this.scene, this.helper, false, Color(0xffffff), this.props.transparentBackground, this.props.postprocessing);
+            this.drawPass.render(this.renderer, this._camera, this.scene, this.helper, false, this.props.transparentBackground, this.props.postprocessing);
             this._colorTarget = this.drawPass.getColorTarget(this.props.postprocessing);
         }
     }

+ 3 - 4
src/mol-canvas3d/passes/multi-sample.ts

@@ -25,7 +25,6 @@ import { StereoCamera } from '../camera/stereo';
 
 import quad_vert from '../../mol-gl/shader/quad.vert';
 import compose_frag from '../../mol-gl/shader/compose.frag';
-import { Color } from '../../mol-util/color';
 
 const ComposeSchema = {
     ...QuadSchema,
@@ -143,7 +142,7 @@ export class MultiSamplePass {
             ValueCell.update(compose.values.uWeight, sampleWeight);
 
             // render scene
-            drawPass.render(renderer, camera, scene, helper, false, Color(0xffffff), transparentBackground, props.postprocessing);
+            drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing);
 
             // compose rendered scene with compose target
             composeTarget.bind();
@@ -193,7 +192,7 @@ export class MultiSamplePass {
         const sampleWeight = 1.0 / offsetList.length;
 
         if (sampleIndex === -1) {
-            drawPass.render(renderer, camera, scene, helper, false, Color(0xffffff), transparentBackground, props.postprocessing);
+            drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing);
             ValueCell.update(compose.values.uWeight, 1.0);
             ValueCell.update(compose.values.tColor, drawPass.getColorTarget(props.postprocessing).texture);
             compose.update();
@@ -221,7 +220,7 @@ export class MultiSamplePass {
                 camera.update();
 
                 // render scene
-                drawPass.render(renderer, camera, scene, helper, false, Color(0xffffff), transparentBackground, props.postprocessing);
+                drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing);
 
                 // compose rendered scene with compose target
                 composeTarget.bind();

+ 29 - 56
src/mol-canvas3d/passes/postprocessing.ts

@@ -184,26 +184,24 @@ const PostprocessingSchema = {
     uTexSize: UniformSpec('v2'),
 
     dOrthographic: DefineSpec('number'),
-    uInvProjection: UniformSpec('m4'),
     uNear: UniformSpec('f'),
     uFar: UniformSpec('f'),
     uFogNear: UniformSpec('f'),
     uFogFar: UniformSpec('f'),
     uFogColor: UniformSpec('v3'),
+    uTransparentBackground: UniformSpec('b'),
 
     uMaxPossibleViewZDiff: UniformSpec('f'),
 
     dOcclusionEnable: DefineSpec('boolean'),
 
     dOutlineEnable: DefineSpec('boolean'),
-    uOutlineScale: UniformSpec('f'),
+    dOutlineScale: DefineSpec('number'),
     uOutlineThreshold: UniformSpec('f'),
-
-    dPackedDepth: DefineSpec('boolean'),
 };
 type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
 
-function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture, packedDepth: boolean, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
+function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
     const values: Values<typeof PostprocessingSchema> = {
         ...QuadValues,
         tSsaoDepth: ValueCell.create(ssaoDepthTexture),
@@ -213,22 +211,20 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
         uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
 
         dOrthographic: ValueCell.create(0),
-        uInvProjection: ValueCell.create(Mat4.identity()),
         uNear: ValueCell.create(1),
         uFar: ValueCell.create(10000),
         uFogNear: ValueCell.create(10000),
         uFogFar: ValueCell.create(10000),
         uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
+        uTransparentBackground: ValueCell.create(false),
 
         uMaxPossibleViewZDiff: ValueCell.create(0.5),
 
         dOcclusionEnable: ValueCell.create(false),
 
         dOutlineEnable: ValueCell.create(false),
-        uOutlineScale: ValueCell.create(ctx.pixelRatio),
-        uOutlineThreshold: ValueCell.create(0.8),
-
-        dPackedDepth: ValueCell.create(packedDepth),
+        dOutlineScale: ValueCell.create(1),
+        uOutlineThreshold: ValueCell.create(0.33),
     };
 
     const schema = { ...PostprocessingSchema };
@@ -242,9 +238,9 @@ export const PostprocessingParams = {
     occlusion: PD.MappedStatic('off', {
         on: PD.Group({
             samples: PD.Numeric(64, {min: 1, max: 256, step: 1}),
-            radius: PD.Numeric(8.0, { min: 1, max: 64, step: 1 }),
-            bias: PD.Numeric(1.0, { min: 0, max: 1, step: 0.001 }),
-            blurKernelSize: PD.Numeric(13, { min: 1, max: 25, step: 2 }),
+            radius: PD.Numeric(24.0, { min: 1, max: 64, step: 1 }),
+            bias: PD.Numeric(1.2, { min: 0, max: 2, step: 0.1 }),
+            blurKernelSize: PD.Numeric(20, { min: 1, max: 25, step: 2 }),
         }),
         off: PD.Group({})
     }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
@@ -291,7 +287,7 @@ export class PostprocessingPass {
     private readonly renderable: PostprocessingRenderable
 
     constructor(private webgl: WebGLContext, drawPass: DrawPass) {
-        const { colorTarget, depthTexture, packedDepth } = drawPass;
+        const { colorTarget, depthTexture } = drawPass;
         const width = colorTarget.getWidth();
         const height = colorTarget.getHeight();
 
@@ -330,7 +326,7 @@ export class PostprocessingPass {
         this.ssaoRenderable = getSsaoRenderable(webgl, depthTexture);
         this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal');
         this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical');
-        this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture,  depthTexture, packedDepth, this.outlinesTarget.texture, this.ssaoDepthTexture);
+        this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture,  depthTexture, this.outlinesTarget.texture, this.ssaoDepthTexture);
     }
 
     setSize(width: number, height: number) {
@@ -349,14 +345,14 @@ export class PostprocessingPass {
         }
     }
 
-    private updateState(camera: ICamera, backgroundColor: Color, props: PostprocessingProps) {
+    private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
         let needsUpdateMain = false;
         let needsUpdateSsao = false;
         let needsUpdateSsaoBlur = false;
 
-        let orthographic = camera.state.mode === 'orthographic' ? 1 : 0;
-        let outlinesEnabled = props.outline.name === 'on';
-        let occlusionEnabled = props.occlusion.name === 'on';
+        const orthographic = camera.state.mode === 'orthographic' ? 1 : 0;
+        const outlinesEnabled = props.outline.name === 'on';
+        const occlusionEnabled = props.occlusion.name === 'on';
 
         let invProjection = Mat4.identity();
         Mat4.invert(invProjection, camera.projection);
@@ -400,26 +396,26 @@ export class PostprocessingPass {
         }
 
         if (props.outline.name === 'on') {
-            let factor = Math.pow(1000, props.outline.params.threshold) / 1000;
-            let maxPossibleViewZDiff = factor * (camera.far - camera.near);
+            const factor = Math.pow(1000, props.outline.params.threshold) / 1000;
+            const maxPossibleViewZDiff = factor * (camera.far - camera.near);
+            const outlineScale = props.outline.params.scale - 1;
 
             ValueCell.updateIfChanged(this.outlinesRenderable.values.uNear, camera.near);
             ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far);
             ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
 
-            ValueCell.updateIfChanged(this.renderable.values.uInvProjection, invProjection);
             ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
-            let fogColor = Vec3();
-            Color.toVec3Normalized(fogColor, backgroundColor);
-            ValueCell.updateIfChanged(this.renderable.values.uFogColor, fogColor);
-            ValueCell.updateIfChanged(this.renderable.values.uOutlineScale, props.outline.params.scale - 1);
             ValueCell.updateIfChanged(this.renderable.values.uOutlineThreshold, props.outline.params.threshold);
+            if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; }
+            ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale);
         }
 
         ValueCell.updateIfChanged(this.renderable.values.uFar, camera.far);
         ValueCell.updateIfChanged(this.renderable.values.uNear, camera.near);
         ValueCell.updateIfChanged(this.renderable.values.uFogFar, camera.fogFar);
         ValueCell.updateIfChanged(this.renderable.values.uFogNear, camera.fogNear);
+        ValueCell.update(this.renderable.values.uFogColor, Color.toVec3Normalized(this.renderable.values.uFogColor.ref.value, backgroundColor));
+        ValueCell.updateIfChanged(this.renderable.values.uTransparentBackground, transparentBackground);
         if (this.renderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateMain = true; }
         ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic);
         if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; }
@@ -452,8 +448,8 @@ export class PostprocessingPass {
         gl.scissor(x, y, width, height);
     }
 
-    render(camera: ICamera, toDrawingBuffer: boolean, backgroundColor: Color, props: PostprocessingProps) {
-        this.updateState(camera, backgroundColor, props);
+    render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
+        this.updateState(camera, transparentBackground, backgroundColor, props);
 
         if (props.outline.name === 'on') {
             this.outlinesTarget.bind();
@@ -494,7 +490,7 @@ export class AntialiasingPass {
     private readonly fxaa: FxaaPass
     private readonly smaa: SmaaPass
 
-    constructor(private webgl: WebGLContext, private drawPass: DrawPass) {
+    constructor(webgl: WebGLContext, private drawPass: DrawPass) {
         const { colorTarget } = drawPass;
         const width = colorTarget.getWidth();
         const height = colorTarget.getHeight();
@@ -505,7 +501,9 @@ export class AntialiasingPass {
     }
 
     setSize(width: number, height: number) {
-        const [w, h] = [this.target.texture.getWidth(), this.target.texture.getHeight()];
+        const w = this.target.texture.getWidth();
+        const h = this.target.texture.getHeight();
+
         if (width !== w || height !== h) {
             this.target.setSize(width, height);
             this.fxaa.setSize(width, height);
@@ -513,22 +511,6 @@ export class AntialiasingPass {
         }
     }
 
-    private updateState(camera: ICamera) {
-        const { gl, state } = this.webgl;
-
-        state.enable(gl.SCISSOR_TEST);
-        state.disable(gl.BLEND);
-        state.disable(gl.DEPTH_TEST);
-        state.depthMask(false);
-
-        const { x, y, width, height } = camera.viewport;
-        gl.viewport(x, y, width, height);
-        gl.scissor(x, y, width, height);
-
-        state.clearColor(0, 0, 0, 1);
-        gl.clear(gl.COLOR_BUFFER_BIT);
-    }
-
     private _renderFxaa(camera: ICamera, toDrawingBuffer: boolean, props: PostprocessingProps) {
         if (props.antialiasing.name !== 'fxaa') return;
 
@@ -536,15 +518,7 @@ export class AntialiasingPass {
             ? this.drawPass.postprocessing.target.texture
             : this.drawPass.colorTarget.texture;
         this.fxaa.update(input, props.antialiasing.params);
-
-        if (toDrawingBuffer) {
-            this.webgl.unbindFramebuffer();
-        } else {
-            this.target.bind();
-        }
-
-        this.updateState(camera);
-        this.fxaa.render();
+        this.fxaa.render(camera.viewport, toDrawingBuffer ? undefined : this.target);
     }
 
     private _renderSmaa(camera: ICamera, toDrawingBuffer: boolean, props: PostprocessingProps) {
@@ -554,7 +528,6 @@ export class AntialiasingPass {
             ? this.drawPass.postprocessing.target.texture
             : this.drawPass.colorTarget.texture;
         this.smaa.update(input, props.antialiasing.params);
-
         this.smaa.render(camera.viewport, toDrawingBuffer ? undefined : this.target);
     }
 

+ 1 - 3
src/mol-gl/renderer.ts

@@ -632,9 +632,7 @@ namespace Renderer {
                 }
             },
 
-            get props() {
-                return p;
-            },
+            props: p,
             get stats(): RendererStats {
                 return {
                     programCount: ctx.stats.resourceCounts.program,

+ 4 - 1
src/mol-gl/shader/chunks/apply-fog.glsl.ts

@@ -1,5 +1,8 @@
 export default `
-float fogDepth = length(vViewPosition);
+float viewZ = uIsOrtho == 1.0
+    ? orthographicDepthToViewZ(fragmentDepth, uNear, uFar)
+    : perspectiveDepthToViewZ(fragmentDepth, uNear, uFar);
+float fogDepth = abs(viewZ);
 float fogFactor = smoothstep(uFogNear, uFogFar, fogDepth);
 float fogAlpha = (1.0 - fogFactor) * gl_FragColor.a;
 float preFogAlpha = gl_FragColor.a;

+ 4 - 0
src/mol-gl/shader/chunks/common-frag-params.glsl.ts

@@ -31,6 +31,10 @@ varying vec3 vViewPosition;
 
 uniform vec2 uViewOffset;
 
+uniform float uNear;
+uniform float uFar;
+uniform float uIsOrtho;
+
 uniform float uFogNear;
 uniform float uFogFar;
 uniform vec3 uFogColor;

+ 10 - 2
src/mol-gl/shader/chunks/common.glsl.ts

@@ -28,7 +28,7 @@ export default `
 float intDiv(const in float a, const in float b) { return float(int(a) / int(b)); }
 float intMod(const in float a, const in float b) { return a - b * float(int(a) / int(b)); }
 
-float pow2(const in float x) { return x*x; }
+float pow2(const in float x) { return x * x; }
 
 const float maxFloat = 10000.0; // NOTE constant also set in TypeScript
 const float floatLogFactor = 9.210440366976517; // log(maxFloat + 1.0);
@@ -90,10 +90,18 @@ vec4 linearTosRGB(const in vec4 c) {
     return vec4(mix(pow(c.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), c.rgb * 12.92, vec3(lessThanEqual(c.rgb, vec3(0.0031308)))), c.a);
 }
 
-float linearizeDepth(in float depth, in float near, in float far) {
+float linearizeDepth(const in float depth, const in float near, const in float far) {
     return (2.0 * near) / (far + near - depth * (far - near));
 }
 
+float perspectiveDepthToViewZ(const in float invClipZ, const in float near, const in float far) {
+    return (near * far) / ((far - near) * invClipZ - far);
+}
+
+float orthographicDepthToViewZ(const in float linearClipZ, const in float near, const in float far) {
+    return linearClipZ * (near - far) - near;
+}
+
 #if __VERSION__ != 300
     // transpose
 

+ 1 - 2
src/mol-gl/shader/cylinders.frag.ts

@@ -17,7 +17,6 @@ varying float vSize;
 varying float vCap;
 
 uniform vec3 uCameraDir;
-uniform float uIsOrtho;
 uniform vec3 uCameraPosition;
 
 #include common
@@ -132,9 +131,9 @@ void main() {
 
         #include apply_interior_color
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragDepthEXT;
+        #include apply_fog
         #include wboit_write
     #endif
 }

+ 6 - 3
src/mol-gl/shader/direct-volume.frag.ts

@@ -30,8 +30,6 @@ uniform vec3 uCameraDir;
 
 uniform sampler2D tDepth;
 uniform vec2 uDrawingBufferSize;
-uniform float uNear;
-uniform float uFar;
 
 varying vec3 vOrigPos;
 varying float vInstance;
@@ -70,6 +68,8 @@ uniform bool uInteriorColorFlag;
 uniform vec3 uInteriorColor;
 bool interior;
 
+uniform float uNear;
+uniform float uFar;
 uniform float uIsOrtho;
 
 uniform vec3 uCellDim;
@@ -166,6 +166,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
     vec4 src = vec4(0.0);
     vec4 dst = vec4(0.0);
     bool hit = false;
+    float fragmentDepth;
 
     vec3 posMin = vec3(0.0);
     vec3 posMax = vec3(1.0) - vec3(1.0) / uGridDim;
@@ -325,6 +326,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
                     #include apply_marker_color
 
                     preFogAlphaBlended = (1.0 - preFogAlphaBlended) * gl_FragColor.a + preFogAlphaBlended;
+                    fragmentDepth = depth;
                     #include apply_fog
 
                     src = gl_FragColor;
@@ -393,6 +395,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
                 #include apply_marker_color
 
                 preFogAlphaBlended = (1.0 - preFogAlphaBlended) * gl_FragColor.a + preFogAlphaBlended;
+                fragmentDepth = calcDepth(mvPosition.xyz);
                 #include apply_fog
 
                 src = gl_FragColor;
@@ -424,7 +427,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
 // TODO: support float texture for higher precision values???
 // TODO: support clipping exclusion texture support
 
-void main () {
+void main() {
     if (gl_FrontFacing)
         discard;
 

+ 1 - 1
src/mol-gl/shader/image.frag.ts

@@ -122,10 +122,10 @@ void main() {
         float group = decodeFloatRGB(texture2D(tGroupTex, vUv).rgb);
         float vMarker = readFromTexture(tMarker, vInstance * float(uGroupCount) + group, uMarkerTexDim).a;
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragCoord.z;
         bool interior = false;
+        #include apply_fog
         #include wboit_write
     #endif
 }

+ 1 - 1
src/mol-gl/shader/lines.frag.ts

@@ -27,10 +27,10 @@ void main(){
         gl_FragColor = material;
 
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragCoord.z;
         bool interior = false;
+        #include apply_fog
         #include wboit_write
     #endif
 }

+ 1 - 1
src/mol-gl/shader/mesh.frag.ts

@@ -59,9 +59,9 @@ void main() {
 
         #include apply_interior_color
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragCoord.z;
+        #include apply_fog
         #include wboit_write
     #endif
 }

+ 1 - 9
src/mol-gl/shader/outlines.frag.ts

@@ -19,14 +19,6 @@ uniform float uMaxPossibleViewZDiff;
 
 #include common
 
-float perspectiveDepthToViewZ(const in float invClipZ, const in float near, const in float far) {
-    return (near * far) / ((far - near) * invClipZ - far);
-}
-
-float orthographicDepthToViewZ(const in float linearClipZ, const in float near, const in float far) {
-    return linearClipZ * (near - far) - near;
-}
-
 float getViewZ(const in float depth) {
     #if dOrthographic == 1
         return orthographicDepthToViewZ(depth, uNear, uFar);
@@ -45,7 +37,7 @@ bool isBackground(const in float depth) {
 
 void main(void) {
     float backgroundViewZ = uFar + 3.0 * uMaxPossibleViewZDiff;
-    
+
     vec2 coords = gl_FragCoord.xy / uTexSize;
     vec2 invTexSize = 1.0 / uTexSize;
 

+ 1 - 1
src/mol-gl/shader/points.frag.ts

@@ -41,10 +41,10 @@ void main(){
         #endif
 
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragCoord.z;
         bool interior = false;
+        #include apply_fog
         #include wboit_write
     #endif
 }

+ 26 - 26
src/mol-gl/shader/postprocessing.frag.ts

@@ -16,12 +16,12 @@ uniform sampler2D tDepth;
 uniform sampler2D tOutlines;
 uniform vec2 uTexSize;
 
-uniform mat4 uInvProjection;
 uniform float uNear;
 uniform float uFar;
 uniform float uFogNear;
 uniform float uFogFar;
 uniform vec3 uFogColor;
+uniform bool uTransparentBackground;
 
 uniform float uOcclusionBias;
 uniform float uOcclusionRadius;
@@ -31,18 +31,10 @@ uniform float uOutlineThreshold;
 
 uniform float uMaxPossibleViewZDiff;
 
-const vec4 occlusionColor = vec4(0.0, 0.0, 0.0, 1.0);
+const vec3 occlusionColor = vec3(0.0);
 
 #include common
 
-float perspectiveDepthToViewZ(const in float invClipZ, const in float near, const in float far) {
-    return (near * far) / ((far - near) * invClipZ - far);
-}
-
-float orthographicDepthToViewZ(const in float linearClipZ, const in float near, const in float far) {
-    return linearClipZ * (near - far) - near;
-}
-
 float getViewZ(const in float depth) {
     #if dOrthographic == 1
         return orthographicDepthToViewZ(depth, uNear, uFar);
@@ -64,25 +56,23 @@ float getOutline(const in vec2 coords, out float closestTexel) {
     vec2 invTexSize = 1.0 / uTexSize;
 
     float selfDepth = getDepth(coords);
-    float selfViewZ = isBackground(selfDepth) ? backgroundViewZ : getViewZ(getDepth(coords));
+    float selfViewZ = isBackground(selfDepth) ? backgroundViewZ : getViewZ(selfDepth);
 
     float outline = 1.0;
-    closestTexel = backgroundViewZ;
-    for (float y = -uOutlineScale; y <= uOutlineScale; y++) {
-        for (float x = -uOutlineScale; x <= uOutlineScale; x++) {
-            if (x * x + y * y > uOutlineScale * uOutlineScale) {
+    closestTexel = 1.0;
+    for (int y = -dOutlineScale; y <= dOutlineScale; y++) {
+        for (int x = -dOutlineScale; x <= dOutlineScale; x++) {
+            if (x * x + y * y > dOutlineScale * dOutlineScale) {
                 continue;
             }
 
-            vec2 sampleCoords = coords + vec2(x, y) * invTexSize;
+            vec2 sampleCoords = coords + vec2(float(x), float(y)) * invTexSize;
 
             vec4 sampleOutlineCombined = texture2D(tOutlines, sampleCoords);
             float sampleOutline = sampleOutlineCombined.r;
             float sampleOutlineDepth = unpackRGToUnitInterval(sampleOutlineCombined.gb);
 
-            float sampleOutlineViewDirLength = length(screenSpaceToViewSpace(vec3(sampleCoords, sampleOutlineDepth), uInvProjection));
-
-            if (sampleOutline == 0.0 && sampleOutlineViewDirLength < closestTexel && abs(selfViewZ - sampleOutlineDepth) > uMaxPossibleViewZDiff) {
+            if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineDepth) > uMaxPossibleViewZDiff) {
                 outline = 0.0;
                 closestTexel = sampleOutlineDepth;
             }
@@ -92,7 +82,7 @@ float getOutline(const in vec2 coords, out float closestTexel) {
 }
 
 float getSsao(vec2 coords) {
-    float rawSsao = unpackRGToUnitInterval(texture(tSsaoDepth, coords).xy);
+    float rawSsao = unpackRGToUnitInterval(texture2D(tSsaoDepth, coords).xy);
     if (rawSsao > 0.999) {
         return 1.0;
     } else if (rawSsao > 0.001) {
@@ -103,7 +93,10 @@ float getSsao(vec2 coords) {
 
 void main(void) {
     vec2 coords = gl_FragCoord.xy / uTexSize;
-    vec4 color = texture(tColor, coords);
+    vec4 color = texture2D(tColor, coords);
+
+    float viewDist;
+    float fogFactor;
 
     #ifdef dOutlineEnable
         float closestTexel;
@@ -111,12 +104,13 @@ void main(void) {
 
         if (outline == 0.0) {
             color.rgb *= outline;
-            float viewDist = abs(getViewZ(closestTexel));
-            float fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
-            if (color.a != 1.0) {
+            viewDist = abs(getViewZ(closestTexel));
+            fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
+            if (!uTransparentBackground) {
+                color.rgb = mix(color.rgb, uFogColor, fogFactor);
+            } else {
                 color.a = 1.0 - fogFactor;
             }
-            color.rgb = mix(color.rgb, uFogColor, fogFactor);
         }
     #endif
 
@@ -124,8 +118,14 @@ void main(void) {
     #ifdef dOcclusionEnable
         float depth = getDepth(coords);
         if (!isBackground(depth)) {
+            viewDist = abs(getViewZ(depth));
+            fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
             float occlusionFactor = getSsao(coords);
-            color = mix(occlusionColor, color, occlusionFactor);
+            if (!uTransparentBackground) {
+                color.rgb = mix(mix(occlusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor);
+            } else {
+                color.rgb = mix(occlusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor);
+            }
         }
     #endif
 

+ 1 - 4
src/mol-gl/shader/spheres.frag.ts

@@ -15,9 +15,6 @@ precision highp int;
 #include common_clip
 #include wboit_params
 
-uniform float uClipNear;
-uniform float uIsOrtho;
-
 varying float vRadius;
 varying float vRadiusSq;
 varying vec3 vPoint;
@@ -98,9 +95,9 @@ void main(void){
 
         #include apply_interior_color
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragDepthEXT;
+        #include apply_fog
         #include wboit_write
     #endif
 }

+ 5 - 13
src/mol-gl/shader/ssao-blur.frag.ts

@@ -24,14 +24,6 @@ uniform float uFar;
 
 #include common
 
-float perspectiveDepthToViewZ(const in float invClipZ, const in float near, const in float far) {
-    return (near * far) / ((far - near) * invClipZ - far);
-}
-
-float orthographicDepthToViewZ(const in float linearClipZ, const in float near, const in float far) {
-    return linearClipZ * (near - far) - near;
-}
-
 float getViewZ(const in float depth) {
     #if dOrthographic == 1
         return orthographicDepthToViewZ(depth, uNear, uFar);
@@ -47,7 +39,7 @@ bool isBackground(const in float depth) {
 void main(void) {
     vec2 coords = gl_FragCoord.xy / uTexSize;
 
-    vec2 packedDepth = texture(tSsaoDepth, coords).zw;
+    vec2 packedDepth = texture2D(tSsaoDepth, coords).zw;
 
     float selfDepth = unpackRGToUnitInterval(packedDepth);
     // if background and if second pass
@@ -66,27 +58,27 @@ void main(void) {
     for (int i = -dOcclusionKernelSize / 2; i <= dOcclusionKernelSize / 2; i++) {
         vec2 sampleCoords = coords + float(i) * offset;
 
-        vec4 sampleSsaoDepth = texture(tSsaoDepth, sampleCoords);
+        vec4 sampleSsaoDepth = texture2D(tSsaoDepth, sampleCoords);
 
         float sampleDepth = unpackRGToUnitInterval(sampleSsaoDepth.zw);
         if (isBackground(sampleDepth)) {
             continue;
         }
 
-        if (abs(i) > 1) {
+        if (abs(float(i)) > 1.0) { // abs is not defined for int in webgl1
             float sampleViewZ = getViewZ(sampleDepth);
             if (abs(selfViewZ - sampleViewZ) > uMaxPossibleViewZDiff) {
                 continue;
             }
         }
 
-        float kernel = uKernel[abs(i)];
+        float kernel = uKernel[int(abs(float(i)))]; // abs is not defined for int in webgl1
         float sampleValue = unpackRGToUnitInterval(sampleSsaoDepth.xy);
 
         sum += kernel * sampleValue;
         kernelSum += kernel;
     }
-    
+
     gl_FragColor = vec4(packUnitIntervalToRG(sum / kernelSum), packedDepth);
 }
 `;

+ 1 - 1
src/mol-gl/shader/text.frag.ts

@@ -65,10 +65,10 @@ void main(){
         gl_FragColor = material;
     #elif defined(dRenderVariant_color)
         #include apply_marker_color
-        #include apply_fog
 
         float fragmentDepth = gl_FragCoord.z;
         bool interior = false;
+        #include apply_fog
         #include wboit_write
     #endif
 }