mirror of
https://github.com/cemu-project/cemu_graphic_packs.git
synced 2024-12-23 08:21:51 +01:00
FXAA pack improvements; Integrated Contrasty, better FXAA, less blurry(#92)
Pull request #92 * Added resolution independent FXAA for BotW * Renamed to give FXAA priority over base graphics packs * Updated FXAA implementation. Integrated Contrasty. * Sharper default settings, to make it look better at native res. Contrasty isn't on by default, you can change it by editing `f14bb57cd5c9cb77_00000000000003c9_ps.txt` and changing ``` #define ENABLE_CONTRASTY 0 ``` to ``` #define ENABLE_CONTRASTY 1 ``` in the graphic pack.
This commit is contained in:
parent
a4da8f46ca
commit
c10123ff26
@ -3,7 +3,16 @@
|
|||||||
// shader 0f2b9ee517917425
|
// shader 0f2b9ee517917425
|
||||||
//replaces broken aa in inventory screen with fxaa.
|
//replaces broken aa in inventory screen with fxaa.
|
||||||
//original shader dumped using cemu 1.9.1, BotW 1.3.1
|
//original shader dumped using cemu 1.9.1, BotW 1.3.1
|
||||||
//credit goes to https://gist.github.com/sakrist/7912905
|
//credit for fxaa implementation http://blog.simonrodriguez.fr/articles/30-07-2016_implementing_fxaa.html
|
||||||
|
|
||||||
|
#define ENABLE_FXAA 1
|
||||||
|
|
||||||
|
const float EDGE_THRESHOLD_MIN = 0.04;
|
||||||
|
const float EDGE_THRESHOLD_MAX = 0.125;
|
||||||
|
const float SUBPIXEL_QUALITY = 0.5;
|
||||||
|
const float[] QUALITY = {1.5, 2.0, 2.0, 2.0, 2.0, 4.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0};
|
||||||
|
const int ITERATIONS = 12;
|
||||||
|
|
||||||
uniform ivec4 uf_remappedPS[2];
|
uniform ivec4 uf_remappedPS[2];
|
||||||
layout(binding = 0) uniform sampler2D textureUnitPS0;// Tex0 addr 0xf49b1800 res 1280x720x1 dim 1 tm: 4 format 0019 compSel: 0 1 2 3 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler0 ClampX/Y/Z: 2 2 2 border: 1
|
layout(binding = 0) uniform sampler2D textureUnitPS0;// Tex0 addr 0xf49b1800 res 1280x720x1 dim 1 tm: 4 format 0019 compSel: 0 1 2 3 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler0 ClampX/Y/Z: 2 2 2 border: 1
|
||||||
layout(binding = 1) uniform sampler2D textureUnitPS1;// Tex1 addr 0x38784000 res 1280x720x1 dim 1 tm: 4 format 0001 compSel: 0 4 4 5 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler1 ClampX/Y/Z: 2 2 2 border: 1
|
layout(binding = 1) uniform sampler2D textureUnitPS1;// Tex1 addr 0x38784000 res 1280x720x1 dim 1 tm: 4 format 0001 compSel: 0 4 4 5 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler1 ClampX/Y/Z: 2 2 2 border: 1
|
||||||
@ -11,60 +20,205 @@ layout(location = 0) in vec4 passParameterSem2;
|
|||||||
layout(location = 0) out vec4 passPixelColor0;
|
layout(location = 0) out vec4 passPixelColor0;
|
||||||
uniform vec2 uf_fragCoordScale;
|
uniform vec2 uf_fragCoordScale;
|
||||||
|
|
||||||
const float FXAA_SPAN_MAX = 8.0;
|
float rgb2luma(vec3 rgb) {
|
||||||
const float FXAA_REDUCE_MUL = 1.0 / 8.0;
|
return sqrt(dot(rgb, vec3(0.299, 0.587, 0.114)));
|
||||||
const float FXAA_REDUCE_MIN = 1.0 / 128.0;
|
}
|
||||||
const ivec2 res = textureSize(textureUnitPS0,0);
|
|
||||||
const vec2 frameBufSize = vec2( float(res.x), float(res.y) );
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec2 texCoords = passParameterSem2.xy;
|
vec2 texCoords = passParameterSem2.xy;
|
||||||
vec3 rgbNW = texture2D(textureUnitPS0, texCoords + (vec2(-1.0, -1.0) / frameBufSize)).xyz;
|
vec3 colorCenter = texture(textureUnitPS0, texCoords).rgb;
|
||||||
vec3 rgbNE = texture2D(textureUnitPS0, texCoords + (vec2(1.0, -1.0) / frameBufSize)).xyz;
|
passPixelColor0.rgb = colorCenter;
|
||||||
vec3 rgbSW = texture2D(textureUnitPS0, texCoords + (vec2(-1.0, 1.0) / frameBufSize)).xyz;
|
|
||||||
vec3 rgbSE = texture2D(textureUnitPS0, texCoords + (vec2(1.0, 1.0) / frameBufSize)).xyz;
|
|
||||||
vec3 rgbM = texture2D(textureUnitPS0, texCoords).xyz;
|
|
||||||
|
|
||||||
vec3 luma = vec3(0.299, 0.587, 0.114);
|
#if (ENABLE_FXAA == 1)
|
||||||
float lumaNW = dot(rgbNW, luma);
|
ivec2 texSize = textureSize(textureUnitPS0, 0);
|
||||||
float lumaNE = dot(rgbNE, luma);
|
vec2 framebufferSize = vec2(float(texSize.x), float(texSize.y));
|
||||||
float lumaSW = dot(rgbSW, luma);
|
vec2 invFramebufferSize = vec2(1.0 / framebufferSize.x, 1.0 / framebufferSize.y);
|
||||||
float lumaSE = dot(rgbSE, luma);
|
|
||||||
float lumaM = dot(rgbM, luma);
|
|
||||||
|
|
||||||
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
|
// Luma at the current fragment
|
||||||
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
|
float lumaCenter = rgb2luma(colorCenter);
|
||||||
|
|
||||||
vec2 dir;
|
// Luma at the four direct neighbours of the current fragment.
|
||||||
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
|
float lumaDown = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(0, -1)).rgb);
|
||||||
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
|
float lumaUp = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(0, 1)).rgb);
|
||||||
|
float lumaLeft = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(-1, 0)).rgb);
|
||||||
|
float lumaRight = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(1, 0)).rgb);
|
||||||
|
|
||||||
float dirReduce = max(
|
// Find the maximum and minimum luma around the current fragment.
|
||||||
(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
|
float lumaMin = min(lumaCenter, min(min(lumaDown, lumaUp), min(lumaLeft, lumaRight)));
|
||||||
FXAA_REDUCE_MIN);
|
float lumaMax = max(lumaCenter, max(max(lumaDown, lumaUp), max(lumaLeft, lumaRight)));
|
||||||
|
|
||||||
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
|
// Compute the delta.
|
||||||
|
float lumaRange = lumaMax - lumaMin;
|
||||||
|
|
||||||
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
|
// 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.
|
||||||
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
|
if (lumaRange > max(EDGE_THRESHOLD_MIN, lumaMax*EDGE_THRESHOLD_MAX)) {
|
||||||
dir * rcpDirMin)) / frameBufSize;
|
// Query the 4 remaining corners lumas.
|
||||||
|
float lumaDownLeft = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(-1, -1)).rgb);
|
||||||
|
float lumaUpRight = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(1, 1)).rgb);
|
||||||
|
float lumaUpLeft = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(-1, 1)).rgb);
|
||||||
|
float lumaDownRight = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(1, -1)).rgb);
|
||||||
|
|
||||||
vec3 rgbA = (1.0 / 2.0) * (
|
// Combine the four edges lumas (using intermediary variables for future computations with the same values).
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (1.0 / 3.0 - 0.5)).xyz +
|
float lumaDownUp = lumaDown + lumaUp;
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (2.0 / 3.0 - 0.5)).xyz);
|
float lumaLeftRight = lumaLeft + lumaRight;
|
||||||
vec3 rgbB = rgbA * (1.0 / 2.0) + (1.0 / 4.0) * (
|
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (0.0 / 3.0 - 0.5)).xyz +
|
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (3.0 / 3.0 - 0.5)).xyz);
|
|
||||||
float lumaB = dot(rgbB, luma);
|
|
||||||
|
|
||||||
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
|
// Same for corners
|
||||||
passPixelColor0.xyz = rgbA;
|
float lumaLeftCorners = lumaDownLeft + lumaUpLeft;
|
||||||
}
|
float lumaDownCorners = lumaDownLeft + lumaDownRight;
|
||||||
else {
|
float lumaRightCorners = lumaDownRight + lumaUpRight;
|
||||||
passPixelColor0.xyz = rgbB;
|
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);
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// Choose the step size (one pixel) according to the edge direction.
|
||||||
|
float stepLength = isHorizontal ? invFramebufferSize.y : invFramebufferSize.x;
|
||||||
|
|
||||||
|
// 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 = texCoords;
|
||||||
|
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(invFramebufferSize.x, 0.0) : vec2(0.0, invFramebufferSize.y);
|
||||||
|
// Compute UVs to explore on each side of the edge, orthogonally. The QUALITY allows us to step faster.
|
||||||
|
vec2 uv1 = currentUv - offset;
|
||||||
|
vec2 uv2 = currentUv + offset;
|
||||||
|
|
||||||
|
// Read the lumas at both current extremities of the exploration segment, and compute the delta wrt to the local average luma.
|
||||||
|
float lumaEnd1 = rgb2luma(texture(textureUnitPS0, uv1).rgb);
|
||||||
|
float lumaEnd2 = rgb2luma(texture(textureUnitPS0, uv2).rgb);
|
||||||
|
lumaEnd1 -= lumaLocalAverage;
|
||||||
|
lumaEnd2 -= lumaLocalAverage;
|
||||||
|
|
||||||
|
// If the luma deltas at the current extremities are 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;
|
||||||
|
}
|
||||||
|
if (!reached2) {
|
||||||
|
uv2 += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both sides have not been reached, continue to explore.
|
||||||
|
if (!reachedBoth) {
|
||||||
|
for (int i = 2; i < ITERATIONS; i++) {
|
||||||
|
// If needed, read luma in 1st direction, compute delta.
|
||||||
|
if (!reached1) {
|
||||||
|
lumaEnd1 = rgb2luma(texture(textureUnitPS0, uv1).rgb);
|
||||||
|
lumaEnd1 = lumaEnd1 - lumaLocalAverage;
|
||||||
|
}
|
||||||
|
// If needed, read luma in opposite direction, compute delta.
|
||||||
|
if (!reached2) {
|
||||||
|
lumaEnd2 = rgb2luma(texture(textureUnitPS0, uv2).rgb);
|
||||||
|
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 extremity of the edge.
|
||||||
|
float distance1 = isHorizontal ? (texCoords.x - uv1.x) : (texCoords.y - uv1.y);
|
||||||
|
float distance2 = isHorizontal ? (uv2.x - texCoords.x) : (uv2.y - texCoords.y);
|
||||||
|
|
||||||
|
// In which direction is the extremity of the edge closer ?
|
||||||
|
bool isDirection1 = distance1 < distance2;
|
||||||
|
float distanceFinal = min(distance1, distance2);
|
||||||
|
|
||||||
|
// Length of the edge.
|
||||||
|
float edgeThickness = (distance1 + distance2);
|
||||||
|
|
||||||
|
// UV offset: read in the direction of the closest side of the edge.
|
||||||
|
float pixelOffset = -distanceFinal / edgeThickness + 0.5;
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
// (in the direction of the closer side of the edge.)
|
||||||
|
bool correctVariation = ((isDirection1 ? lumaEnd1 : lumaEnd2) < 0.0) != isLumaCenterSmaller;
|
||||||
|
|
||||||
|
// 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 * SUBPIXEL_QUALITY;
|
||||||
|
|
||||||
|
// Pick the biggest of the two offsets.
|
||||||
|
finalOffset = max(finalOffset, subPixelOffsetFinal);
|
||||||
|
|
||||||
|
// Compute the final UV coordinates.
|
||||||
|
vec2 finalUv = texCoords;
|
||||||
|
if (isHorizontal) {
|
||||||
|
finalUv.y += finalOffset * stepLength;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
finalUv.x += finalOffset * stepLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the color at the new UV coordinates, and use it.
|
||||||
|
vec3 finalColor = texture(textureUnitPS0, finalUv).rgb;
|
||||||
|
passPixelColor0.rgb = finalColor;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
passPixelColor0.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void oldmain() {
|
|
||||||
passPixelColor0 = texture(textureUnitPS0, passParameterSem2.xy);
|
|
||||||
}
|
|
||||||
|
@ -2,8 +2,32 @@
|
|||||||
#extension GL_ARB_texture_gather : enable
|
#extension GL_ARB_texture_gather : enable
|
||||||
// shader f14bb57cd5c9cb77
|
// shader f14bb57cd5c9cb77
|
||||||
//replaces broken aa everywhere with fxaa
|
//replaces broken aa everywhere with fxaa
|
||||||
|
//also includes vibrance logic from Contrasty
|
||||||
//original shader dumped using cemu 1.9.1, BotW 1.3.1
|
//original shader dumped using cemu 1.9.1, BotW 1.3.1
|
||||||
//credit goes to https://gist.github.com/sakrist/7912905
|
//credit for fxaa implementation http://blog.simonrodriguez.fr/articles/30-07-2016_implementing_fxaa.html
|
||||||
|
//Credit to bestminr for vibrance logic
|
||||||
|
|
||||||
|
#define ENABLE_FXAA 1
|
||||||
|
#define ENABLE_CONTRASTY 0
|
||||||
|
|
||||||
|
const float EDGE_THRESHOLD_MIN = 0.04;
|
||||||
|
const float EDGE_THRESHOLD_MAX = 0.125;
|
||||||
|
const float SUBPIXEL_QUALITY = 0.5;
|
||||||
|
const float[] QUALITY = {1.5, 2.0, 2.0, 2.0, 2.0, 4.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0};
|
||||||
|
const int ITERATIONS = 12;
|
||||||
|
|
||||||
|
/*Gamma, exposure, vibrance and crushContrast can be modified */
|
||||||
|
const float gamma = 0.81; // 1.0 is neutral Botw is already colour graded at this stage
|
||||||
|
const float exposure = 1.17; // 1.0 is neutral
|
||||||
|
const float vibrance = 0.008; // 0.0 is neutral
|
||||||
|
const float crushContrast = 0.004; // 0.0 is neutral. Use small increments, loss of shadow detail
|
||||||
|
|
||||||
|
//Uncomment below and in body to scale 16-235 not recommended */
|
||||||
|
/*
|
||||||
|
const float floor = 16.0 / 255;
|
||||||
|
const float scale = 255.0/(235.0-16.0);
|
||||||
|
*/
|
||||||
|
|
||||||
uniform ivec4 uf_remappedPS[4];
|
uniform ivec4 uf_remappedPS[4];
|
||||||
layout(binding = 0) uniform sampler2D textureUnitPS0;// Tex0 addr 0xf4713800 res 1280x720x1 dim 1 tm: 4 format 0019 compSel: 0 1 2 3 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler0 ClampX/Y/Z: 2 2 2 border: 1
|
layout(binding = 0) uniform sampler2D textureUnitPS0;// Tex0 addr 0xf4713800 res 1280x720x1 dim 1 tm: 4 format 0019 compSel: 0 1 2 3 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler0 ClampX/Y/Z: 2 2 2 border: 1
|
||||||
layout(binding = 1) uniform sampler2D textureUnitPS1;// Tex1 addr 0x387f8000 res 1280x720x1 dim 1 tm: 4 format 0001 compSel: 0 4 4 5 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler1 ClampX/Y/Z: 2 2 2 border: 1
|
layout(binding = 1) uniform sampler2D textureUnitPS1;// Tex1 addr 0x387f8000 res 1280x720x1 dim 1 tm: 4 format 0001 compSel: 0 4 4 5 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler1 ClampX/Y/Z: 2 2 2 border: 1
|
||||||
@ -11,56 +35,220 @@ layout(location = 0) in vec4 passParameterSem2;
|
|||||||
layout(location = 0) out vec4 passPixelColor0;
|
layout(location = 0) out vec4 passPixelColor0;
|
||||||
uniform vec2 uf_fragCoordScale;
|
uniform vec2 uf_fragCoordScale;
|
||||||
|
|
||||||
const float FXAA_SPAN_MAX = 8.0;
|
float rgb2luma(vec3 rgb) {
|
||||||
const float FXAA_REDUCE_MUL = 1.0 / 8.0;
|
return sqrt(dot(rgb, vec3(0.299, 0.587, 0.114)));
|
||||||
const float FXAA_REDUCE_MIN = 1.0 / 128.0;
|
}
|
||||||
const ivec2 res = textureSize(textureUnitPS0,0);
|
|
||||||
const vec2 frameBufSize = vec2( float(res.x), float(res.y) );
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec2 texCoords = passParameterSem2.xy;
|
vec2 texCoords = passParameterSem2.xy;
|
||||||
vec3 rgbNW = texture2D(textureUnitPS0, texCoords + (vec2(-1.0, -1.0) / frameBufSize)).xyz;
|
vec3 colorCenter = texture(textureUnitPS0, texCoords).rgb;
|
||||||
vec3 rgbNE = texture2D(textureUnitPS0, texCoords + (vec2(1.0, -1.0) / frameBufSize)).xyz;
|
passPixelColor0.rgb = colorCenter;
|
||||||
vec3 rgbSW = texture2D(textureUnitPS0, texCoords + (vec2(-1.0, 1.0) / frameBufSize)).xyz;
|
|
||||||
vec3 rgbSE = texture2D(textureUnitPS0, texCoords + (vec2(1.0, 1.0) / frameBufSize)).xyz;
|
|
||||||
vec3 rgbM = texture2D(textureUnitPS0, texCoords).xyz;
|
|
||||||
|
|
||||||
vec3 luma = vec3(0.299, 0.587, 0.114);
|
#if (ENABLE_FXAA == 1)
|
||||||
float lumaNW = dot(rgbNW, luma);
|
ivec2 texSize = textureSize(textureUnitPS0, 0);
|
||||||
float lumaNE = dot(rgbNE, luma);
|
vec2 framebufferSize = vec2(float(texSize.x), float(texSize.y));
|
||||||
float lumaSW = dot(rgbSW, luma);
|
vec2 invFramebufferSize = vec2(1.0 / framebufferSize.x, 1.0 / framebufferSize.y);
|
||||||
float lumaSE = dot(rgbSE, luma);
|
|
||||||
float lumaM = dot(rgbM, luma);
|
|
||||||
|
|
||||||
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
|
// Luma at the current fragment
|
||||||
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
|
float lumaCenter = rgb2luma(colorCenter);
|
||||||
|
|
||||||
vec2 dir;
|
// Luma at the four direct neighbours of the current fragment.
|
||||||
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
|
float lumaDown = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(0, -1)).rgb);
|
||||||
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
|
float lumaUp = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(0, 1)).rgb);
|
||||||
|
float lumaLeft = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(-1, 0)).rgb);
|
||||||
|
float lumaRight = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(1, 0)).rgb);
|
||||||
|
|
||||||
float dirReduce = max(
|
// Find the maximum and minimum luma around the current fragment.
|
||||||
(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
|
float lumaMin = min(lumaCenter, min(min(lumaDown, lumaUp), min(lumaLeft, lumaRight)));
|
||||||
FXAA_REDUCE_MIN);
|
float lumaMax = max(lumaCenter, max(max(lumaDown, lumaUp), max(lumaLeft, lumaRight)));
|
||||||
|
|
||||||
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
|
// Compute the delta.
|
||||||
|
float lumaRange = lumaMax - lumaMin;
|
||||||
|
|
||||||
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
|
// 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.
|
||||||
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
|
if (lumaRange > max(EDGE_THRESHOLD_MIN, lumaMax*EDGE_THRESHOLD_MAX)) {
|
||||||
dir * rcpDirMin)) / frameBufSize;
|
// Query the 4 remaining corners lumas.
|
||||||
|
float lumaDownLeft = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(-1, -1)).rgb);
|
||||||
|
float lumaUpRight = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(1, 1)).rgb);
|
||||||
|
float lumaUpLeft = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(-1, 1)).rgb);
|
||||||
|
float lumaDownRight = rgb2luma(textureOffset(textureUnitPS0, texCoords, ivec2(1, -1)).rgb);
|
||||||
|
|
||||||
vec3 rgbA = (1.0 / 2.0) * (
|
// Combine the four edges lumas (using intermediary variables for future computations with the same values).
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (1.0 / 3.0 - 0.5)).xyz +
|
float lumaDownUp = lumaDown + lumaUp;
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (2.0 / 3.0 - 0.5)).xyz);
|
float lumaLeftRight = lumaLeft + lumaRight;
|
||||||
vec3 rgbB = rgbA * (1.0 / 2.0) + (1.0 / 4.0) * (
|
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (0.0 / 3.0 - 0.5)).xyz +
|
|
||||||
texture2D(textureUnitPS0, texCoords.xy + dir * (3.0 / 3.0 - 0.5)).xyz);
|
|
||||||
float lumaB = dot(rgbB, luma);
|
|
||||||
|
|
||||||
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
|
// Same for corners
|
||||||
passPixelColor0.xyz = rgbA;
|
float lumaLeftCorners = lumaDownLeft + lumaUpLeft;
|
||||||
}
|
float lumaDownCorners = lumaDownLeft + lumaDownRight;
|
||||||
else {
|
float lumaRightCorners = lumaDownRight + lumaUpRight;
|
||||||
passPixelColor0.xyz = rgbB;
|
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);
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// Choose the step size (one pixel) according to the edge direction.
|
||||||
|
float stepLength = isHorizontal ? invFramebufferSize.y : invFramebufferSize.x;
|
||||||
|
|
||||||
|
// 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 = texCoords;
|
||||||
|
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(invFramebufferSize.x, 0.0) : vec2(0.0, invFramebufferSize.y);
|
||||||
|
// Compute UVs to explore on each side of the edge, orthogonally. The QUALITY allows us to step faster.
|
||||||
|
vec2 uv1 = currentUv - offset;
|
||||||
|
vec2 uv2 = currentUv + offset;
|
||||||
|
|
||||||
|
// Read the lumas at both current extremities of the exploration segment, and compute the delta wrt to the local average luma.
|
||||||
|
float lumaEnd1 = rgb2luma(texture(textureUnitPS0, uv1).rgb);
|
||||||
|
float lumaEnd2 = rgb2luma(texture(textureUnitPS0, uv2).rgb);
|
||||||
|
lumaEnd1 -= lumaLocalAverage;
|
||||||
|
lumaEnd2 -= lumaLocalAverage;
|
||||||
|
|
||||||
|
// If the luma deltas at the current extremities are 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;
|
||||||
|
}
|
||||||
|
if (!reached2) {
|
||||||
|
uv2 += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both sides have not been reached, continue to explore.
|
||||||
|
if (!reachedBoth) {
|
||||||
|
for (int i = 2; i < ITERATIONS; i++) {
|
||||||
|
// If needed, read luma in 1st direction, compute delta.
|
||||||
|
if (!reached1) {
|
||||||
|
lumaEnd1 = rgb2luma(texture(textureUnitPS0, uv1).rgb);
|
||||||
|
lumaEnd1 = lumaEnd1 - lumaLocalAverage;
|
||||||
|
}
|
||||||
|
// If needed, read luma in opposite direction, compute delta.
|
||||||
|
if (!reached2) {
|
||||||
|
lumaEnd2 = rgb2luma(texture(textureUnitPS0, uv2).rgb);
|
||||||
|
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 extremity of the edge.
|
||||||
|
float distance1 = isHorizontal ? (texCoords.x - uv1.x) : (texCoords.y - uv1.y);
|
||||||
|
float distance2 = isHorizontal ? (uv2.x - texCoords.x) : (uv2.y - texCoords.y);
|
||||||
|
|
||||||
|
// In which direction is the extremity of the edge closer ?
|
||||||
|
bool isDirection1 = distance1 < distance2;
|
||||||
|
float distanceFinal = min(distance1, distance2);
|
||||||
|
|
||||||
|
// Length of the edge.
|
||||||
|
float edgeThickness = (distance1 + distance2);
|
||||||
|
|
||||||
|
// UV offset: read in the direction of the closest side of the edge.
|
||||||
|
float pixelOffset = -distanceFinal / edgeThickness + 0.5;
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
// (in the direction of the closer side of the edge.)
|
||||||
|
bool correctVariation = ((isDirection1 ? lumaEnd1 : lumaEnd2) < 0.0) != isLumaCenterSmaller;
|
||||||
|
|
||||||
|
// 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 * SUBPIXEL_QUALITY;
|
||||||
|
|
||||||
|
// Pick the biggest of the two offsets.
|
||||||
|
finalOffset = max(finalOffset, subPixelOffsetFinal);
|
||||||
|
|
||||||
|
// Compute the final UV coordinates.
|
||||||
|
vec2 finalUv = texCoords;
|
||||||
|
if (isHorizontal) {
|
||||||
|
finalUv.y += finalOffset * stepLength;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
finalUv.x += finalOffset * stepLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the color at the new UV coordinates, and use it.
|
||||||
|
vec3 finalColor = texture(textureUnitPS0, finalUv).rgb;
|
||||||
|
passPixelColor0.rgb = finalColor;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (ENABLE_CONTRASTY == 1)
|
||||||
|
vec3 fColour = (passPixelColor0.xyz);
|
||||||
|
fColour = max(vec3(0.0), fColour - vec3(crushContrast));
|
||||||
|
fColour = clamp(exposure * fColour, 0.0, 1.0);
|
||||||
|
fColour = pow(fColour, vec3(1.0 / gamma));
|
||||||
|
float luminance = fColour.r*0.299 + fColour.g*0.587 + fColour.b*0.114;
|
||||||
|
float mn = min(min(fColour.r, fColour.g), fColour.b);
|
||||||
|
float mx = max(max(fColour.r, fColour.g), fColour.b);
|
||||||
|
float sat = (1.0-(mx - mn)) * (1.0-mx) * luminance * 5.0;
|
||||||
|
vec3 lightness = vec3((mn + mx)/2.0);
|
||||||
|
// vibrance
|
||||||
|
fColour = mix(fColour, mix(fColour, lightness, -vibrance), sat);
|
||||||
|
//vec3 fColour = (fColour.xyz - floor) * scale; // Not recommended 0-255->16-235..
|
||||||
|
passPixelColor0 = vec4(fColour.x, fColour.y, fColour.z, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
passPixelColor0.a = 1.0;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user