/***************************************************************************** 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/) ******************************************************************************/ // transforms homogeneous 3D position according to MVP matrices (for vertex shaders) // note: you must use this exact code, otherwise you'll get depth fighting due to numeric differences! vec4 objectPosToClip(vec4 position, mat4 modelView, mat4 projection) { return projection * (modelView * position); } // transforms 3D position from world space to object/model space using inverse model transform vec3 worldPosToObject(vec3 worldPosition, mat4 modelMatrix) { return (worldPosition - vec3(modelMatrix[3])) * mat3(modelMatrix); } // returns view Z coordinate with reversed sign (monotonically increasing with depth) // in other words, it is eye-fragment distance along view direction float depthToZ(mat4 projectionMatrix, float depth) { float clipZ = 2.0 * depth - 1.0; float A = projectionMatrix[2].z; float B = projectionMatrix[3].z; // note: D3 uses nonstandard far-at-infinity projection matrix (see R_SetupProjection) // it means that d > 0.999 is invalid range // the clamping to -eps from below ensures that such depth (e.g. depth = 1) produce large distance // (according to R_SetupProjection, eps = 1e-5 gives distance ~= 6e+5) return B / min(A + clipZ, -1e-5); } // samples depth texture and returns negated view Z with derivatives // tcDelta should equal inverse resolution of depth texture (sampling distance) // Zderivs is mathematically equivalent to (dFdx(return), dFdy(return)) if depth and render resolutions are equal // but this function returns good values even for texels on discontinuity edge float sampleZWithDerivs(sampler2D depthTexture, mat4 projectionMatrix, vec2 tcPoint, vec2 tcDelta, out vec2 Zderivs) { // set cross pattern vec2 tcMoreX = tcPoint + vec2(tcDelta.x, 0); vec2 tcLessX = tcPoint - vec2(tcDelta.x, 0); vec2 tcMoreY = tcPoint + vec2(0, tcDelta.y); vec2 tcLessY = tcPoint - vec2(0, tcDelta.y); // evaluate all samples float valueCenter = depthToZ(projectionMatrix, texture(depthTexture, tcPoint).r); float valueMoreX = depthToZ(projectionMatrix, texture(depthTexture, tcMoreX).r); float valueLessX = depthToZ(projectionMatrix, texture(depthTexture, tcLessX).r); float valueMoreY = depthToZ(projectionMatrix, texture(depthTexture, tcMoreY).r); float valueLessY = depthToZ(projectionMatrix, texture(depthTexture, tcLessY).r); // set infinite values for texcoords outside [0..1] if (tcMoreX.x > 1) valueMoreX = 1e+20; if (tcLessX.x < 0) valueLessX = 1e+20; if (tcMoreY.x > 1) valueMoreY = 1e+20; if (tcLessY.x < 0) valueLessY = 1e+20; // compute all finite differences float derivMoreX = valueMoreX - valueCenter; float derivLessX = -(valueLessX - valueCenter); float derivMoreY = valueMoreY - valueCenter; float derivLessY = -(valueLessY - valueCenter); // among two differences, choose one with smaller magnitude Zderivs.x = (abs(derivLessX) < abs(derivMoreX) ? derivLessX : derivMoreX); Zderivs.y = (abs(derivLessY) < abs(derivMoreY) ? derivLessY : derivMoreY); return valueCenter; }