Ver Fonte

handle outlines for per-group transparency

- fix allowTransparentBackfaces for per-group transparency
Alexander Rose há 2 anos atrás
pai
commit
102ef2795d

+ 2 - 1
CHANGELOG.md

@@ -7,7 +7,8 @@ Note that since we don't clearly distinguish between a public and private interf
 ## [Unreleased]
 
 - Fix case handling of ``struct_conf`` mmCIF enumeration field (#425)
-- Add support for outlines around transparent objects (only per-object)
+- Add support for outlines around transparent objects
+- Fix ``allowTransparentBackfaces`` for per-group transparency
 
 ## [v3.7.0] - 2022-04-13
 

+ 1 - 1
src/mol-canvas3d/passes/draw.ts

@@ -144,7 +144,7 @@ export class DrawPass {
                 this.depthTarget.bind();
                 renderer.clear(false);
                 if (scene.getOpacityAverage() < 1) {
-                    renderer.renderDepthTransparent(scene.primitives, camera, null);
+                    renderer.renderDepthWboit(scene.primitives, camera, null);
                 }
             }
 

+ 2 - 2
src/mol-geo/geometry/cylinders/cylinders.ts

@@ -242,7 +242,7 @@ export namespace Cylinders {
             uDoubleSided: ValueCell.create(props.doubleSided),
             dIgnoreLight: ValueCell.create(props.ignoreLight),
             dXrayShaded: ValueCell.create(props.xrayShaded),
-            dOpaqueBackfaces: ValueCell.create(props.transparentBackfaces === 'opaque'),
+            dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
             uBumpFrequency: ValueCell.create(props.bumpFrequency),
             uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
         };
@@ -260,7 +260,7 @@ export namespace Cylinders {
         ValueCell.updateIfChanged(values.uDoubleSided, props.doubleSided);
         ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
         ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
-        ValueCell.updateIfChanged(values.dOpaqueBackfaces, props.transparentBackfaces === 'opaque');
+        ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
         ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
         ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
     }

+ 2 - 2
src/mol-geo/geometry/mesh/mesh.ts

@@ -701,7 +701,7 @@ export namespace Mesh {
             dFlipSided: ValueCell.create(props.flipSided),
             dIgnoreLight: ValueCell.create(props.ignoreLight),
             dXrayShaded: ValueCell.create(props.xrayShaded),
-            dOpaqueBackfaces: ValueCell.create(props.transparentBackfaces === 'opaque'),
+            dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
             uBumpFrequency: ValueCell.create(props.bumpFrequency),
             uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
 
@@ -722,7 +722,7 @@ export namespace Mesh {
         ValueCell.updateIfChanged(values.dFlipSided, props.flipSided);
         ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
         ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
-        ValueCell.updateIfChanged(values.dOpaqueBackfaces, props.transparentBackfaces === 'opaque');
+        ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
         ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
         ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
     }

+ 2 - 2
src/mol-geo/geometry/spheres/spheres.ts

@@ -209,7 +209,7 @@ export namespace Spheres {
             uDoubleSided: ValueCell.create(props.doubleSided),
             dIgnoreLight: ValueCell.create(props.ignoreLight),
             dXrayShaded: ValueCell.create(props.xrayShaded),
-            dOpaqueBackfaces: ValueCell.create(props.transparentBackfaces === 'opaque'),
+            dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
             uBumpFrequency: ValueCell.create(props.bumpFrequency),
             uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
         };
@@ -227,7 +227,7 @@ export namespace Spheres {
         ValueCell.updateIfChanged(values.uDoubleSided, props.doubleSided);
         ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
         ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
-        ValueCell.updateIfChanged(values.dOpaqueBackfaces, props.transparentBackfaces === 'opaque');
+        ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
         ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
         ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
     }

+ 2 - 2
src/mol-geo/geometry/texture-mesh/texture-mesh.ts

@@ -174,7 +174,7 @@ export namespace TextureMesh {
             dFlipSided: ValueCell.create(props.flipSided),
             dIgnoreLight: ValueCell.create(props.ignoreLight),
             dXrayShaded: ValueCell.create(props.xrayShaded),
-            dOpaqueBackfaces: ValueCell.create(props.transparentBackfaces === 'opaque'),
+            dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
             uBumpFrequency: ValueCell.create(props.bumpFrequency),
             uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
 
@@ -195,7 +195,7 @@ export namespace TextureMesh {
         ValueCell.updateIfChanged(values.dFlipSided, props.flipSided);
         ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
         ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
-        ValueCell.updateIfChanged(values.dOpaqueBackfaces, props.transparentBackfaces === 'opaque');
+        ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
         ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
         ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
     }

+ 1 - 1
src/mol-gl/renderable/cylinders.ts

@@ -26,7 +26,7 @@ export const CylindersSchema = {
     uDoubleSided: UniformSpec('b'),
     dIgnoreLight: DefineSpec('boolean'),
     dXrayShaded: DefineSpec('boolean'),
-    dOpaqueBackfaces: DefineSpec('boolean'),
+    dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
     uBumpFrequency: UniformSpec('f'),
     uBumpAmplitude: UniformSpec('f'),
 };

+ 1 - 1
src/mol-gl/renderable/mesh.ts

@@ -22,7 +22,7 @@ export const MeshSchema = {
     dFlipSided: DefineSpec('boolean'),
     dIgnoreLight: DefineSpec('boolean'),
     dXrayShaded: DefineSpec('boolean'),
-    dOpaqueBackfaces: DefineSpec('boolean'),
+    dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
     uBumpFrequency: UniformSpec('f'),
     uBumpAmplitude: UniformSpec('f'),
     meta: ValueSpec('unknown')

+ 1 - 1
src/mol-gl/renderable/spheres.ts

@@ -23,7 +23,7 @@ export const SpheresSchema = {
     uDoubleSided: UniformSpec('b'),
     dIgnoreLight: DefineSpec('boolean'),
     dXrayShaded: DefineSpec('boolean'),
-    dOpaqueBackfaces: DefineSpec('boolean'),
+    dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
     uBumpFrequency: UniformSpec('f'),
     uBumpAmplitude: UniformSpec('f'),
 };

+ 1 - 1
src/mol-gl/renderable/texture-mesh.ts

@@ -23,7 +23,7 @@ export const TextureMeshSchema = {
     dFlipSided: DefineSpec('boolean'),
     dIgnoreLight: DefineSpec('boolean'),
     dXrayShaded: DefineSpec('boolean'),
-    dOpaqueBackfaces: DefineSpec('boolean'),
+    dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
     uBumpFrequency: UniformSpec('f'),
     uBumpAmplitude: UniformSpec('f'),
     meta: ValueSpec('unknown')

+ 22 - 3
src/mol-gl/renderer.ts

@@ -61,6 +61,7 @@ interface Renderer {
     renderDepth: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderDepthOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderDepthTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
+    renderDepthWboit: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderMarkingDepth: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderMarkingMask: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
     renderBlended: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
@@ -408,6 +409,23 @@ namespace Renderer {
             }
         };
 
+        const renderDepthWboit = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
+            state.disable(gl.BLEND);
+            state.enable(gl.DEPTH_TEST);
+            state.depthMask(true);
+
+            updateInternal(group, camera, depthTexture, true, false);
+
+            const { renderables } = group;
+            for (let i = 0, il = renderables.length; i < il; ++i) {
+                const r = renderables[i];
+
+                if (!r.state.opaque || r.values.transparencyAverage.ref.value > 0) {
+                    renderObject(r, 'depth', Flag.None);
+                }
+            }
+        };
+
         const renderMarkingDepth = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
             state.disable(gl.BLEND);
             state.enable(gl.DEPTH_TEST);
@@ -461,7 +479,7 @@ namespace Renderer {
                 const r = renderables[i];
                 if (r.state.opaque) {
                     renderObject(r, 'colorBlended', Flag.None);
-                } else if (r.values.uDoubleSided?.ref.value && r.values.dOpaqueBackfaces?.ref.value) {
+                } else if (r.values.uDoubleSided?.ref.value && r.values.dTransparentBackfaces?.ref.value === 'opaque') {
                     renderObject(r, 'colorBlended', Flag.BlendedBack);
                 }
             }
@@ -495,7 +513,7 @@ namespace Renderer {
                 if (!r.state.opaque && !r.state.writeDepth) {
                     if (r.values.uDoubleSided?.ref.value) {
                         // render frontfaces and backfaces separately to avoid artefacts
-                        if (!r.values.dOpaqueBackfaces?.ref.value) {
+                        if (r.values.dTransparentBackfaces?.ref.value !== 'opaque') {
                             renderObject(r, 'colorBlended', Flag.BlendedBack);
                         }
                         renderObject(r, 'colorBlended', Flag.BlendedFront);
@@ -535,7 +553,7 @@ namespace Renderer {
                 // TODO: simplify, handle in renderable.state???
                 // uAlpha is updated in "render" so we need to recompute it here
                 const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
-                if ((alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values.dGeometryType.ref.value !== 'directVolume' && r.values.dPointStyle?.ref.value !== 'fuzzy' && !r.values.dXrayShaded?.ref.value) || r.values.dOpaqueBackfaces?.ref.value) {
+                if ((alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values.dGeometryType.ref.value !== 'directVolume' && r.values.dPointStyle?.ref.value !== 'fuzzy' && !r.values.dXrayShaded?.ref.value) || r.values.dTransparentBackfaces?.ref.value === 'opaque') {
                     renderObject(r, 'colorWboit', Flag.None);
                 }
             }
@@ -585,6 +603,7 @@ namespace Renderer {
             renderDepth,
             renderDepthOpaque,
             renderDepthTransparent,
+            renderDepthWboit,
             renderMarkingDepth,
             renderMarkingMask,
             renderBlended,

+ 1 - 1
src/mol-gl/shader/chunks/apply-interior-color.glsl.ts

@@ -6,7 +6,7 @@ if (interior) {
         gl_FragColor.rgb *= 1.0 - uInteriorDarkening;
     }
 
-    #ifdef dOpaqueBackfaces
+    #ifdef dTransparentBackfaces_opaque
         gl_FragColor.a = 1.0;
     #endif
 }

+ 12 - 1
src/mol-gl/shader/chunks/assign-material-color.glsl.ts

@@ -31,6 +31,9 @@ export const assign_material_color = `
 #elif defined(dRenderVariant_pick)
     vec4 material = vColor;
 #elif defined(dRenderVariant_depth)
+    if (uRenderWboit && gl_FragColor.a == 1.0) {
+        discard;
+    }
     #ifdef enabledFragDepth
         vec4 material = packDepthToRGBA(gl_FragDepthEXT);
     #else
@@ -74,6 +77,10 @@ export const assign_material_color = `
             discard; // ignore so the element below can be picked
     #else
         #if defined(dRenderVariant_colorBlended)
+            #if defined(dTransparentBackfaces_off)
+                if (interior && ta < 1.0) discard;
+            #endif
+
             float at = 0.0;
 
             // shift by view-offset during multi-sample rendering to allow for blending
@@ -99,7 +106,11 @@ export const assign_material_color = `
             #endif
 
             if (ta < 0.99 && (ta < 0.01 || ta < at)) {
-                discard;
+                #if defined(dTransparentBackfaces_opaque)
+                    if (!interior) discard;
+                #else
+                    discard;
+                #endif
             }
         #elif defined(dRenderVariant_colorWboit)
             material.a *= ta;

+ 1 - 1
src/mol-gl/shader/chunks/check-picking-alpha.glsl.ts

@@ -4,7 +4,7 @@ float fogFactor = smoothstep(uFogNear, uFogFar, abs(viewZ));
 float alpha = (1.0 - fogFactor) * uAlpha;
 // if not opaque enough ignore so the element below can be picked
 if (uAlpha < uPickingAlphaThreshold || alpha < 0.1) {
-    #ifdef dOpaqueBackfaces
+    #ifdef dTransparentBackfaces_opaque
         if (!interior) discard;
     #else
         discard;

+ 3 - 0
src/mol-gl/shader/chunks/wboit-write.glsl.ts

@@ -14,6 +14,9 @@ export const wboit_write = `
     } else if (uRenderWboit) {
         // the 'fragmentDepth > 0.99' check is to handle precision issues with packed depth
         if (preFogAlpha != 1.0 && (fragmentDepth < getDepth(gl_FragCoord.xy / uDrawingBufferSize) || fragmentDepth > 0.99)) {
+            #ifdef dTransparentBackfaces_off
+                if (interior) discard;
+            #endif
             float alpha = gl_FragColor.a;
             float wboitWeight = alpha * clamp(pow(1.0 - fragmentDepth, 2.0), 0.01, 1.0);
             gl_FragColor = vec4(gl_FragColor.rgb * alpha * wboitWeight, alpha);