diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 0950c4ced563b65fe1efd695d65de4bd84dbef0f..75e995aac8d784997a3ef2ac9ddf3572b40f6835 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/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) diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index da4a273a98f6dede4ad3441d82bebf1ab8955fa0..24ab5c36d0bca2f2d710bb059c6d7ca3f041c232 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/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'), } diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index a4ba67c8838305a8eb63e259d19a06b3554e7eba..db06d23bd21387015f46c989a0b705b474dbf099 100644 --- a/src/mol-gl/renderer.ts +++ b/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) diff --git a/src/mol-gl/shader/chunks/apply-fog.glsl.ts b/src/mol-gl/shader/chunks/apply-fog.glsl.ts index d7308351b7c2d98ecdfac9cd73554cc12c252262..2bfd2cd87b334cb9d77d8be7e0c9ce734d723f78 100644 --- a/src/mol-gl/shader/chunks/apply-fog.glsl.ts +++ b/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 ` \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts index 6ee029edb1a3bcfda5866b7be472485185404ba4..28d04173c777ac782cfea172149e2df5c2a948b2 100644 --- a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts +++ b/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; ` \ No newline at end of file diff --git a/src/mol-plugin/skin/base/components/viewport.scss b/src/mol-plugin/skin/base/components/viewport.scss index b77e628d4ea8d97ca5e521501db3b53797263596..54472ba0c377a49525e6616379445420c84cbe57 100644 --- a/src/mol-plugin/skin/base/components/viewport.scss +++ b/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 {