/***************************************************************************** The Dark Mod GPL Source Code This file is part of the The Dark Mod Source Code, originally based on the Doom 3 GPL Source Code as published in 2011. The Dark Mod Source Code 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. For details, see LICENSE.TXT. Project: The Dark Mod (http://www.thedarkmod.com/) ******************************************************************************/ #version 330 #pragma tdm_include "tdm_utils.glsl" #pragma tdm_include "tdm_transform.glsl" #pragma tdm_include "volumetric_common.glsl" out vec4 FragColor; uniform sampler2D u_resultTexture; uniform sampler2D u_depthTexture; uniform vec2 u_invDestResolution; uniform vec2 u_subpixelShift; uniform bool u_upsampling; vec2 invSrcResolution; vec2 texelToTc(ivec2 texel) { // converts texel index to texcoord on source texture return (texel + vec2(0.5)) * invSrcResolution; } void main() { vec2 thisTC = gl_FragCoord.xy * u_invDestResolution; if (u_upsampling) { // depth-aware upsampling invSrcResolution = vec2(1) / vec2(textureSize(u_resultTexture, 0)); vec2 factor = textureSize(u_resultTexture, 0) * u_invDestResolution; // canonical view Z we'll compare with vec2 distDerivs; float thisDist = sampleZWithDerivs(u_depthTexture, u_projectionMatrix, thisTC, u_invDestResolution, distDerivs); // since we render backfaces, set tangent plane as upper limit for view distance float exitDist = depthToZ(u_projectionMatrix, gl_FragCoord.z); vec2 exitDerivs = vec2(dFdx(exitDist), dFdy(exitDist)); // find low-resolution pixel/blocks: nearest and right-bottom ones vec2 lowBlock = gl_FragCoord.xy * factor; ivec2 nearestBlock = ivec2(lowBlock); ivec2 rightBlock = ivec2(lowBlock + vec2(0.5)); vec2 rightWeight = lowBlock + vec2(0.5) - rightBlock; // sample color and depth in nearest 4 blocks for custom bilinear filtering vec2 tc11 = texelToTc(rightBlock + ivec2(0, 0)); vec2 tc01 = texelToTc(rightBlock + ivec2(-1, 0)); vec2 tc10 = texelToTc(rightBlock + ivec2(0, -1)); vec2 tc00 = texelToTc(rightBlock + ivec2(-1, -1)); vec4 color11 = texture(u_resultTexture, tc11); vec4 color01 = texture(u_resultTexture, tc01); vec4 color10 = texture(u_resultTexture, tc10); vec4 color00 = texture(u_resultTexture, tc00); float dist11 = depthToZ(u_projectionMatrix, texture(u_depthTexture, tc11 + u_subpixelShift).r); float dist01 = depthToZ(u_projectionMatrix, texture(u_depthTexture, tc01 + u_subpixelShift).r); float dist10 = depthToZ(u_projectionMatrix, texture(u_depthTexture, tc10 + u_subpixelShift).r); float dist00 = depthToZ(u_projectionMatrix, texture(u_depthTexture, tc00 + u_subpixelShift).r); float weight11 = rightWeight.x * rightWeight.y * depthDifferenceWeight(thisDist, dist11, thisTC, tc11, distDerivs, exitDist, exitDerivs); float weight01 = (1-rightWeight.x) * rightWeight.y * depthDifferenceWeight(thisDist, dist01, thisTC, tc01, distDerivs, exitDist, exitDerivs); float weight10 = rightWeight.x * (1-rightWeight.y) * depthDifferenceWeight(thisDist, dist10, thisTC, tc10, distDerivs, exitDist, exitDerivs); float weight00 = (1-rightWeight.x) * (1-rightWeight.y) * depthDifferenceWeight(thisDist, dist00, thisTC, tc00, distDerivs, exitDist, exitDerivs); // compute weighted sum (depth-aware bilinear filtering) float weightSum = weight00 + weight01 + weight10 + weight11; vec4 colorSum = weight11 * color11 + weight01 * color01 + weight10 * color10 + weight00 * color00; // find color of nearest block vec4 colorNearest = texture(u_resultTexture, texelToTc(nearestBlock)); // since weightSum can be low (even zero), lerp between bilinear average and nearest color FragColor = mix(colorNearest, colorSum / max(weightSum, 1e-3), smoothstep(0.03, 0.1, weightSum)); } else { FragColor = texture(u_resultTexture, thisTC); } }