ソースを参照

Add option to toogle transparent outline

Alice Russell 2 年 前
コミット
0c54b0dd6e

+ 1 - 1
CHANGELOG.md

@@ -5,7 +5,7 @@ Note that since we don't clearly distinguish between a public and private interf
 
 
 ## [Unreleased]
-- Add option `minimumOpacity` parameter to outlines to hide any outlines of components with a lower alpha value lower
+- Add an `includeTransparent` parameter to hide/show outlines of components that are transparent
 
 ## [v3.25.1] - 2022-11-20
 

+ 1 - 0
src/apps/docking-viewer/viewport.tsx

@@ -54,6 +54,7 @@ function occlusionStyle(plugin: PluginContext) {
                 scale: 1.0,
                 threshold: 0.33,
                 color: Color(0x0000),
+                includeTransparent: true,
             } }
         }
     } });

+ 2 - 2
src/examples/lighting/index.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -25,7 +25,7 @@ const Canvas3DPresets = {
         canvas3d: <Preset>{
             postprocessing: {
                 occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
-                outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } }
+                outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } }
             },
             renderer: {
                 ambientIntensity: 1.0,

+ 1 - 0
src/extensions/cellpack/model.ts

@@ -612,6 +612,7 @@ export const LoadCellPackModel = StateAction.build({
                         scale: 1,
                         threshold: 0.33,
                         color: ColorNames.black,
+                        includeTransparent: true,
                     }
                 }
             }

+ 0 - 3
src/mol-canvas3d/passes/draw.ts

@@ -145,7 +145,6 @@ export class DrawPass {
             if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
                 this.depthTargetTransparent.bind();
                 renderer.clearDepth(true);
-                renderer.setOutlineAlphaThreshold(PostprocessingPass.getOutlineMinimumOpacity(postprocessingProps));
                 if (scene.opacityAverage < 1) {
                     renderer.renderDepthTransparent(scene.primitives, camera, this.depthTextureOpaque);
                 }
@@ -200,7 +199,6 @@ export class DrawPass {
             if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
                 this.depthTargetTransparent.bind();
                 renderer.clearDepth(true);
-                renderer.setOutlineAlphaThreshold(PostprocessingPass.getOutlineMinimumOpacity(postprocessingProps));
                 if (scene.opacityAverage < 1) {
                     renderer.renderDepthTransparent(scene.primitives, camera, this.depthTextureOpaque);
                 }
@@ -265,7 +263,6 @@ export class DrawPass {
                 if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
                     this.depthTargetTransparent.bind();
                     renderer.clearDepth(true);
-                    renderer.setOutlineAlphaThreshold(PostprocessingPass.getOutlineMinimumOpacity(postprocessingProps));
                     if (scene.opacityAverage < 1) {
                         renderer.renderDepthTransparent(scene.primitives, camera, this.depthTextureOpaque);
                     }

+ 24 - 11
src/mol-canvas3d/passes/postprocessing.ts

@@ -42,10 +42,12 @@ const OutlinesSchema = {
     uFar: UniformSpec('f'),
 
     uMaxPossibleViewZDiff: UniformSpec('f'),
+
+    dTransparentOutline: DefineSpec('boolean'),
 };
 type OutlinesRenderable = ComputeRenderable<Values<typeof OutlinesSchema>>
 
-function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, depthTextureTransparent: Texture): OutlinesRenderable {
+function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, depthTextureTransparent: Texture, transparentOutline: boolean): OutlinesRenderable {
     const width = depthTextureOpaque.getWidth();
     const height = depthTextureOpaque.getHeight();
 
@@ -60,6 +62,8 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d
         uFar: ValueCell.create(10000),
 
         uMaxPossibleViewZDiff: ValueCell.create(0.5),
+
+        dTransparentOutline: ValueCell.create(transparentOutline),
     };
 
     const schema = { ...OutlinesSchema };
@@ -224,10 +228,12 @@ const PostprocessingSchema = {
     dOutlineEnable: DefineSpec('boolean'),
     dOutlineScale: DefineSpec('number'),
     uOutlineThreshold: UniformSpec('f'),
+
+    dTransparentOutline: DefineSpec('boolean'),
 };
 type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
 
-function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
+function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture, transparentOutline: boolean): PostprocessingRenderable {
     const values: Values<typeof PostprocessingSchema> = {
         ...QuadValues,
         tSsaoDepth: ValueCell.create(ssaoDepthTexture),
@@ -254,6 +260,8 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
         dOutlineEnable: ValueCell.create(false),
         dOutlineScale: ValueCell.create(1),
         uOutlineThreshold: ValueCell.create(0.33),
+
+        dTransparentOutline: ValueCell.create(transparentOutline),
     };
 
     const schema = { ...PostprocessingSchema };
@@ -279,7 +287,7 @@ export const PostprocessingParams = {
             scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }),
             threshold: PD.Numeric(0.33, { min: 0.01, max: 1, step: 0.01 }),
             color: PD.Color(Color(0x000000)),
-            minimumOpacity: PD.Optional(PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'The minimum opacity value needed for an object to be have an outline' })),
+            includeTransparent: PD.Boolean(true, { description: 'Whether to show outline for objects with an opacity value less than 1' }),
         }),
         off: PD.Group({})
     }, { cycle: true, description: 'Draw outline around 3D objects' }),
@@ -301,10 +309,6 @@ export class PostprocessingPass {
         return props.outline.name === 'on';
     }
 
-    static getOutlineMinimumOpacity(props: PostprocessingProps) {
-        return props.outline.name === 'on' ? props.outline.params.minimumOpacity ?? 0.0 : 0.0;
-    }
-
     readonly target: RenderTarget;
 
     private readonly outlinesTarget: RenderTarget;
@@ -353,7 +357,7 @@ export class PostprocessingPass {
         this.target = webgl.createRenderTarget(width, height, false, 'uint8', 'linear');
 
         this.outlinesTarget = webgl.createRenderTarget(width, height, false);
-        this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent);
+        this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent, true);
 
         this.ssaoFramebuffer = webgl.resources.framebuffer();
         this.ssaoBlurFirstPassFramebuffer = webgl.resources.framebuffer();
@@ -378,7 +382,7 @@ export class PostprocessingPass {
         this.ssaoRenderable = getSsaoRenderable(webgl, this.downsampleFactor === 1 ? depthTextureOpaque : this.downsampledDepthTarget.texture);
         this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal');
         this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical');
-        this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture);
+        this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture, true);
 
         this.background = new BackgroundPass(webgl, assetManager, width, height);
     }
@@ -413,6 +417,7 @@ export class PostprocessingPass {
         let needsUpdateMain = false;
         let needsUpdateSsao = false;
         let needsUpdateSsaoBlur = false;
+        let needsUpdateOutline = false;
 
         const orthographic = camera.state.mode === 'orthographic' ? 1 : 0;
         const outlinesEnabled = props.outline.name === 'on';
@@ -500,23 +505,27 @@ export class PostprocessingPass {
         }
 
         if (props.outline.name === 'on') {
-            let { threshold } = props.outline.params;
+            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) / 1000;
             // use radiusMax for stable outlines when zooming
             const maxPossibleViewZDiff = factor * camera.state.radiusMax;
             const outlineScale = props.outline.params.scale - 1;
-
             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) { needsUpdateOutline = true; }            
+            ValueCell.updateIfChanged(this.outlinesRenderable.values.dTransparentOutline, transparentOutline);
 
             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);
             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);
         }
 
         ValueCell.updateIfChanged(this.renderable.values.uFar, camera.far);
@@ -532,6 +541,10 @@ export class PostprocessingPass {
         if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; }
         ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled);
 
+        if (needsUpdateOutline) {
+            this.outlinesRenderable.update();
+        }
+
         if (needsUpdateSsao) {
             this.ssaoRenderable.update();
         }

+ 1 - 7
src/mol-gl/renderer.ts

@@ -80,7 +80,6 @@ interface Renderer {
     setTransparentBackground: (value: boolean) => void
     setDrawingBufferSize: (width: number, height: number) => void
     setPixelRatio: (value: number) => void
-    setOutlineAlphaThreshold: (value: number) => void
 
     dispose: () => void
 }
@@ -187,8 +186,6 @@ namespace Renderer {
         const ambientColor = Vec3();
         Vec3.scale(ambientColor, Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity);
 
-        let outlineAlphaThreshold = 0.0;
-
         const globalUniforms: GlobalUniformValues = {
             uModel: ValueCell.create(Mat4.identity()),
             uView: ValueCell.create(view),
@@ -435,7 +432,7 @@ namespace Renderer {
             const { renderables } = group;
             for (let i = 0, il = renderables.length; i < il; ++i) {
                 const r = renderables[i];
-                if ((!r.state.opaque && r.values.alpha.ref.value > outlineAlphaThreshold) || r.values.transparencyAverage.ref.value > 0 || r.values.dXrayShaded?.ref.value) {
+                if (!r.state.opaque || r.values.transparencyAverage.ref.value > 0 || r.values.dXrayShaded?.ref.value) {
                     renderObject(r, 'depth', Flag.None);
                 }
             }
@@ -830,9 +827,6 @@ namespace Renderer {
                     instancedDrawCount: stats.instancedDrawCount,
                 };
             },
-            setOutlineAlphaThreshold: (value: number) => {
-                outlineAlphaThreshold = value;
-            },
             dispose: () => {
                 // TODO
             }

+ 5 - 1
src/mol-gl/shader/outlines.frag.ts

@@ -38,7 +38,11 @@ float getDepthOpaque(const in vec2 coords) {
 }
 
 float getDepthTransparent(const in vec2 coords) {
-    return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
+    #ifdef dTransparentOutline
+        return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
+    #else
+        return 1.0;
+    #endif
 }
 
 bool isBackground(const in float depth) {

+ 5 - 1
src/mol-gl/shader/postprocessing.frag.ts

@@ -50,7 +50,11 @@ float getDepthOpaque(const in vec2 coords) {
 }
 
 float getDepthTransparent(const in vec2 coords) {
-    return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
+    #ifdef dTransparentOutline
+        return unpackRGBAToDepth(texture2D(tDepthTransparent, coords));
+    #else
+        return 1.0;
+    #endif
 }
 
 bool isBackground(const in float depth) {

+ 2 - 2
src/mol-plugin-ui/structure/quick-styles.tsx

@@ -56,7 +56,7 @@ export class QuickStyles extends PurePluginUIComponent {
                 postprocessing: {
                     outline: {
                         name: 'on',
-                        params: { scale: 1, color: Color(0x000000), threshold: 0.25 }
+                        params: { scale: 1, color: Color(0x000000), threshold: 0.25, includeTransparent: true }
                     },
                     occlusion: {
                         name: 'on',
@@ -78,7 +78,7 @@ export class QuickStyles extends PurePluginUIComponent {
                         name: 'on',
                         params: pp.outline.name === 'on'
                             ? pp.outline.params
-                            : { scale: 1, color: Color(0x000000), threshold: 0.33 }
+                            : { scale: 1, color: Color(0x000000), threshold: 0.33, includeTransparent: true }
                     },
                     occlusion: {
                         name: 'on',