molstar
Version:
A comprehensive macromolecular library.
233 lines (189 loc) • 9.13 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fxaa_frag = void 0;
exports.fxaa_frag = `
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D tColor;
uniform vec2 uTexSizeInv;
// adapted from https://github.com/kosua20/Rendu
// MIT License Copyright (c) 2017 Simon Rodriguez
float rgb2luma(vec3 rgb){
return sqrt(dot(rgb, vec3(0.299, 0.587, 0.114)));
}
float sampleLuma(vec2 uv) {
return rgb2luma(texture2D(tColor, uv).rgb);
}
float sampleLuma(vec2 uv, float uOffset, float vOffset) {
uv += uTexSizeInv * vec2(uOffset, vOffset);
return sampleLuma(uv);
}
void main(void) {
vec2 coords = gl_FragCoord.xy * uTexSizeInv;
vec2 inverseScreenSize = uTexSizeInv;
vec4 colorCenter = texture2D(tColor, coords);
// Luma at the current fragment
float lumaCenter = rgb2luma(colorCenter.rgb);
// Luma at the four direct neighbours of the current fragment.
float lumaDown = sampleLuma(coords, 0.0, -1.0);
float lumaUp = sampleLuma(coords, 0.0, 1.0);
float lumaLeft = sampleLuma(coords, -1.0, 0.0);
float lumaRight = sampleLuma(coords, 1.0, 0.0);
// Find the maximum and minimum luma around the current fragment.
float lumaMin = min(lumaCenter, min(min(lumaDown, lumaUp), min(lumaLeft, lumaRight)));
float lumaMax = max(lumaCenter, max(max(lumaDown, lumaUp), max(lumaLeft, lumaRight)));
// Compute the delta.
float lumaRange = lumaMax - lumaMin;
// If the luma variation is lower that a threshold (or if we are in a really dark area),
// we are not on an edge, don't perform any AA.
if (lumaRange < max(dEdgeThresholdMin, lumaMax * dEdgeThresholdMax)) {
gl_FragColor = colorCenter;
return;
}
// Query the 4 remaining corners lumas.
float lumaDownLeft = sampleLuma(coords, -1.0, -1.0);
float lumaUpRight = sampleLuma(coords, 1.0, 1.0);
float lumaUpLeft = sampleLuma(coords, -1.0, 1.0);
float lumaDownRight = sampleLuma(coords, 1.0, -1.0);
// Combine the four edges lumas (using intermediary variables for future computations
// with the same values).
float lumaDownUp = lumaDown + lumaUp;
float lumaLeftRight = lumaLeft + lumaRight;
// Same for corners
float lumaLeftCorners = lumaDownLeft + lumaUpLeft;
float lumaDownCorners = lumaDownLeft + lumaDownRight;
float lumaRightCorners = lumaDownRight + lumaUpRight;
float lumaUpCorners = lumaUpRight + lumaUpLeft;
// Compute an estimation of the gradient along the horizontal and vertical axis.
float edgeHorizontal = abs(-2.0 * lumaLeft + lumaLeftCorners) + abs(-2.0 * lumaCenter + lumaDownUp) * 2.0 + abs(-2.0 * lumaRight + lumaRightCorners);
float edgeVertical = abs(-2.0 * lumaUp + lumaUpCorners) + abs(-2.0 * lumaCenter + lumaLeftRight) * 2.0 + abs(-2.0 * lumaDown + lumaDownCorners);
// Is the local edge horizontal or vertical ?
bool isHorizontal = (edgeHorizontal >= edgeVertical);
// Choose the step size (one pixel) accordingly.
float stepLength = isHorizontal ? inverseScreenSize.y : inverseScreenSize.x;
// Select the two neighboring texels lumas in the opposite direction to the local edge.
float luma1 = isHorizontal ? lumaDown : lumaLeft;
float luma2 = isHorizontal ? lumaUp : lumaRight;
// Compute gradients in this direction.
float gradient1 = luma1 - lumaCenter;
float gradient2 = luma2 - lumaCenter;
// Which direction is the steepest ?
bool is1Steepest = abs(gradient1) >= abs(gradient2);
// Gradient in the corresponding direction, normalized.
float gradientScaled = 0.25 * max(abs(gradient1), abs(gradient2));
// Average luma in the correct direction.
float lumaLocalAverage = 0.0;
if(is1Steepest){
// Switch the direction
stepLength = -stepLength;
lumaLocalAverage = 0.5 * (luma1 + lumaCenter);
} else {
lumaLocalAverage = 0.5 * (luma2 + lumaCenter);
}
// Shift UV in the correct direction by half a pixel.
vec2 currentUv = coords;
if(isHorizontal){
currentUv.y += stepLength * 0.5;
} else {
currentUv.x += stepLength * 0.5;
}
// Compute offset (for each iteration step) in the right direction.
vec2 offset = isHorizontal ? vec2(inverseScreenSize.x, 0.0) : vec2(0.0, inverseScreenSize.y);
// Compute UVs to explore on each side of the edge, orthogonally.
// The QUALITY allows us to step faster.
vec2 uv1 = currentUv - offset * QUALITY(0);
vec2 uv2 = currentUv + offset * QUALITY(0);
// Read the lumas at both current extremities of the exploration segment,
// and compute the delta wrt to the local average luma.
float lumaEnd1 = sampleLuma(uv1);
float lumaEnd2 = sampleLuma(uv2);
lumaEnd1 -= lumaLocalAverage;
lumaEnd2 -= lumaLocalAverage;
// If the luma deltas at the current extremities is larger than the local gradient,
// we have reached the side of the edge.
bool reached1 = abs(lumaEnd1) >= gradientScaled;
bool reached2 = abs(lumaEnd2) >= gradientScaled;
bool reachedBoth = reached1 && reached2;
// If the side is not reached, we continue to explore in this direction.
if(!reached1){
uv1 -= offset * QUALITY(1);
}
if(!reached2){
uv2 += offset * QUALITY(1);
}
// If both sides have not been reached, continue to explore.
if(!reachedBoth){
for(int i = 2; i < dIterations; i++){
// If needed, read luma in 1st direction, compute delta.
if(!reached1){
lumaEnd1 = sampleLuma(uv1);
lumaEnd1 = lumaEnd1 - lumaLocalAverage;
}
// If needed, read luma in opposite direction, compute delta.
if(!reached2){
lumaEnd2 = sampleLuma(uv2);
lumaEnd2 = lumaEnd2 - lumaLocalAverage;
}
// If the luma deltas at the current extremities is larger than the local gradient,
// we have reached the side of the edge.
reached1 = abs(lumaEnd1) >= gradientScaled;
reached2 = abs(lumaEnd2) >= gradientScaled;
reachedBoth = reached1 && reached2;
// If the side is not reached, we continue to explore in this direction,
// with a variable quality.
if(!reached1){
uv1 -= offset * QUALITY(i);
}
if(!reached2){
uv2 += offset * QUALITY(i);
}
// If both sides have been reached, stop the exploration.
if(reachedBoth){
break;
}
}
}
// Compute the distances to each side edge of the edge (!).
float distance1 = isHorizontal ? (coords.x - uv1.x) : (coords.y - uv1.y);
float distance2 = isHorizontal ? (uv2.x - coords.x) : (uv2.y - coords.y);
// In which direction is the side of the edge closer ?
bool isDirection1 = distance1 < distance2;
float distanceFinal = min(distance1, distance2);
// Thickness of the edge.
float edgeThickness = (distance1 + distance2);
// Is the luma at center smaller than the local average ?
bool isLumaCenterSmaller = lumaCenter < lumaLocalAverage;
// If the luma at center is smaller than at its neighbour,
// the delta luma at each end should be positive (same variation).
bool correctVariation1 = (lumaEnd1 < 0.0) != isLumaCenterSmaller;
bool correctVariation2 = (lumaEnd2 < 0.0) != isLumaCenterSmaller;
// Only keep the result in the direction of the closer side of the edge.
bool correctVariation = isDirection1 ? correctVariation1 : correctVariation2;
// UV offset: read in the direction of the closest side of the edge.
float pixelOffset = - distanceFinal / edgeThickness + 0.5;
// If the luma variation is incorrect, do not offset.
float finalOffset = correctVariation ? pixelOffset : 0.0;
// Sub-pixel shifting
// Full weighted average of the luma over the 3x3 neighborhood.
float lumaAverage = (1.0 / 12.0) * (2.0 * (lumaDownUp + lumaLeftRight) + lumaLeftCorners + lumaRightCorners);
// Ratio of the delta between the global average and the center luma,
// over the luma range in the 3x3 neighborhood.
float subPixelOffset1 = clamp(abs(lumaAverage - lumaCenter) / lumaRange, 0.0, 1.0);
float subPixelOffset2 = (-2.0 * subPixelOffset1 + 3.0) * subPixelOffset1 * subPixelOffset1;
// Compute a sub-pixel offset based on this delta.
float subPixelOffsetFinal = subPixelOffset2 * subPixelOffset2 * float(dSubpixelQuality);
// Pick the biggest of the two offsets.
finalOffset = max(finalOffset, subPixelOffsetFinal);
// Compute the final UV coordinates.
vec2 finalUv = coords;
if(isHorizontal){
finalUv.y += finalOffset * stepLength;
} else {
finalUv.x += finalOffset * stepLength;
}
// Read the color at the new UV coordinates, and use it.
gl_FragColor = texture2D(tColor, finalUv);
}
`;