diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d8c5963038ba92b58e284561f7e466e4c491372..949d705362d4bcb4128d6783a2aaa7467ab75edd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Add occlusion color parameter +- Fix issue with outlines and orthographic camera +- Reduce over-blurring occlusion at larger view distances + ## [v3.31.4] - 2023-02-24 - Allow link cylinder/line `dashCount` set to '0' diff --git a/src/apps/docking-viewer/viewport.tsx b/src/apps/docking-viewer/viewport.tsx index d1c4ff85ab2c940349d9a7dcbec2fa3a8f0d113c..fe92d0f9623a4583c52d17f832faa02575cec632 100644 --- a/src/apps/docking-viewer/viewport.tsx +++ b/src/apps/docking-viewer/viewport.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -50,6 +50,7 @@ function occlusionStyle(plugin: PluginContext) { radius: 5, samples: 32, resolutionScale: 1, + color: Color(0x000000), } }, outline: { name: 'on', params: { scale: 1.0, diff --git a/src/examples/lighting/index.ts b/src/examples/lighting/index.ts index 0cc1048ef7843c78080a383bd8927ea3ba88a2a4..ceab47858abd78c4b5e964b4dcbd64a8563989a3 100644 --- a/src/examples/lighting/index.ts +++ b/src/examples/lighting/index.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> */ @@ -24,7 +24,7 @@ const Canvas3DPresets = { illustrative: { canvas3d: <Preset>{ postprocessing: { - occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } }, + occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1, color: Color(0x000000) } }, outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } }, shadow: { name: 'off', params: {} }, }, diff --git a/src/extensions/cellpack/model.ts b/src/extensions/cellpack/model.ts index cf932b8dd2fe6b7e96d521b6faea044494e1b630..e58388495eeab24a682abeb7712f09817c7a3f12 100644 --- a/src/extensions/cellpack/model.ts +++ b/src/extensions/cellpack/model.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 Ludovic Autin <ludovic.autin@gmail.com> @@ -604,6 +604,7 @@ export const LoadCellPackModel = StateAction.build({ bias: 1, blurKernelSize: 15, resolutionScale: 1, + color: Color(0x000000), } }, shadow: { diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts index 7ee7402d02452786c97b9413a975003f1e4cf8f3..e1c9ce4f85af804226c8f8336c6358169460e8f8 100644 --- a/src/mol-canvas3d/passes/postprocessing.ts +++ b/src/mol-canvas3d/passes/postprocessing.ts @@ -43,9 +43,9 @@ const OutlinesSchema = { dOrthographic: DefineSpec('number'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), + uInvProjection: UniformSpec('m4'), - uMaxPossibleViewZDiff: UniformSpec('f'), - + uOutlineThreshold: UniformSpec('f'), dTransparentOutline: DefineSpec('boolean'), }; type OutlinesRenderable = ComputeRenderable<Values<typeof OutlinesSchema>> @@ -63,9 +63,9 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d dOrthographic: ValueCell.create(0), uNear: ValueCell.create(1), uFar: ValueCell.create(10000), + uInvProjection: ValueCell.create(Mat4.identity()), - uMaxPossibleViewZDiff: ValueCell.create(0.5), - + uOutlineThreshold: ValueCell.create(0.33), dTransparentOutline: ValueCell.create(transparentOutline), }; @@ -189,8 +189,7 @@ const SsaoBlurSchema = { uBlurDirectionX: UniformSpec('f'), uBlurDirectionY: UniformSpec('f'), - uMaxPossibleViewZDiff: UniformSpec('f'), - + uInvProjection: UniformSpec('m4'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), uBounds: UniformSpec('v4'), @@ -211,8 +210,7 @@ function getSsaoBlurRenderable(ctx: WebGLContext, ssaoDepthTexture: Texture, dir uBlurDirectionX: ValueCell.create(direction === 'horizontal' ? 1 : 0), uBlurDirectionY: ValueCell.create(direction === 'vertical' ? 1 : 0), - uMaxPossibleViewZDiff: ValueCell.create(0.5), - + uInvProjection: ValueCell.create(Mat4.identity()), uNear: ValueCell.create(0.0), uFar: ValueCell.create(10000.0), uBounds: ValueCell.create(Vec4()), @@ -280,11 +278,9 @@ const PostprocessingSchema = { uFogFar: UniformSpec('f'), uFogColor: UniformSpec('v3'), uOutlineColor: UniformSpec('v3'), + uOcclusionColor: UniformSpec('v3'), uTransparentBackground: UniformSpec('b'), - uMaxPossibleViewZDiff: UniformSpec('f'), - uInvProjection: UniformSpec('m4'), - dOcclusionEnable: DefineSpec('boolean'), uOcclusionOffset: UniformSpec('v2'), @@ -292,8 +288,6 @@ const PostprocessingSchema = { dOutlineEnable: DefineSpec('boolean'), dOutlineScale: DefineSpec('number'), - uOutlineThreshold: UniformSpec('f'), - dTransparentOutline: DefineSpec('boolean'), }; type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>> @@ -317,11 +311,9 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d uFogFar: ValueCell.create(10000), uFogColor: ValueCell.create(Vec3.create(1, 1, 1)), uOutlineColor: ValueCell.create(Vec3.create(0, 0, 0)), + uOcclusionColor: ValueCell.create(Vec3.create(0, 0, 0)), 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)), @@ -329,8 +321,6 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d dOutlineEnable: ValueCell.create(false), dOutlineScale: ValueCell.create(1), - uOutlineThreshold: ValueCell.create(0.33), - dTransparentOutline: ValueCell.create(transparentOutline), }; @@ -349,6 +339,7 @@ export const PostprocessingParams = { bias: PD.Numeric(0.8, { min: 0, max: 3, step: 0.1 }), blurKernelSize: PD.Numeric(15, { min: 1, max: 25, step: 2 }), resolutionScale: PD.Numeric(1, { min: 0.1, max: 1, step: 0.05 }, { description: 'Adjust resolution of occlusion calculation' }), + color: PD.Color(Color(0x000000)), }), off: PD.Group({}) }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), @@ -543,11 +534,14 @@ export class PostprocessingPass { ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.uFar, camera.far); ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.uFar, camera.far); + ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uInvProjection, invProjection); + ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uInvProjection, invProjection); + if (this.ssaoBlurFirstPassRenderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateSsaoBlur = true; + ValueCell.update(this.ssaoBlurFirstPassRenderable.values.dOrthographic, orthographic); + ValueCell.update(this.ssaoBlurSecondPassRenderable.values.dOrthographic, orthographic); } - ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.dOrthographic, orthographic); - ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOrthographic, orthographic); if (this.nSamples !== props.occlusion.params.samples) { needsUpdateSsao = true; @@ -567,8 +561,8 @@ export class PostprocessingPass { ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uKernel, kernel); ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uKernel, kernel); - ValueCell.updateIfChanged(this.ssaoBlurFirstPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize); - ValueCell.updateIfChanged(this.ssaoBlurSecondPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize); + ValueCell.update(this.ssaoBlurFirstPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize); + ValueCell.update(this.ssaoBlurSecondPassRenderable.values.dOcclusionKernelSize, this.blurKernelSize); } if (this.downsampleFactor !== props.occlusion.params.resolutionScale) { @@ -595,6 +589,8 @@ export class PostprocessingPass { ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurSecondPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurSecondPassRenderable.values.uTexSize.ref.value, sw, sh)); } + + ValueCell.update(this.renderable.values.uOcclusionColor, Color.toVec3Normalized(this.renderable.values.uOcclusionColor.ref.value, props.occlusion.params.color)); } if (props.shadow.name === 'on') { @@ -611,7 +607,10 @@ export class PostprocessingPass { ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far); - ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic); + if (this.shadowsRenderable.values.dOrthographic.ref.value !== orthographic) { + ValueCell.update(this.shadowsRenderable.values.dOrthographic, orthographic); + needsUpdateShadows = true; + } ValueCell.updateIfChanged(this.shadowsRenderable.values.uMaxDistance, props.shadow.params.maxDistance); ValueCell.updateIfChanged(this.shadowsRenderable.values.uTolerance, props.shadow.params.tolerance); @@ -630,30 +629,33 @@ export class PostprocessingPass { } if (props.outline.name === 'on') { - let { threshold, includeTransparent } = props.outline.params; - const transparentOutline = includeTransparent ?? true; - // orthographic needs lower threshold - if (camera.state.mode === 'orthographic') threshold /= 5; - const factor = Math.pow(1000, threshold / 10) / 1000; - // use radiusMax for stable outlines when zooming - const maxPossibleViewZDiff = factor * camera.state.radiusMax; + const transparentOutline = props.outline.params.includeTransparent ?? true; const outlineScale = props.outline.params.scale - 1; + const outlineThreshold = 50 * props.outline.params.threshold; ValueCell.updateIfChanged(this.outlinesRenderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far); - ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff); - if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { needsUpdateOutlines = true; } - ValueCell.updateIfChanged(this.outlinesRenderable.values.dTransparentOutline, transparentOutline); + ValueCell.update(this.outlinesRenderable.values.uInvProjection, invProjection); + if (this.outlinesRenderable.values.dTransparentOutline.ref.value !== transparentOutline) { + needsUpdateOutlines = true; + ValueCell.update(this.outlinesRenderable.values.dTransparentOutline, transparentOutline); + } + if (this.outlinesRenderable.values.dOrthographic.ref.value !== orthographic) { + needsUpdateOutlines = true; + ValueCell.update(this.outlinesRenderable.values.dOrthographic, orthographic); + } + ValueCell.updateIfChanged(this.outlinesRenderable.values.uOutlineThreshold, outlineThreshold); 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; } - ValueCell.updateIfChanged(this.renderable.values.dTransparentOutline, transparentOutline); + if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { + needsUpdateMain = true; + ValueCell.update(this.renderable.values.dOutlineScale, outlineScale); + } + if (this.renderable.values.dTransparentOutline.ref.value !== transparentOutline) { + needsUpdateMain = true; + ValueCell.update(this.renderable.values.dTransparentOutline, transparentOutline); + } } ValueCell.updateIfChanged(this.renderable.values.uFar, camera.far); @@ -662,15 +664,23 @@ export class PostprocessingPass { 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; } - ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled); - if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { needsUpdateMain = true; } - ValueCell.updateIfChanged(this.renderable.values.dShadowEnable, shadowsEnabled); - if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; } - ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled); + if (this.renderable.values.dOrthographic.ref.value !== orthographic) { + needsUpdateMain = true; + ValueCell.update(this.renderable.values.dOrthographic, orthographic); + } + + if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { + needsUpdateMain = true; + ValueCell.update(this.renderable.values.dOutlineEnable, outlinesEnabled); + } + if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { + needsUpdateMain = true; + ValueCell.update(this.renderable.values.dShadowEnable, shadowsEnabled); + } + if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { + needsUpdateMain = true; + ValueCell.update(this.renderable.values.dOcclusionEnable, occlusionEnabled); + } if (needsUpdateOutlines) { this.outlinesRenderable.update(); diff --git a/src/mol-gl/shader/outlines.frag.ts b/src/mol-gl/shader/outlines.frag.ts index 443843945e03497943f3712e4bda90540ee3726e..55134888c0f59b15f38354ea1f2baca390c42ef4 100644 --- a/src/mol-gl/shader/outlines.frag.ts +++ b/src/mol-gl/shader/outlines.frag.ts @@ -16,8 +16,9 @@ uniform vec2 uTexSize; uniform float uNear; uniform float uFar; +uniform mat4 uInvProjection; -uniform float uMaxPossibleViewZDiff; +uniform float uOutlineThreshold; #include common @@ -49,17 +50,25 @@ 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); +} + void main(void) { - float backgroundViewZ = uFar + 3.0 * uMaxPossibleViewZDiff; + float backgroundViewZ = 2.0 * uFar; vec2 coords = gl_FragCoord.xy / uTexSize; vec2 invTexSize = 1.0 / uTexSize; float selfDepthOpaque = getDepthOpaque(coords); float selfViewZOpaque = isBackground(selfDepthOpaque) ? backgroundViewZ : getViewZ(selfDepthOpaque); + float pixelSizeOpaque = getPixelSize(coords, selfDepthOpaque) * uOutlineThreshold; float selfDepthTransparent = getDepthTransparent(coords); float selfViewZTransparent = isBackground(selfDepthTransparent) ? backgroundViewZ : getViewZ(selfDepthTransparent); + float pixelSizeTransparent = getPixelSize(coords, selfDepthTransparent) * uOutlineThreshold; float outline = 1.0; float bestDepth = 1.0; @@ -73,14 +82,14 @@ void main(void) { float sampleDepthTransparent = getDepthTransparent(sampleCoords); float sampleViewZOpaque = isBackground(sampleDepthOpaque) ? backgroundViewZ : getViewZ(sampleDepthOpaque); - if (abs(selfViewZOpaque - sampleViewZOpaque) > uMaxPossibleViewZDiff && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestDepth) { + if (abs(selfViewZOpaque - sampleViewZOpaque) > pixelSizeOpaque && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestDepth) { outline = 0.0; bestDepth = sampleDepthOpaque; } if (sampleDepthTransparent < sampleDepthOpaque) { float sampleViewZTransparent = isBackground(sampleDepthTransparent) ? backgroundViewZ : getViewZ(sampleDepthTransparent); - if (abs(selfViewZTransparent - sampleViewZTransparent) > uMaxPossibleViewZDiff && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestDepth) { + if (abs(selfViewZTransparent - sampleViewZTransparent) > pixelSizeTransparent && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestDepth) { outline = 0.0; bestDepth = sampleDepthTransparent; transparentFlag = 1.0; diff --git a/src/mol-gl/shader/postprocessing.frag.ts b/src/mol-gl/shader/postprocessing.frag.ts index 49b335fc19af3ea1d369f6a6cec173c0dd0b781d..22d4a364217e3b762df94f85a3c75e635a249a2d 100644 --- a/src/mol-gl/shader/postprocessing.frag.ts +++ b/src/mol-gl/shader/postprocessing.frag.ts @@ -24,16 +24,10 @@ uniform float uFogNear; uniform float uFogFar; uniform vec3 uFogColor; uniform vec3 uOutlineColor; +uniform vec3 uOcclusionColor; 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 float getViewZ(const in float depth) { @@ -64,21 +58,14 @@ 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; + float backgroundViewZ = 2.0 * uFar; vec2 invTexSize = 1.0 / uTexSize; float transparentDepth = getDepthTransparent(coords); float opaqueSelfViewZ = isBackground(opaqueDepth) ? backgroundViewZ : getViewZ(opaqueDepth); float transparentSelfViewZ = isBackground(transparentDepth) ? backgroundViewZ : getViewZ(transparentDepth); float selfDepth = min(opaqueDepth, transparentDepth); - float pixelSize = getPixelSize(coords, selfDepth); float outline = 1.0; closestTexel = 1.0; @@ -96,7 +83,7 @@ float getOutline(const in vec2 coords, const in float opaqueDepth, out float clo float sampleOutlineViewZ = isBackground(sampleOutlineDepth) ? backgroundViewZ : getViewZ(sampleOutlineDepth); float selfViewZ = sampleOutlineCombined.a == 0.0 ? opaqueSelfViewZ : transparentSelfViewZ; - if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel && abs(selfViewZ - sampleOutlineViewZ) > uMaxPossibleViewZDiff + (pixelSize * outlineDistanceFactor)) { + if (sampleOutline == 0.0 && sampleOutlineDepth < closestTexel) { outline = 0.0; closestTexel = sampleOutlineDepth; } @@ -130,9 +117,9 @@ void main(void) { fogFactor = smoothstep(uFogNear, uFogFar, viewDist); float occlusionFactor = getSsao(coords + uOcclusionOffset); if (!uTransparentBackground) { - color.rgb = mix(mix(occlusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor); + color.rgb = mix(mix(uOcclusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor); } else { - color.rgb = mix(occlusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor); + color.rgb = mix(uOcclusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor); } } #endif diff --git a/src/mol-gl/shader/ssao-blur.frag.ts b/src/mol-gl/shader/ssao-blur.frag.ts index efa894dc21f8d9e4f490424f1bb5afd6e9864a57..a277714602a96071817ea170a2c9136a071b838a 100644 --- a/src/mol-gl/shader/ssao-blur.frag.ts +++ b/src/mol-gl/shader/ssao-blur.frag.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 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 Ăron Samuel Kovács <aron.kovacs@mail.muni.cz> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -19,8 +19,7 @@ uniform float uKernel[dOcclusionKernelSize]; uniform float uBlurDirectionX; uniform float uBlurDirectionY; -uniform float uMaxPossibleViewZDiff; - +uniform mat4 uInvProjection; uniform float uNear; uniform float uFar; @@ -42,6 +41,12 @@ bool outsideBounds(const in vec2 p) { return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w; } +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); +} + void main(void) { vec2 coords = gl_FragCoord.xy / uTexSize; @@ -60,6 +65,8 @@ void main(void) { } float selfViewZ = getViewZ(selfDepth); + float pixelSize = getPixelSize(coords, selfDepth); + float maxDiffViewZ = pixelSize * 5.0; vec2 offset = vec2(uBlurDirectionX, uBlurDirectionY) / uTexSize; @@ -67,6 +74,8 @@ void main(void) { float kernelSum = 0.0; // only if kernelSize is odd for (int i = -dOcclusionKernelSize / 2; i <= dOcclusionKernelSize / 2; i++) { + if (abs(float(i)) > 1.0 && abs(float(i)) * pixelSize > 0.5) continue; + vec2 sampleCoords = coords + float(i) * offset; if (outsideBounds(sampleCoords)) { continue; @@ -79,9 +88,9 @@ void main(void) { continue; } - if (abs(float(i)) > 1.0) { // abs is not defined for int in webgl1 + if (abs(float(i)) > 1.0) { float sampleViewZ = getViewZ(sampleDepth); - if (abs(selfViewZ - sampleViewZ) > uMaxPossibleViewZDiff) { + if (abs(selfViewZ - sampleViewZ) > maxDiffViewZ) { continue; } } diff --git a/src/mol-plugin-ui/structure/quick-styles.tsx b/src/mol-plugin-ui/structure/quick-styles.tsx index 27bda32a3ba4376210c13b00bc3345ef35bca922..2e93764dac2e1842724041a718f819f204ac4d34 100644 --- a/src/mol-plugin-ui/structure/quick-styles.tsx +++ b/src/mol-plugin-ui/structure/quick-styles.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2022-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -60,7 +60,7 @@ export class QuickStyles extends PurePluginUIComponent { }, occlusion: { name: 'on', - params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 } + params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1, color: Color(0x000000) } }, shadow: { name: 'off', params: {} }, } @@ -85,7 +85,7 @@ export class QuickStyles extends PurePluginUIComponent { name: 'on', params: pp.occlusion.name === 'on' ? pp.occlusion.params - : { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 } + : { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1, color: Color(0x000000) } }, shadow: { name: 'off', params: {} }, } diff --git a/src/mol-plugin/util/headless-screenshot.ts b/src/mol-plugin/util/headless-screenshot.ts index aa98ebad00b15bca25257f21eff45fb453842e05..26948caa0c5df5f09664a914cc3783fa14d69af5 100644 --- a/src/mol-plugin/util/headless-screenshot.ts +++ b/src/mol-plugin/util/headless-screenshot.ts @@ -210,6 +210,7 @@ export const STYLIZED_POSTPROCESSING: Partial<PostprocessingProps> = { bias: 0.8, blurKernelSize: 15, resolutionScale: 1, + color: ColorNames.black, } }, outline: { name: 'on' as const, params: {