Browse Source

support rendering with transparent background

Alexander Rose 5 years ago
parent
commit
3ea3fb8984

+ 3 - 2
src/mol-canvas3d/canvas3d.ts

@@ -93,10 +93,11 @@ namespace Canvas3D {
 
     export function fromCanvas(canvas: HTMLCanvasElement, props: Partial<Canvas3DProps> = {}, runTask = DefaultRunTask) {
         const gl = getGLContext(canvas, {
-            alpha: false,
+            alpha: true,
             antialias: true,
             depth: true,
-            preserveDrawingBuffer: true
+            preserveDrawingBuffer: true,
+            premultipliedAlpha: false,
         })
         if (gl === null) throw new Error('Could not create a WebGL rendering context')
         const input = InputObserver.fromElement(canvas)

+ 1 - 0
src/mol-gl/renderable/schema.ts

@@ -168,6 +168,7 @@ export const GlobalUniformSchema = {
     uFogFar: UniformSpec('f'),
     uFogColor: UniformSpec('v3'),
 
+    uTransparentBackground: UniformSpec('i'),
     uPickingAlphaThreshold: UniformSpec('f'),
     uInteriorDarkening: UniformSpec('f'),
 }

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

@@ -46,6 +46,7 @@ interface Renderer {
 
 export const RendererParams = {
     backgroundColor: PD.Color(Color(0x000000), { description: 'Background color of the 3D canvas' }),
+    transparentBackground: PD.Boolean(false, { description: 'Background opacity of the 3D canvas' }),
     pickingAlphaThreshold: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'The minimum opacity value needed for an object to be pickable.' }),
     interiorDarkening: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
 
@@ -107,6 +108,7 @@ namespace Renderer {
             uFogFar: ValueCell.create(camera.fogFar),
             uFogColor: ValueCell.create(bgColor),
 
+            uTransparentBackground: ValueCell.create(p.transparentBackground ? 1 : 0),
             uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold),
             uInteriorDarkening: ValueCell.create(p.interiorDarkening),
         }
@@ -191,7 +193,7 @@ namespace Renderer {
 
             if (clear) {
                 if (variant === 'color') {
-                    state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1.0)
+                    state.clearColor(bgColor[0], bgColor[1], bgColor[2], p.transparentBackground ? 0 : 1)
                 } else {
                     state.clearColor(1, 1, 1, 1)
                 }
@@ -204,7 +206,7 @@ namespace Renderer {
                     if (r.state.opaque) renderObject(r, variant)
                 }
 
-                state.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
+                state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE)
                 state.enable(gl.BLEND)
                 for (let i = 0, il = renderables.length; i < il; ++i) {
                     const r = renderables[i]
@@ -224,7 +226,7 @@ namespace Renderer {
             clear: () => {
                 state.depthMask(true)
                 state.colorMask(true, true, true, true)
-                state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1.0)
+                state.clearColor(bgColor[0], bgColor[1], bgColor[2], p.transparentBackground ? 0 : 1)
                 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
             },
             render,
@@ -243,6 +245,10 @@ namespace Renderer {
                     Color.toVec3Normalized(bgColor, p.backgroundColor)
                     ValueCell.update(globalUniforms.uFogColor, Vec3.copy(globalUniforms.uFogColor.ref.value, bgColor))
                 }
+                if (props.transparentBackground !== undefined && props.transparentBackground !== p.transparentBackground) {
+                    p.transparentBackground = props.transparentBackground
+                    ValueCell.update(globalUniforms.uTransparentBackground, p.transparentBackground ? 1 : 0)
+                }
                 if (props.lightIntensity !== undefined && props.lightIntensity !== p.lightIntensity) {
                     p.lightIntensity = props.lightIntensity
                     ValueCell.update(globalUniforms.uLightIntensity, p.lightIntensity)

+ 6 - 5
src/mol-gl/shader/chunks/apply-fog.glsl.ts

@@ -2,10 +2,11 @@ export default `
 #ifdef dUseFog
 	float depth = length(vViewPosition);
     float fogFactor = smoothstep(uFogNear, uFogFar, depth);
-	gl_FragColor.rgb = mix(gl_FragColor.rgb, uFogColor, fogFactor);
-    float fogAlpha = (1.0 - fogFactor) * gl_FragColor.a;
-    if (fogAlpha < 0.01)
-        discard;
-    gl_FragColor = vec4(gl_FragColor.rgb, fogAlpha);
+    if (uTransparentBackground == 0) {
+	    gl_FragColor.rgb = mix(gl_FragColor.rgb, uFogColor, fogFactor);
+    } else {
+        float fogAlpha = (1.0 - fogFactor) * gl_FragColor.a;
+        gl_FragColor.a = fogAlpha;
+    }
 #endif
 `

+ 1 - 0
src/mol-gl/shader/chunks/common-frag-params.glsl.ts

@@ -22,6 +22,7 @@ uniform vec3 uFogColor;
 uniform float uAlpha;
 uniform float uPickingAlphaThreshold;
 uniform int uPickable;
+uniform int uTransparentBackground;
 
 uniform float uInteriorDarkening;
 `

+ 8 - 0
src/mol-plugin/skin/base/components/viewport.scss

@@ -27,6 +27,14 @@
     -webkit-tap-highlight-color: rgba(0,0,0,0);
     -webkit-touch-callout: none;
     touch-action: manipulation;
+
+    > canvas {
+        background-color: $default-background;
+        background-image: linear-gradient(45deg, lightgrey 25%, transparent 25%, transparent 75%, lightgrey 75%, lightgrey),
+        linear-gradient(45deg, lightgrey 25%, transparent 25%, transparent 75%, lightgrey 75%, lightgrey);
+        background-size: 60px 60px;
+        background-position: 0 0, 30px 30px;
+    }
 }
 
 .msp-viewport-controls {