Browse Source

refactored wboit into seperate pass

Alexander Rose 4 years ago
parent
commit
9bc256bdab

+ 19 - 12
src/mol-canvas3d/passes/draw.ts

@@ -22,6 +22,7 @@ import { Helper } from '../helper/helper';
 import quad_vert from '../../mol-gl/shader/quad.vert';
 import depthMerge_frag from '../../mol-gl/shader/depth-merge.frag';
 import { StereoCamera } from '../camera/stereo';
+import { WboitPass } from './wboit';
 
 const DepthMergeSchema = {
     ...QuadSchema,
@@ -62,6 +63,8 @@ export class DrawPass {
     private depthTextureVolumes: Texture
     private depthMerge: DepthMergeRenderable
 
+    private wboit: WboitPass
+
     constructor(private webgl: WebGLContext, width: number, height: number) {
         const { extensions, resources } = webgl;
 
@@ -84,6 +87,8 @@ export class DrawPass {
             this.depthTextureVolumes.define(width, height);
         }
         this.depthMerge = getDepthMergeRenderable(webgl, this.depthTexturePrimitives, this.depthTextureVolumes, this.packedDepth);
+
+        this.wboit = new WboitPass(webgl, width, height);
     }
 
     setSize(width: number, height: number) {
@@ -112,6 +117,8 @@ export class DrawPass {
             }
 
             ValueCell.update(this.depthMerge.values.uTexSize, Vec2.set(this.depthMerge.values.uTexSize.ref.value, width, height));
+
+            this.wboit.setSize(width, height);
         }
     }
 
@@ -135,45 +142,45 @@ export class DrawPass {
         // extensions.depthTexture is unsupported (i.e. depthTarget is set)
         if (!toDrawingBuffer && this.depthTargetPrimitives) {
             console.log('packed depth opaque primitives');
-            renderer.render(this.depthTargetPrimitives, scene.primitives, camera, 'depth', true, transparentBackground, 1, null, false);
+            renderer.render(this.depthTargetPrimitives, scene.primitives, camera, 'depth', true, transparentBackground, 1, null, false, this.wboit);
         }
 
         // render opaque color
-        renderer.render(renderTarget, scene.primitives, camera, 'color', true, transparentBackground, 1, null, false);
+        renderer.render(renderTarget, scene.primitives, camera, 'color', true, transparentBackground, 1, null, false, this.wboit);
 
         if (helper.debug.isEnabled) {
             helper.debug.syncVisibility();
-            renderer.render(renderTarget, helper.debug.scene, camera, 'color', false, transparentBackground, 1, null, false);
+            renderer.render(renderTarget, helper.debug.scene, camera, 'color', false, transparentBackground, 1, null, false, this.wboit);
         }
         if (helper.handle.isEnabled) {
-            renderer.render(renderTarget, helper.handle.scene, camera, 'color', false, transparentBackground, 1, null, false);
+            renderer.render(renderTarget, helper.handle.scene, camera, 'color', false, transparentBackground, 1, null, false, this.wboit);
         }
         if (helper.camera.isEnabled) {
             helper.camera.update(camera);
-            renderer.render(renderTarget, helper.camera.scene, helper.camera.camera, 'color', false, transparentBackground, 1, null, false);
+            renderer.render(renderTarget, helper.camera.scene, helper.camera.camera, 'color', false, transparentBackground, 1, null, false, this.wboit);
         }
 
         if (!toDrawingBuffer && this.depthTargetPrimitivesTransparent) {
             console.log('packed depth transparent primitives');
-            renderer.render(this.depthTargetPrimitivesTransparent, scene.primitives, camera, 'depth', true, transparentBackground, 1, null, false);
+            renderer.render(this.depthTargetPrimitivesTransparent, scene.primitives, camera, 'depth', true, transparentBackground, 1, null, false, this.wboit);
         }
 
         // render transparent color
         if (renderTarget !== null) {
             this.depthTexturePrimitivesTransparent.attachFramebuffer(renderTarget.framebuffer, 'depth');
-            renderer.render(renderTarget, scene.primitives, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true);
+            renderer.render(renderTarget, scene.primitives, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true, this.wboit);
         }
 
         if (helper.debug.isEnabled) {
             helper.debug.syncVisibility();
-            renderer.render(renderTarget, helper.debug.scene, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true);
+            renderer.render(renderTarget, helper.debug.scene, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true, this.wboit);
         }
         if (helper.handle.isEnabled) {
-            renderer.render(renderTarget, helper.handle.scene, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true);
+            renderer.render(renderTarget, helper.handle.scene, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true, this.wboit);
         }
         if (helper.camera.isEnabled) {
             helper.camera.update(camera);
-            renderer.render(renderTarget, helper.camera.scene, helper.camera.camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true);
+            renderer.render(renderTarget, helper.camera.scene, helper.camera.camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true, this.wboit);
         }
 
         // do direct-volume rendering
@@ -187,12 +194,12 @@ export class DrawPass {
                 this.webgl.gl.scissor(x, y, width, height);
                 this.webgl.gl.clear(this.webgl.gl.DEPTH_BUFFER_BIT);
             }
-            renderer.render(renderTarget, scene.volumes, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true);
+            renderer.render(renderTarget, scene.volumes, camera, 'color', false, transparentBackground, 1, this.depthTexturePrimitives, true, this.wboit);
 
             // do volume depth pass if extensions.depthTexture is unsupported (i.e. depthTarget is set)
             if (this.depthTargetVolumes) {
                 console.log('packed depth volumes');
-                renderer.render(this.depthTargetVolumes, scene.volumes, camera, 'depth', true, transparentBackground, 1, this.depthTexturePrimitives, false);
+                renderer.render(this.depthTargetVolumes, scene.volumes, camera, 'depth', true, transparentBackground, 1, this.depthTexturePrimitives, false, this.wboit);
             }
         }
 

+ 3 - 3
src/mol-canvas3d/passes/pick.ts

@@ -66,9 +66,9 @@ export class PickPass {
     private renderVariant(renderTarget: RenderTarget, renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, variant: GraphicsRenderVariant) {
         const pickScale = this.pickBaseScale / this.webgl.pixelRatio;
         const depth = this.drawPass.depthTexturePrimitives;
-        renderer.render(renderTarget, scene.primitives, camera, variant, true, false, pickScale, null, false);
-        renderer.render(renderTarget, scene.volumes, camera, variant, false, false, pickScale, depth, false);
-        renderer.render(renderTarget, helper.handle.scene, camera, variant, false, false, pickScale, null, false);
+        renderer.render(renderTarget, scene.primitives, camera, variant, true, false, pickScale, null, false, null);
+        renderer.render(renderTarget, scene.volumes, camera, variant, false, false, pickScale, depth, false, null);
+        renderer.render(renderTarget, helper.handle.scene, camera, variant, false, false, pickScale, null, false, null);
     }
 
     render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper) {

+ 109 - 0
src/mol-canvas3d/passes/wboit.ts

@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { QuadSchema, QuadValues } from '../../mol-gl/compute/util';
+import { ComputeRenderable, createComputeRenderable } from '../../mol-gl/renderable';
+import { TextureSpec, Values } from '../../mol-gl/renderable/schema';
+import { ShaderCode } from '../../mol-gl/shader-code';
+import { WebGLContext } from '../../mol-gl/webgl/context';
+import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
+import { Texture } from '../../mol-gl/webgl/texture';
+import { ValueCell } from '../../mol-util';
+import quad_vert from '../../mol-gl/shader/quad.vert';
+import evaluate_wboit_frag from '../../mol-gl/shader/evaluate-wboit.frag';
+import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
+
+const EvaluateWboitSchema = {
+    ...QuadSchema,
+    tWboitA: TextureSpec('texture', 'rgba', 'float', 'nearest'),
+    tWboitB: TextureSpec('texture', 'rgba', 'float', 'nearest'),
+};
+const EvaluateWboitShaderCode = ShaderCode('evaluate-wboit', quad_vert, evaluate_wboit_frag);
+type EvaluateWboitRenderable = ComputeRenderable<Values<typeof EvaluateWboitSchema>>
+
+function getEvaluateWboitRenderable(ctx: WebGLContext, wboitATexture: Texture, wboitBTexture: Texture): EvaluateWboitRenderable {
+    const values: Values<typeof EvaluateWboitSchema> = {
+        ...QuadValues,
+        tWboitA: ValueCell.create(wboitATexture),
+        tWboitB: ValueCell.create(wboitBTexture),
+    };
+
+    const schema = { ...EvaluateWboitSchema };
+    const renderItem = createComputeRenderItem(ctx, 'triangles', EvaluateWboitShaderCode, schema, values);
+
+    return createComputeRenderable(renderItem, values);
+}
+
+//
+
+export class WboitPass {
+    private readonly renderable: EvaluateWboitRenderable
+
+    private readonly framebuffer: Framebuffer
+    private readonly textureA: Texture
+    private readonly textureB: Texture
+
+    private _enabled = false;
+    get enabled() {
+        return this._enabled;
+    }
+
+    bind() {
+        const { state, gl } = this.webgl;
+
+        this.framebuffer.bind();
+
+        state.clearColor(0, 0, 0, 1);
+        gl.clear(gl.COLOR_BUFFER_BIT);
+
+        state.disable(gl.DEPTH_TEST);
+
+        state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);
+        state.enable(gl.BLEND);
+    }
+
+    render() {
+        const { state, gl } = this.webgl;
+
+        state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
+        state.enable(gl.BLEND);
+
+        this.renderable.update();
+        this.renderable.render();
+    }
+
+    setSize(width: number, height: number) {
+        this.textureA.define(width, height);
+        this.textureB.define(width, height);
+    }
+
+    constructor(private webgl: WebGLContext, width: number, height: number) {
+        const { resources, extensions } = webgl;
+        const { drawBuffers, textureFloat, colorBufferFloat, depthTexture } = extensions;
+        if (!textureFloat || !colorBufferFloat || !depthTexture || !drawBuffers) return;
+
+        this.textureA = resources.texture('image-float32', 'rgba', 'float', 'nearest');
+        this.textureA.define(width, height);
+
+        this.textureB = resources.texture('image-float32', 'rgba', 'float', 'nearest');
+        this.textureB.define(width, height);
+
+        this.renderable = getEvaluateWboitRenderable(webgl, this.textureA, this.textureB);
+
+        this.framebuffer = resources.framebuffer();
+        this.framebuffer.bind();
+        drawBuffers.drawBuffers([
+            drawBuffers.COLOR_ATTACHMENT0,
+            drawBuffers.COLOR_ATTACHMENT1,
+        ]);
+
+        this.textureA.attachFramebuffer(this.framebuffer, 'color0');
+        this.textureB.attachFramebuffer(this.framebuffer, 'color1');
+
+        this._enabled = true;
+    }
+}

+ 19 - 92
src/mol-gl/renderer.ts

@@ -9,11 +9,11 @@ import { ICamera } from '../mol-canvas3d/camera';
 import Scene from './scene';
 import { WebGLContext } from './webgl/context';
 import { Mat4, Vec3, Vec4, Vec2, Quat } from '../mol-math/linear-algebra';
-import { ComputeRenderable, createComputeRenderable, Renderable } from './renderable';
+import { Renderable } from './renderable';
 import { Color } from '../mol-util/color';
 import { ValueCell, deepEqual } from '../mol-util';
-import { RenderableValues, GlobalUniformValues, BaseValues, TextureSpec, Values } from './renderable/schema';
-import { createComputeRenderItem, GraphicsRenderVariant } from './webgl/render-item';
+import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema';
+import { GraphicsRenderVariant } from './webgl/render-item';
 import { ParamDefinition as PD } from '../mol-util/param-definition';
 import { Clipping } from '../mol-theme/clipping';
 import { stringToWords } from '../mol-util/string';
@@ -21,12 +21,8 @@ import { Transparency } from '../mol-theme/transparency';
 import { degToRad } from '../mol-math/misc';
 import { createNullTexture, Texture, Textures } from './webgl/texture';
 import { RenderTarget } from './webgl/render-target';
-import { QuadSchema, QuadValues } from './compute/util';
-
-import quad_vert from '../mol-gl/shader/quad.vert';
-import evaluate_wboit_frag from '../mol-gl/shader/evaluate-wboit.frag';
-import { ShaderCode } from './shader-code';
 import { arrayMapUpsert } from '../mol-util/array';
+import { WboitPass } from '../mol-canvas3d/passes/wboit';
 
 export interface RendererStats {
     programCount: number
@@ -49,7 +45,7 @@ interface Renderer {
     readonly props: Readonly<RendererProps>
 
     clear: (transparentBackground: boolean) => void
-    render: (renderTarget: RenderTarget | null, group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, drawingBufferScale: number, depthTexture: Texture | null, renderTransparent: boolean) => void
+    render: (renderTarget: RenderTarget | null, group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, drawingBufferScale: number, depthTexture: Texture | null, renderTransparent: boolean, wboit: WboitPass | null) => void
     setProps: (props: Partial<RendererProps>) => void
     setViewport: (x: number, y: number, width: number, height: number) => void
     dispose: () => void
@@ -165,13 +161,11 @@ function getClip(props: RendererProps['clip'], clip?: Clip): Clip {
 
 namespace Renderer {
     export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
-        const { gl, state, resources, stats } = ctx;
+        const { gl, state, stats, extensions: { fragDepth } } = ctx;
         const p = PD.merge(RendererParams, PD.getDefaultValues(RendererParams), props);
         const style = getStyle(p.style);
         const clip = getClip(p.clip);
 
-        const { drawBuffers, textureFloat, colorBufferFloat, depthTexture, fragDepth } = ctx.extensions;
-
         const viewport = Viewport();
         const drawingBufferSize = Vec2.create(gl.drawingBufferWidth, gl.drawingBufferHeight);
         const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor);
@@ -181,27 +175,6 @@ namespace Renderer {
             ['tDepth', nullDepthTexture]
         ];
 
-        const enableWboit = textureFloat && colorBufferFloat && depthTexture && drawBuffers;
-
-        const wboitATexture = enableWboit ? resources.texture('image-float32', 'rgba', 'float', 'nearest') : null;
-        wboitATexture?.define(viewport.width, viewport.height);
-        const wboitBTexture = enableWboit ? resources.texture('image-float32', 'rgba', 'float', 'nearest') : null;
-        wboitBTexture?.define(viewport.width, viewport.height);
-
-        const evaluateWboitRenderable = enableWboit ? getEvaluateWboitRenderable(ctx, wboitATexture!, wboitBTexture!) : null;
-
-        const wboitFramebuffer = resources.framebuffer();
-        if (enableWboit) {
-            wboitFramebuffer.bind();
-            drawBuffers!.drawBuffers([
-                drawBuffers!.COLOR_ATTACHMENT0,
-                drawBuffers!.COLOR_ATTACHMENT1,
-            ]);
-
-            wboitATexture!.attachFramebuffer(wboitFramebuffer, 'color0');
-            wboitBTexture!.attachFramebuffer(wboitFramebuffer, 'color1');
-        }
-
         const view = Mat4();
         const invView = Mat4();
         const modelView = Mat4();
@@ -270,7 +243,7 @@ namespace Renderer {
 
         let globalUniformsNeedUpdate = true;
 
-        const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: GraphicsRenderVariant) => {
+        const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: GraphicsRenderVariant, wboit: WboitPass | null) => {
             if (!r.state.visible || (!r.state.pickable && variant[0] === 'p')) {
                 return;
             }
@@ -308,7 +281,7 @@ namespace Renderer {
                 state.disable(gl.CULL_FACE);
                 state.frontFace(gl.CCW);
 
-                if (!enableWboit) {
+                if (!wboit?.enabled) {
                     // depth test done manually in shader against `depthTexture`
                     // still need to enable when fragDepth can be used to write depth
                     if (r.values.dRenderMode.ref.value === 'volume' || !fragDepth) {
@@ -345,13 +318,13 @@ namespace Renderer {
                     state.cullFace(gl.BACK);
                 }
 
-                if (!enableWboit) state.depthMask(r.state.writeDepth);
+                if (!wboit?.enabled) state.depthMask(r.state.writeDepth);
             }
 
             r.render(variant, sharedTexturesList);
         };
 
-        const render = (renderTarget: RenderTarget | null, group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, drawingBufferScale: number, depthTexture: Texture | null, renderTransparent: boolean) => {
+        const render = (renderTarget: RenderTarget | null, group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, clear: boolean, transparentBackground: boolean, drawingBufferScale: number, depthTexture: Texture | null, renderTransparent: boolean, wboit: WboitPass | null) => {
             arrayMapUpsert(sharedTexturesList, 'tDepth', depthTexture || nullDepthTexture);
 
             ValueCell.update(globalUniforms.uModel, group.view);
@@ -418,7 +391,7 @@ namespace Renderer {
             }
 
             if (variant === 'color') {
-                if (enableWboit) {
+                if (wboit?.enabled) {
                     if (!renderTransparent) {
                         state.enable(gl.DEPTH_TEST);
                         state.depthMask(true);
@@ -426,27 +399,19 @@ namespace Renderer {
                         for (let i = 0, il = renderables.length; i < il; ++i) {
                             const r = renderables[i];
                             if (r.values.uAlpha.ref.value === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values?.dRenderMode?.ref.value !== 'volume') {
-                                renderObject(r, variant);
+                                renderObject(r, variant, wboit);
                             }
                         }
                     } else {
-                        wboitFramebuffer.bind();
-
-                        state.clearColor(0, 0, 0, 1);
-                        gl.clear(gl.COLOR_BUFFER_BIT);
+                        wboit.bind();
 
                         ValueCell.updateIfChanged(globalUniforms.uRenderWboit, 1);
                         globalUniformsNeedUpdate = true;
 
-                        state.disable(gl.DEPTH_TEST);
-
-                        state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);
-                        state.enable(gl.BLEND);
-
                         for (let i = 0, il = renderables.length; i < il; ++i) {
                             const r = renderables[i];
                             if (r.values.uAlpha.ref.value < 1 || r.values.transparencyAverage.ref.value !== 0) {
-                                renderObject(r, variant);
+                                renderObject(r, variant, wboit);
                             }
                         }
 
@@ -456,22 +421,13 @@ namespace Renderer {
                             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
                         }
 
-                        state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
-                        state.enable(gl.BLEND);
-
-                        // unclear why needed but otherwise there is a
-                        // "Draw framebuffer is incomplete" error for the very first render call
-                        // before there are any renderables...
-                        if (renderables.length > 0) {
-                            evaluateWboitRenderable!.update();
-                            evaluateWboitRenderable!.render();
-                        }
+                        wboit.render();
                     }
                 } else {
                     for (let i = 0, il = renderables.length; i < il; ++i) {
                         const r = renderables[i];
                         if (r.state.opaque) {
-                            renderObject(r, variant);
+                            renderObject(r, variant, wboit);
                         }
                     }
 
@@ -480,13 +436,13 @@ namespace Renderer {
                     for (let i = 0, il = renderables.length; i < il; ++i) {
                         const r = renderables[i];
                         if (!r.state.opaque && r.state.writeDepth) {
-                            renderObject(r, variant);
+                            renderObject(r, variant, wboit);
                         }
                     }
                     for (let i = 0, il = renderables.length; i < il; ++i) {
                         const r = renderables[i];
                         if (!r.state.opaque && !r.state.writeDepth) {
-                            renderObject(r, variant);
+                            renderObject(r, variant, wboit);
                         }
                     }
                 }
@@ -494,7 +450,7 @@ namespace Renderer {
                 if (!renderTransparent) {
                     for (let i = 0, il = renderables.length; i < il; ++i) {
                         if (!renderables[i].state.colorOnly) {
-                            renderObject(renderables[i], variant);
+                            renderObject(renderables[i], variant, wboit);
                         }
                     }
                 }
@@ -577,13 +533,6 @@ namespace Renderer {
                     Viewport.set(viewport, x, y, width, height);
                     ValueCell.update(globalUniforms.uViewportHeight, height);
                     ValueCell.update(globalUniforms.uViewport, Vec4.set(globalUniforms.uViewport.ref.value, x, y, width, height));
-
-                    // TODO: this gets called every frame... in any case, we will need to move
-                    //       the wboit resources (framebuffer, textures, renderable) eventually
-                    //       to the draw pass to be more efficient when having >100 viewports
-                    //       rendered to a single canvas every frame.
-                    wboitATexture?.define(viewport.width, viewport.height);
-                    wboitBTexture?.define(viewport.width, viewport.height);
                 }
             },
 
@@ -614,26 +563,4 @@ namespace Renderer {
     }
 }
 
-const EvaluateWboitSchema = {
-    ...QuadSchema,
-    tWboitA: TextureSpec('texture', 'rgba', 'float', 'nearest'),
-    tWboitB: TextureSpec('texture', 'rgba', 'float', 'nearest'),
-};
-
-type EvaluateWboitRenderable = ComputeRenderable<Values<typeof EvaluateWboitSchema>>
-
-function getEvaluateWboitRenderable(ctx: WebGLContext, wboitATexture: Texture, wboitBTexture: Texture): EvaluateWboitRenderable {
-    const values: Values<typeof EvaluateWboitSchema> = {
-        ...QuadValues,
-        tWboitA: ValueCell.create(wboitATexture),
-        tWboitB: ValueCell.create(wboitBTexture),
-    };
-
-    const schema = { ...EvaluateWboitSchema };
-    const shaderCode = ShaderCode('wboit', quad_vert, evaluate_wboit_frag);
-    const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values);
-
-    return createComputeRenderable(renderItem, values);
-}
-
 export default Renderer;

+ 1 - 1
src/mol-gl/shader/chunks/wboit-params.glsl.ts

@@ -2,6 +2,7 @@ export default `
 #if defined(dRenderVariant_color)
     #if !defined(dRenderMode_volume) && !defined(dRenderMode_isosurface)
         uniform sampler2D tDepth;
+        uniform vec2 uDrawingBufferSize;
 
         float getDepth(const in vec2 coords) {
             #ifdef dPackedDepth
@@ -12,7 +13,6 @@ export default `
         }
     #endif
     uniform int uRenderWboit;
-    uniform vec4 uViewport;
 #endif
 
 float calcDepth(const in vec3 pos) {

+ 1 - 2
src/mol-gl/shader/chunks/wboit-write.glsl.ts

@@ -4,8 +4,7 @@ if (uRenderWboit == 0) {
         discard;
     }
 } else if (uRenderWboit == 1) {
-    // TODO: volumes not rendering has something to do with the depth test
-    if (gl_FragColor.a != 1.0 && absFragDepth < getDepth(gl_FragCoord.xy / uViewport.zw)) {
+    if (gl_FragColor.a != 1.0 && absFragDepth < getDepth(gl_FragCoord.xy / uDrawingBufferSize)) {
         float alpha = gl_FragColor.a;
         float wboitWeight = alpha * clamp(pow(1.0 - absFragDepth, 2.0), 0.01, 1.0);
         gl_FragColor = vec4(gl_FragColor.rgb * alpha * wboitWeight, alpha);