UNPKG

molstar

Version:

A comprehensive macromolecular library.

223 lines (194 loc) 8.14 kB
/** * Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz> * @author Gianluca Tomasello <giagitom@gmail.com> */ export const postprocessing_frag = ` precision highp float; precision highp int; precision highp sampler2D; uniform sampler2D tSsaoDepth; uniform sampler2D tSsaoDepthTransparent; uniform sampler2D tColor; uniform sampler2D tTransparentColor; uniform sampler2D tDepthOpaque; uniform sampler2D tDepthTransparent; uniform sampler2D tShadows; uniform sampler2D tOutlines; uniform vec2 uTexSize; uniform float uNear; uniform float uFar; uniform float uFogNear; uniform float uFogFar; uniform vec3 uFogColor; uniform vec3 uOutlineColor; uniform vec3 uOcclusionColor; uniform bool uTransparentBackground; uniform vec2 uOcclusionOffset; #include common float getViewZ(const in float depth) { #if dOrthographic == 1 return orthographicDepthToViewZ(depth, uNear, uFar); #else return perspectiveDepthToViewZ(depth, uNear, uFar); #endif } float getDepthOpaque(const in vec2 coords) { #ifdef depthTextureSupport return texture2D(tDepthOpaque, coords).r; #else return unpackRGBAToDepth(texture2D(tDepthOpaque, coords)); #endif } float getDepthTransparent(const in vec2 coords) { return unpackRGBAToDepthWithAlpha(texture2D(tDepthTransparent, coords)).x; } bool isBackground(const in float depth) { return depth == 1.0; } int squaredOutlineScale = dOutlineScale * dOutlineScale; void getOutline(const in vec2 coords, out bool hasOpaque, out bool hasTransparent, out float opaqueDepth, out float transparentDepth, out float alpha) { vec2 invTexSize = 1.0 / uTexSize; hasOpaque = false; hasTransparent = false; opaqueDepth = 1.0; transparentDepth = 1.0; alpha = 0.0; for (int y = -dOutlineScale; y <= dOutlineScale; y++) { for (int x = -dOutlineScale; x <= dOutlineScale; x++) { if (x * x + y * y > squaredOutlineScale) { continue; } vec2 sampleCoords = coords + vec2(float(x), float(y)) * invTexSize; vec4 sampleOutlineCombined = texture2D(tOutlines, sampleCoords); float sampleOpaqueDepth = unpackRGToUnitInterval(sampleOutlineCombined.gb); float sampleTransparentDepth = sampleOutlineCombined.a; vec2 sampleFlagWithAlpha = unpack2x4(sampleOutlineCombined.r); float sampleFlag = sampleFlagWithAlpha.x; float sampleAlpha = clamp(sampleFlagWithAlpha.y * 0.5, 0.01, 1.0); if ((sampleFlag > 0.20 && sampleFlag < 0.30) || (sampleFlag > 0.70 && sampleFlag < 0.80)) { // transparent || both if (sampleOpaqueDepth < opaqueDepth) { hasOpaque = true; opaqueDepth = sampleOpaqueDepth; } } if ((((sampleFlag > 0.45 && sampleFlag < 0.55) || (sampleFlag > 0.70 && sampleFlag < 0.80))) && sampleTransparentDepth < transparentDepth) { // transparent || both hasTransparent = true; transparentDepth = sampleTransparentDepth; alpha = sampleAlpha; } } } } float getSsao(vec2 coords) { float rawSsao = unpackRGToUnitInterval(texture2D(tSsaoDepth, coords).xy); if (rawSsao > 0.999) { return 1.0; } else if (rawSsao > 0.001) { return rawSsao; } // treat values close to 0.0 as errors and return no occlusion return 1.0; } float getSsaoTransparent(vec2 coords) { float rawSsao = unpackRGToUnitInterval(texture2D(tSsaoDepthTransparent, coords).xy); if (rawSsao > 0.999) { return 1.0; } else if (rawSsao > 0.001) { return rawSsao; } // treat values close to 0.0 as errors and return no occlusion return 1.0; } void main(void) { vec2 coords = gl_FragCoord.xy / uTexSize; vec4 color = texture2D(tColor, coords); float opaqueDepth = getDepthOpaque(coords); float transparentDepth = 1.0; #ifdef dBlendTransparency bool blendTransparency = true; vec4 transparentColor = texture2D(tTransparentColor, coords); #if defined(dOutlineEnable) || defined(dOcclusionEnable) && defined(dOcclusionIncludeTransparency) transparentDepth = getDepthTransparent(coords); #endif #endif #if defined(dOcclusionEnable) || defined(dShadowEnable) bool isOpaqueBackground = isBackground(opaqueDepth); float viewDist = abs(getViewZ(opaqueDepth)); float fogFactor = smoothstep(uFogNear, uFogFar, viewDist); #endif #if defined(dOcclusionEnable) if (!isOpaqueBackground) { float occlusionFactor = getSsao(coords + uOcclusionOffset); if (!uTransparentBackground) { color.rgb = mix(mix(uOcclusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor); } else { color.rgb = mix(uOcclusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor); } } #if defined(dBlendTransparency) && defined(dOcclusionIncludeTransparency) if (!isBackground(transparentDepth)) { float viewDist = abs(getViewZ(transparentDepth)); float fogFactor = smoothstep(uFogNear, uFogFar, viewDist); float occlusionFactor = getSsaoTransparent(coords + uOcclusionOffset); transparentColor.rgb = mix(uOcclusionColor * (1.0 - fogFactor), transparentColor.rgb, occlusionFactor); } #endif #endif #ifdef dShadowEnable if (!isOpaqueBackground) { vec4 shadow = texture2D(tShadows, coords); if (!uTransparentBackground) { color.rgb = mix(mix(vec3(0), uFogColor, fogFactor), color.rgb, shadow.a); } else { color.rgb = mix(vec3(0) * (1.0 - fogFactor), color.rgb, shadow.a); } } #endif // outline needs to be handled after occlusion and shadow to keep them clean #ifdef dOutlineEnable bool hasOpaque; bool hasTransparent; float outlineOpaqueDepth; float outlineTransparentDepth; float outlineAlpha; getOutline(coords, hasOpaque, hasTransparent, outlineOpaqueDepth, outlineTransparentDepth, outlineAlpha); if (hasOpaque) { float viewDist = abs(getViewZ(outlineOpaqueDepth)); float fogFactor = smoothstep(uFogNear, uFogFar, viewDist); if (!uTransparentBackground) { color.rgb = mix(uOutlineColor, uFogColor, fogFactor); } else { color.a = 1.0 - fogFactor; color.rgb = mix(uOutlineColor, vec3(0.0), fogFactor); } } #ifdef dBlendTransparency if (hasTransparent) { if (hasOpaque && outlineOpaqueDepth < outlineTransparentDepth) { blendTransparency = false; } else { float finalOutlineAlpha = clamp(outlineAlpha * 2.0, 0.0, 1.0); float viewDist = abs(getViewZ(outlineTransparentDepth)); float fogFactor = smoothstep(uFogNear, uFogFar, viewDist); float finalAlpha = max(transparentColor.a, finalOutlineAlpha * (1.0 - fogFactor)); transparentColor.a = finalAlpha; transparentColor.rgb = uOutlineColor * finalAlpha; } } #endif #endif #ifdef dBlendTransparency if (blendTransparency) { float alpha = transparentColor.a; if (alpha != 0.0) { // blending color = transparentColor + color * (1.0 - alpha); } } #endif gl_FragColor = color; } `;