From a50e81551fc32d383b43e452d1fd704a99799893 Mon Sep 17 00:00:00 2001
From: Alexander Rose <alexander.rose@weirdbyte.de>
Date: Mon, 6 Mar 2023 22:48:31 -0800
Subject: [PATCH] use ssao-scale for gl viewport/scissor

---
 CHANGELOG.md                              |  1 +
 src/mol-canvas3d/passes/postprocessing.ts | 38 ++++++++++++++---------
 2 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 949d70536..0d82f6aa8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add occlusion color parameter
 - Fix issue with outlines and orthographic camera
 - Reduce over-blurring occlusion at larger view distances
+- Fix occlusion artefact with non-canvas viewport and pixel-ratio > 1
 
 ## [v3.31.4] - 2023-02-24
 
diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts
index e1c9ce4f8..efc98c0f4 100644
--- a/src/mol-canvas3d/passes/postprocessing.ts
+++ b/src/mol-canvas3d/passes/postprocessing.ts
@@ -709,10 +709,6 @@ export class PostprocessingPass {
         state.disable(gl.BLEND);
         state.disable(gl.DEPTH_TEST);
         state.depthMask(false);
-
-        const { x, y, width, height } = camera.viewport;
-        state.viewport(x, y, width, height);
-        state.scissor(x, y, width, height);
     }
 
     private occlusionOffset: [x: number, y: number] = [0, 0];
@@ -731,20 +727,21 @@ export class PostprocessingPass {
         if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render');
         this.updateState(camera, transparentBackground, backgroundColor, props, light);
 
-        if (props.outline.name === 'on') {
-            this.outlinesTarget.bind();
-            this.outlinesRenderable.render();
-        }
-
-        if (props.shadow.name === 'on') {
-            this.shadowsTarget.bind();
-            this.shadowsRenderable.render();
-        }
+        const { gl, state } = this.webgl;
+        const { x, y, width, height } = camera.viewport;
 
         // don't render occlusion if offset is given,
         // which will reuse the existing occlusion
         if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) {
             if (isTimingMode) this.webgl.timer.mark('SSAO.render');
+            const sx = Math.floor(x * this.ssaoScale);
+            const sy = Math.floor(y * this.ssaoScale);
+            const sw = Math.ceil(width * this.ssaoScale);
+            const sh = Math.ceil(height * this.ssaoScale);
+
+            state.viewport(sx, sy, sw, sh);
+            state.scissor(sx, sy, sw, sh);
+
             if (this.ssaoScale < 1) {
                 this.downsampledDepthTarget.bind();
                 this.downsampleDepthRenderable.render();
@@ -761,14 +758,25 @@ export class PostprocessingPass {
             if (isTimingMode) this.webgl.timer.markEnd('SSAO.render');
         }
 
+        state.viewport(x, y, width, height);
+        state.scissor(x, y, width, height);
+
+        if (props.outline.name === 'on') {
+            this.outlinesTarget.bind();
+            this.outlinesRenderable.render();
+        }
+
+        if (props.shadow.name === 'on') {
+            this.shadowsTarget.bind();
+            this.shadowsRenderable.render();
+        }
+
         if (toDrawingBuffer) {
             this.webgl.unbindFramebuffer();
         } else {
             this.target.bind();
         }
 
-        const { gl, state } = this.webgl;
-
         this.background.update(camera, props.background);
         if (this.background.isEnabled(props.background)) {
             if (this.transparentBackground) {
-- 
GitLab