Pārlūkot izejas kodu

added renderBlended postprocessing

AronKovacs 4 gadi atpakaļ
vecāks
revīzija
560e40773f

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

@@ -221,9 +221,9 @@ export class DrawPass {
         this.wboit.render();
     }
 
-    private _renderBlended(renderer: Renderer, camera: ICamera, scene: Scene, toDrawingBuffer: boolean, postprocessingProps: PostprocessingProps) {
+    private _renderBlended(renderer: Renderer, camera: ICamera, scene: Scene, backgroundColor: Color, toDrawingBuffer: boolean, postprocessingProps: PostprocessingProps) {
         if (toDrawingBuffer) {
-            this.webgl.unbindFramebuffer();
+            this.drawTarget.bind();
         } else {
             this.colorTarget.bind();
             if (!this.packedDepth) {
@@ -234,22 +234,22 @@ export class DrawPass {
         renderer.clear(true);
         renderer.renderBlendedOpaque(scene.primitives, camera, 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();
-            renderer.clear(false);
-            renderer.renderDepth(scene.primitives, camera, null);
-            this.colorTarget.bind();
-        }
-
-        // do direct-volume rendering
         if (!toDrawingBuffer) {
+            // do a depth pass if not rendering to drawing buffer and
+            // extensions.depthTexture is unsupported (i.e. depthTarget is set)
+            if (this.depthTargetPrimitives) {
+                this.depthTargetPrimitives.bind();
+                renderer.clear(false);
+                renderer.renderDepth(scene.primitives, camera, null);
+                this.colorTarget.bind();
+            }
+
+            // do direct-volume rendering
             if (!this.packedDepth) {
                 this.depthTextureVolumes.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
                 renderer.clearDepth(); // from previous frame
             }
-            renderer.renderBlendedVolume(scene.volumes, camera, this.depthTexturePrimitives);
+            renderer.renderBlendedVolumeOpaque(scene.volumes, camera, this.depthTexturePrimitives);
 
             // do volume depth pass if extensions.depthTexture is unsupported (i.e. depthTarget is set)
             if (this.depthTargetVolumes) {
@@ -259,21 +259,34 @@ export class DrawPass {
                 this.colorTarget.bind();
             }
 
-            if (!this.packedDepth) {
-                this.depthTexturePrimitives.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
+            // merge depths from primitive and volume rendering
+            this._depthMerge();
+            this.colorTarget.bind();
+
+            if (PostprocessingPass.isEnabled(postprocessingProps)) {
+                this.postprocessing.render(camera, false, backgroundColor, postprocessingProps);
+            }
+            renderer.renderBlendedVolumeTransparent(scene.volumes, camera, this.depthTexturePrimitives);
+
+            if (PostprocessingPass.isEnabled(postprocessingProps)) {
+                if (!this.packedDepth) {
+                    this.depthTexturePrimitives.attachFramebuffer(this.postprocessing.target.framebuffer, 'depth');
+                }
+                this.postprocessing.target.bind();
+            } else {
+                if (!this.packedDepth) {
+                    this.depthTexturePrimitives.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
+                }
+                this.colorTarget.bind();
             }
         }
 
         renderer.renderBlendedTransparent(scene.primitives, camera, null);
-
-        // merge depths from primitive and volume rendering
-        if (!toDrawingBuffer) {
-            this._depthMerge();
-            this.colorTarget.bind();
-        }
     }
 
     private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, backgroundColor: Color, postprocessingProps: PostprocessingProps) {
+        const volumeRendering = scene.volumes.renderables.length > 0;
+        const postprocessingEnabled = PostprocessingPass.isEnabled(postprocessingProps);
         const antialiasingEnabled = FxaaPass.isEnabled(postprocessingProps);
 
         const { x, y, width, height } = camera.viewport;
@@ -283,13 +296,15 @@ export class DrawPass {
         if (this.wboitEnabled) {
             this._renderWboit(renderer, camera, scene, backgroundColor, postprocessingProps);
         } else {
-            this._renderBlended(renderer, camera, scene, !antialiasingEnabled && toDrawingBuffer, postprocessingProps);
+            this._renderBlended(renderer, camera, scene, backgroundColor, !volumeRendering && !postprocessingEnabled && !antialiasingEnabled && toDrawingBuffer, postprocessingProps);
         }
 
         if (PostprocessingPass.isEnabled(postprocessingProps)) {
             this.postprocessing.target.bind();
-        } else {
+        } else if (!toDrawingBuffer || volumeRendering || this.wboitEnabled) {
             this.colorTarget.bind();
+        } else {
+            this.drawTarget.bind();
         }
 
         if (helper.debug.isEnabled) {
@@ -310,9 +325,10 @@ export class DrawPass {
         } else if (toDrawingBuffer) {
             this.drawTarget.bind();
 
+            this.webgl.state.disable(this.webgl.gl.DEPTH_TEST);
             if (PostprocessingPass.isEnabled(postprocessingProps)) {
                 this.copyFboPostprocessing.render();
-            } else {
+            } else if (volumeRendering || this.wboitEnabled) {
                 this.copyFboTarget.render();
             }
         }

+ 10 - 68
src/mol-canvas3d/passes/postprocessing.ts

@@ -264,7 +264,7 @@ export const PostprocessingParams = {
     }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
     outline: PD.MappedStatic('off', {
         on: PD.Group({
-            scale: PD.Numeric(1, { min: 0, max: 5, step: 1 }),
+            scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }),
             threshold: PD.Numeric(0.1, { min: 0.01, max: 1, step: 0.01 }),
         }),
         off: PD.Group({})
@@ -313,7 +313,7 @@ export class PostprocessingPass {
         const height = colorTarget.getHeight();
 
         this.nSamples = 64;
-        this.blurKernelSize = 3;
+        this.blurKernelSize = 13;
 
         this.target = webgl.createRenderTarget(width, height, false, 'uint8', 'linear');
 
@@ -365,9 +365,10 @@ export class PostprocessingPass {
         let outlinesEnabled = props.outline.name === 'on';
         let occlusionEnabled = props.occlusion.name === 'on';
 
+        let invProjection = Mat4.identity();
+        Mat4.invert(invProjection, camera.projection);
+
         if (props.occlusion.name === 'on') {
-            let invProjection = Mat4.identity();
-            Mat4.invert(invProjection, camera.projection);
             ValueCell.updateIfChanged(this.ssaoRenderable.values.uProjection, camera.projection);
             ValueCell.updateIfChanged(this.ssaoRenderable.values.uInvProjection, invProjection);
 
@@ -413,8 +414,10 @@ export class PostprocessingPass {
             ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
 
             ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
-            ValueCell.updateIfChanged(this.renderable.values.uFogColor, Color.toVec3Normalized(this.renderable.values.uFogColor.ref.value, backgroundColor));
-            ValueCell.updateIfChanged(this.renderable.values.uOutlineScale, props.outline.params.scale);
+            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);
         }
 
@@ -444,14 +447,6 @@ export class PostprocessingPass {
 
         const { gl, state } = this.webgl;
 
-        state.disable(gl.SCISSOR_TEST);
-        state.disable(gl.BLEND);
-        state.disable(gl.DEPTH_TEST);
-        state.depthMask(false);
-
-        /*
-        const { gl, state } = this.webgl;
-
         state.enable(gl.SCISSOR_TEST);
         state.disable(gl.BLEND);
         state.disable(gl.DEPTH_TEST);
@@ -460,9 +455,6 @@ export class PostprocessingPass {
         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);*/
     }
 
     render(camera: ICamera, toDrawingBuffer: boolean, backgroundColor: Color, props: PostprocessingProps) {
@@ -496,53 +488,6 @@ export class PostprocessingPass {
 
         this.renderable.render();
     }
-
-    _render(camera: ICamera, toDrawingBuffer: boolean, props: PostprocessingProps) {
-        const { values } = this.renderable;
-
-        ValueCell.updateIfChanged(values.uFar, camera.far);
-        ValueCell.updateIfChanged(values.uNear, camera.near);
-        ValueCell.updateIfChanged(values.uFogFar, camera.fogFar);
-        ValueCell.updateIfChanged(values.uFogNear, camera.fogNear);
-
-        let needsUpdate = false;
-
-        const orthographic = camera.state.mode === 'orthographic' ? 1 : 0;
-        if (values.dOrthographic.ref.value !== orthographic) needsUpdate = true;
-        ValueCell.updateIfChanged(values.dOrthographic, orthographic);
-
-        const occlusion = props.occlusion.name === 'on';
-        if (values.dOcclusionEnable.ref.value !== occlusion) needsUpdate = true;
-        ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusion);
-        if (props.occlusion.name === 'on') {
-            // const { kernelSize } = props.occlusion.params;
-            // if (values.dOcclusionKernelSize.ref.value !== kernelSize) needsUpdate = true;
-            // ValueCell.updateIfChanged(values.dOcclusionKernelSize, kernelSize);
-            // ValueCell.updateIfChanged(values.uOcclusionBias, props.occlusion.params.bias);
-            // ValueCell.updateIfChanged(values.uOcclusionRadius, props.occlusion.params.radius);
-        }
-
-        const outline = props.outline.name === 'on';
-        if (values.dOutlineEnable.ref.value !== outline) needsUpdate = true;
-        ValueCell.updateIfChanged(values.dOutlineEnable, outline);
-        if (props.outline.name === 'on') {
-            ValueCell.updateIfChanged(values.uOutlineScale, props.outline.params.scale * this.webgl.pixelRatio);
-            ValueCell.updateIfChanged(values.uOutlineThreshold, props.outline.params.threshold);
-        }
-
-        if (needsUpdate) {
-            this.renderable.update();
-        }
-
-        if (toDrawingBuffer) {
-            this.webgl.unbindFramebuffer();
-        } else {
-            this.target.bind();
-        }
-
-        // this.updateState(camera);
-        this.renderable.render();
-    }
 }
 
 export class FxaaPass {
@@ -573,7 +518,7 @@ export class FxaaPass {
     private updateState(camera: ICamera) {
         const { gl, state } = this.webgl;
 
-        state.disable(gl.SCISSOR_TEST);
+        state.enable(gl.SCISSOR_TEST);
         state.disable(gl.BLEND);
         state.disable(gl.DEPTH_TEST);
         state.depthMask(false);
@@ -581,9 +526,6 @@ export class FxaaPass {
         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);
     }
 
     render(camera: ICamera, toDrawingBuffer: boolean, props: PostprocessingProps) {

+ 31 - 4
src/mol-gl/renderer.ts

@@ -51,7 +51,8 @@ interface Renderer {
     renderBlended: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderBlendedOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderBlendedTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
-    renderBlendedVolume: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
+    renderBlendedVolumeOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
+    renderBlendedVolumeTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderWboitOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderWboitTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
 
@@ -452,7 +453,7 @@ namespace Renderer {
             }
         };
 
-        const renderBlendedVolume = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
+        const renderBlendedVolumeOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
             state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
             state.enable(gl.BLEND);
 
@@ -461,7 +462,32 @@ namespace Renderer {
             const { renderables } = group;
             for (let i = 0, il = renderables.length; i < il; ++i) {
                 const r = renderables[i];
-                renderObject(r, 'colorBlended');
+
+                // TODO: simplify, handle on renderable.state???
+                // uAlpha is updated in "render" so we need to recompute it here
+                const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
+                if (alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && !r.values.dXrayShaded?.ref.value) {
+                    renderObject(r, 'colorBlended');
+                }
+            }
+        };
+
+        const renderBlendedVolumeTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
+            state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+            state.enable(gl.BLEND);
+
+            updateInternal(group, camera, depthTexture, false);
+
+            const { renderables } = group;
+            for (let i = 0, il = renderables.length; i < il; ++i) {
+                const r = renderables[i];
+
+                // TODO: simplify, handle on renderable.state???
+                // uAlpha is updated in "render" so we need to recompute it here
+                const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
+                if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dXrayShaded?.ref.value) {
+                    renderObject(r, 'colorBlended');
+                }
             }
         };
 
@@ -530,7 +556,8 @@ namespace Renderer {
             renderBlended,
             renderBlendedOpaque,
             renderBlendedTransparent,
-            renderBlendedVolume,
+            renderBlendedVolumeOpaque,
+            renderBlendedVolumeTransparent,
             renderWboitOpaque,
             renderWboitTransparent,