molstar
Version:
A comprehensive macromolecular library.
185 lines (153 loc) • 7.66 kB
JavaScript
"use strict";
/**
* Copyright (c) 2019-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
* @author Sebastian Bittrich <sebastian.m.bittrich@gmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.outlines_frag = void 0;
exports.outlines_frag = `
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D tDepthOpaque;
uniform sampler2D tDepthTransparent;
uniform vec2 uTexSize;
uniform float uNear;
uniform float uFar;
uniform mat4 uInvProjection;
uniform float uOutlineThreshold;
float getViewZ(const in float depth) {
return orthographicDepthToViewZ(depth, uNear, uFar);
return perspectiveDepthToViewZ(depth, uNear, uFar);
}
float getDepthOpaque(const in vec2 coords) {
return texture2D(tDepthOpaque, coords).r;
return unpackRGBAToDepth(texture2D(tDepthOpaque, coords));
}
vec2 getDepthTransparentWithAlpha(const in vec2 coords) {
return unpackRGBAToDepthWithAlpha(texture2D(tDepthTransparent, coords));
return vec2(1.0, 0.0);
}
bool isBackground(const in float depth) {
return depth == 1.0;
}
float getPixelSize(const in vec2 coords, const in float depth) {
vec3 viewPos0 = screenSpaceToViewSpace(vec3(coords, depth), uInvProjection);
vec3 viewPos1 = screenSpaceToViewSpace(vec3(coords + vec2(1.0, 0.0) / uTexSize, depth), uInvProjection);
return distance(viewPos0, viewPos1);
}
void main(void) {
float backgroundViewZ = 2.0 * uFar;
vec2 coords = gl_FragCoord.xy / uTexSize;
vec2 invTexSize = 1.0 / uTexSize;
float selfDepthOpaque = getDepthOpaque(coords);
float selfViewZOpaque = isBackground(selfDepthOpaque) ? backgroundViewZ : getViewZ(selfDepthOpaque);
float pixelSizeOpaque = getPixelSize(coords, selfDepthOpaque) * uOutlineThreshold;
vec2 selfDepthTransparentWithAlpha = getDepthTransparentWithAlpha(coords);
float selfDepthTransparent = selfDepthTransparentWithAlpha.x;
float selfViewZTransparent = isBackground(selfDepthTransparent) ? backgroundViewZ : getViewZ(selfDepthTransparent);
float pixelSizeTransparent = getPixelSize(coords, selfDepthTransparent) * uOutlineThreshold;
float bestOpaqueDepth = 1.0;
float bestTransparentDepth = 1.0;
float bestTransparentAlpha = 0.0;
float opaqueOutlineFlag = 0.0;
float transparentOutlineFlag = 0.0;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 sampleCoords = coords + vec2(float(x), float(y)) * invTexSize;
// Opaque
float sampleDepthOpaque = getDepthOpaque(sampleCoords);
float sampleViewZOpaque = isBackground(sampleDepthOpaque) ? backgroundViewZ : getViewZ(sampleDepthOpaque);
if (abs(selfViewZOpaque - sampleViewZOpaque) > pixelSizeOpaque && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestOpaqueDepth) {
bestOpaqueDepth = sampleDepthOpaque;
opaqueOutlineFlag = 1.0;
}
// Transparent
vec2 sampleDepthTransparentWithAlpha = getDepthTransparentWithAlpha(sampleCoords);
float sampleDepthTransparent = sampleDepthTransparentWithAlpha.x;
float sampleAlphaTransparent = sampleDepthTransparentWithAlpha.y;
float sampleViewZTransparent = isBackground(sampleDepthTransparent) ? backgroundViewZ : getViewZ(sampleDepthTransparent);
if (abs(selfViewZTransparent - sampleViewZTransparent) > pixelSizeTransparent && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestTransparentDepth) {
bestTransparentDepth = sampleDepthTransparent;
bestTransparentAlpha = sampleAlphaTransparent;
transparentOutlineFlag = 1.0;
}
}
}
if (transparentOutlineFlag > 0.0 && abs(selfViewZOpaque - getViewZ(bestTransparentDepth)) < pixelSizeOpaque) { // Disable transparent outline close to opaque elements
transparentOutlineFlag = 0.0;
}
// lazy curvature veto: only compute if an outline was found and center is not background
const float kCurvatureGate = 0.75;
vec2 dx = vec2(invTexSize.x, 0.0);
vec2 dy = vec2(0.0, invTexSize.y);
if (opaqueOutlineFlag > 0.0 && !isBackground(selfDepthOpaque)) {
float dL = getDepthOpaque(coords - dx);
float dR = getDepthOpaque(coords + dx);
float dU = getDepthOpaque(coords + dy);
float dD = getDepthOpaque(coords - dy);
float vzL = isBackground(dL) ? backgroundViewZ : getViewZ(dL);
float vzR = isBackground(dR) ? backgroundViewZ : getViewZ(dR);
float vzU = isBackground(dU) ? backgroundViewZ : getViewZ(dU);
float vzD = isBackground(dD) ? backgroundViewZ : getViewZ(dD);
float ddx = abs(vzL + vzR - 2.0 * selfViewZOpaque);
float ddy = abs(vzU + vzD - 2.0 * selfViewZOpaque);
float curvOpaque = max(ddx, ddy);
if (curvOpaque < pixelSizeOpaque * kCurvatureGate) {
opaqueOutlineFlag = 0.0;
bestOpaqueDepth = 1.0;
}
}
if (transparentOutlineFlag > 0.0 && !isBackground(selfDepthTransparent)) {
vec2 daL = getDepthTransparentWithAlpha(coords - dx);
vec2 daR = getDepthTransparentWithAlpha(coords + dx);
vec2 daU = getDepthTransparentWithAlpha(coords + dy);
vec2 daD = getDepthTransparentWithAlpha(coords - dy);
float dL = daL.x;
float dR = daR.x;
float dU = daU.x;
float dD = daD.x;
float vzL = isBackground(dL) ? backgroundViewZ : getViewZ(dL);
float vzR = isBackground(dR) ? backgroundViewZ : getViewZ(dR);
float vzU = isBackground(dU) ? backgroundViewZ : getViewZ(dU);
float vzD = isBackground(dD) ? backgroundViewZ : getViewZ(dD);
float ddx = abs(vzL + vzR - 2.0 * selfViewZTransparent);
float ddy = abs(vzU + vzD - 2.0 * selfViewZTransparent);
float curvTransparent = max(ddx, ddy);
if (curvTransparent < pixelSizeTransparent * kCurvatureGate) {
transparentOutlineFlag = 0.0;
bestTransparentDepth = 1.0;
bestTransparentAlpha = 0.0;
}
}
vec2 depthPacked; // Pack depth in G/B channels
float outlineTypeFlag = 0.0;
if (opaqueOutlineFlag > 0.0 && transparentOutlineFlag > 0.0) {
outlineTypeFlag = 0.75; // Both
depthPacked = packUnitIntervalToRG(bestOpaqueDepth);
} else if (transparentOutlineFlag > 0.0) {
outlineTypeFlag = 0.5; // Transparent only
depthPacked = packUnitIntervalToRG(bestTransparentDepth);
} else if (opaqueOutlineFlag > 0.0) {
outlineTypeFlag = 0.25; // Opaque only
depthPacked = packUnitIntervalToRG(bestOpaqueDepth);
}
float alpha = clamp(bestTransparentAlpha, 0.0, 0.5) * 2.0; // limiting to range [0.0, 0.5] to improve alpha precision since we don't need a wider range
float packedFlagWithAlpha = pack2x4(vec2(outlineTypeFlag, alpha)); // pack outlineType with alpha
gl_FragColor = vec4(packedFlagWithAlpha, depthPacked.x, depthPacked.y, bestTransparentDepth);
}
`;