From 3baa03ccdc0bb66196ddb3b2126eeee94868b759 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Sun, 22 Jan 2023 14:21:37 -0800 Subject: [PATCH] adjust outlines based on view distance --- CHANGELOG.md | 1 + src/mol-canvas3d/passes/postprocessing.ts | 8 ++++++-- src/mol-gl/shader/postprocessing.frag.ts | 13 +++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb1eed9a9..1a296add5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Note that since we don't clearly distinguish between a public and private interf - Improve boundary calculation performance - Add option to create & include images in state snapshots - Fix SSAO artefacts with high bias values +- Improve outlines, visually more stable at different view distances ## [v3.29.0] - 2023-01-15 diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts index 1a1401642..1955b7378 100644 --- a/src/mol-canvas3d/passes/postprocessing.ts +++ b/src/mol-canvas3d/passes/postprocessing.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Ăron Samuel Kovács <aron.kovacs@mail.muni.cz> @@ -283,6 +283,7 @@ const PostprocessingSchema = { uTransparentBackground: UniformSpec('b'), uMaxPossibleViewZDiff: UniformSpec('f'), + uInvProjection: UniformSpec('m4'), dOcclusionEnable: DefineSpec('boolean'), uOcclusionOffset: UniformSpec('v2'), @@ -319,6 +320,7 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d uTransparentBackground: ValueCell.create(false), uMaxPossibleViewZDiff: ValueCell.create(0.5), + uInvProjection: ValueCell.create(Mat4.identity()), dOcclusionEnable: ValueCell.create(true), uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)), @@ -630,7 +632,7 @@ export class PostprocessingPass { const transparentOutline = includeTransparent ?? true; // orthographic needs lower threshold if (camera.state.mode === 'orthographic') threshold /= 5; - const factor = Math.pow(1000, threshold) / 1000; + const factor = Math.pow(1000, threshold / 10) / 1000; // use radiusMax for stable outlines when zooming const maxPossibleViewZDiff = factor * camera.state.radiusMax; const outlineScale = props.outline.params.scale - 1; @@ -644,6 +646,8 @@ export class PostprocessingPass { ValueCell.update(this.renderable.values.uOutlineColor, Color.toVec3Normalized(this.renderable.values.uOutlineColor.ref.value, props.outline.params.color)); ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff); + ValueCell.update(this.renderable.values.uInvProjection, invProjection); + if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale); if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { needsUpdateMain = true; } diff --git a/src/mol-gl/shader/postprocessing.frag.ts b/src/mol-gl/shader/postprocessing.frag.ts index 80e971222..d22deb145 100644 --- a/src/mol-gl/shader/postprocessing.frag.ts +++ b/src/mol-gl/shader/postprocessing.frag.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Ăron Samuel Kovács <aron.kovacs@mail.muni.cz> @@ -29,7 +29,9 @@ uniform bool uTransparentBackground; uniform vec2 uOcclusionOffset; uniform float uMaxPossibleViewZDiff; +uniform mat4 uInvProjection; +const float outlineDistanceFactor = 5.0; const vec3 occlusionColor = vec3(0.0); #include common @@ -62,12 +64,19 @@ bool isBackground(const in float depth) { return depth == 1.0; } +float getPixelSize(const in vec2 coords, const in float depth) { + vec3 viewPos0 = screenSpaceToViewSpace(vec3(coords, depth), uInvProjection); + vec3 viewPos1 = screenSpaceToViewSpace(vec3(coords + vec2(1.0, 0.0) / uTexSize, depth), uInvProjection); + return distance(viewPos0, viewPos1); +} + float getOutline(const in vec2 coords, const in float opaqueDepth, out float closestTexel) { float backgroundViewZ = uFar + 3.0 * uMaxPossibleViewZDiff; vec2 invTexSize = 1.0 / uTexSize; float selfDepth = min(opaqueDepth, getDepthTransparent(coords)); float selfViewZ = isBackground(selfDepth) ? backgroundViewZ : getViewZ(selfDepth); + float pixelSize = getPixelSize(coords, selfDepth); float outline = 1.0; closestTexel = 1.0; @@ -84,7 +93,7 @@ float getOutline(const in vec2 coords, const in float opaqueDepth, out float clo float sampleOutlineDepth = unpackRGToUnitInterval(sampleOutlineCombined.gb); float sampleOutlineViewZ = isBackground(sampleOutlineDepth) ? backgroundViewZ : getViewZ(sampleOutlineDepth); - if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineViewZ) > uMaxPossibleViewZDiff) { + if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineViewZ) > uMaxPossibleViewZDiff + (pixelSize * outlineDistanceFactor)) { outline = 0.0; closestTexel = sampleOutlineDepth; } -- GitLab