134 lines
4.9 KiB
GLSL
134 lines
4.9 KiB
GLSL
/*
|
|
Copyright (c) 2017 yvt
|
|
|
|
This file is part of OpenSpades.
|
|
|
|
OpenSpades is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OpenSpades is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
uniform sampler2D inputTexture;
|
|
uniform sampler2D depthTexture;
|
|
uniform sampler2D previousTexture;
|
|
uniform sampler2D processedInputTexture;
|
|
uniform vec2 inverseVP;
|
|
uniform mat4 reprojectionMatrix;
|
|
|
|
varying vec2 texCoord;
|
|
/* UE4-style temporal AA. Implementation is based on my ShaderToy submission */
|
|
|
|
// YUV-RGB conversion routine from Hyper3D
|
|
vec3 encodePalYuv(vec3 rgb)
|
|
{
|
|
return vec3(
|
|
dot(rgb, vec3(0.299, 0.587, 0.114)),
|
|
dot(rgb, vec3(-0.14713, -0.28886, 0.436)),
|
|
dot(rgb, vec3(0.615, -0.51499, -0.10001))
|
|
);
|
|
}
|
|
|
|
vec3 decodePalYuv(vec3 yuv)
|
|
{
|
|
return vec3(
|
|
dot(yuv, vec3(1., 0., 1.13983)),
|
|
dot(yuv, vec3(1., -0.39465, -0.58060)),
|
|
dot(yuv, vec3(1., 2.03211, 0.))
|
|
);
|
|
}
|
|
|
|
|
|
void main() {
|
|
// ------------------------------------------------------------------------
|
|
// Reprojection
|
|
//
|
|
// Calulate the Z position of the current pixel. Take the minimum Z value
|
|
// of the neighboring pixels to preserve the antialiasing of foreground
|
|
// objects.
|
|
vec2 off = inverseVP;
|
|
float inputZ0 = texture2D(depthTexture, texCoord).x;
|
|
float inputZ1 = texture2D(depthTexture, texCoord + vec2(+off.x, 0.0)).x;
|
|
float inputZ2 = texture2D(depthTexture, texCoord + vec2(-off.x, 0.0)).x;
|
|
float inputZ3 = texture2D(depthTexture, texCoord + vec2(0.0, +off.y)).x;
|
|
float inputZ4 = texture2D(depthTexture, texCoord + vec2(0.0, -off.y)).x;
|
|
float inputZ5 = texture2D(depthTexture, texCoord + vec2(+off.x, +off.y)).x;
|
|
float inputZ6 = texture2D(depthTexture, texCoord + vec2(-off.x, +off.y)).x;
|
|
float inputZ7 = texture2D(depthTexture, texCoord + vec2(+off.x, -off.y)).x;
|
|
float inputZ8 = texture2D(depthTexture, texCoord + vec2(-off.x, -off.y)).x;
|
|
float inputZ = min(min(min(inputZ0, inputZ1), min(inputZ2, inputZ3)),
|
|
min(min(inputZ4, inputZ5), min(inputZ6, min(inputZ7, inputZ8))));
|
|
|
|
// Predict where the point was in the previous frame. The Z range [0, 0.1]
|
|
// is for a view weapon, so assume no movement in this range.
|
|
vec4 reprojectedTexCoord;
|
|
if (inputZ < 0.1) {
|
|
reprojectedTexCoord.xy = texCoord.xy;
|
|
} else {
|
|
reprojectedTexCoord = reprojectionMatrix * vec4(texCoord, inputZ, 1.0);
|
|
reprojectedTexCoord.xy /= reprojectedTexCoord.w;
|
|
}
|
|
|
|
vec4 lastColor = texture2D(previousTexture, reprojectedTexCoord.xy);
|
|
|
|
// ------------------------------------------------------------------------
|
|
vec3 antialiased = lastColor.xyz;
|
|
float mixRate = min(lastColor.w, 0.5);
|
|
|
|
vec3 in0 = texture2D(processedInputTexture, texCoord).xyz;
|
|
|
|
antialiased = mix(antialiased, in0, mixRate);
|
|
|
|
vec3 in1 = texture2D(inputTexture, texCoord + vec2(+off.x, 0.0)).xyz;
|
|
vec3 in2 = texture2D(inputTexture, texCoord + vec2(-off.x, 0.0)).xyz;
|
|
vec3 in3 = texture2D(inputTexture, texCoord + vec2(0.0, +off.y)).xyz;
|
|
vec3 in4 = texture2D(inputTexture, texCoord + vec2(0.0, -off.y)).xyz;
|
|
vec3 in5 = texture2D(inputTexture, texCoord + vec2(+off.x, +off.y)).xyz;
|
|
vec3 in6 = texture2D(inputTexture, texCoord + vec2(-off.x, +off.y)).xyz;
|
|
vec3 in7 = texture2D(inputTexture, texCoord + vec2(+off.x, -off.y)).xyz;
|
|
vec3 in8 = texture2D(inputTexture, texCoord + vec2(-off.x, -off.y)).xyz;
|
|
|
|
antialiased = encodePalYuv(antialiased);
|
|
in0 = encodePalYuv(in0);
|
|
in1 = encodePalYuv(in1);
|
|
in2 = encodePalYuv(in2);
|
|
in3 = encodePalYuv(in3);
|
|
in4 = encodePalYuv(in4);
|
|
in5 = encodePalYuv(in5);
|
|
in6 = encodePalYuv(in6);
|
|
in7 = encodePalYuv(in7);
|
|
in8 = encodePalYuv(in8);
|
|
|
|
vec3 minColor = min(min(min(in0, in1), min(in2, in3)), in4);
|
|
vec3 maxColor = max(max(max(in0, in1), max(in2, in3)), in4);
|
|
minColor = mix(minColor,
|
|
min(min(min(in5, in6), min(in7, in8)), minColor), 0.5);
|
|
maxColor = mix(maxColor,
|
|
max(max(max(in5, in6), max(in7, in8)), maxColor), 0.5);
|
|
|
|
vec3 preclamping = antialiased;
|
|
antialiased = clamp(antialiased, minColor, maxColor);
|
|
|
|
mixRate = 1.0 / (1.0 / mixRate + 1.0);
|
|
|
|
vec3 diff = abs(antialiased - preclamping);
|
|
float clampAmount = max(max(diff.x, diff.y), diff.z);
|
|
|
|
mixRate += clampAmount * 8.0;
|
|
mixRate = clamp(mixRate, 0.05, 0.5);
|
|
|
|
antialiased = decodePalYuv(antialiased);
|
|
|
|
gl_FragColor = vec4(max(antialiased, vec3(0.0)), mixRate);
|
|
}
|