#include "../shaderenv.h" struct fragment { // normalized screen position float4 pos: WPOS; float2 texCoord: TEXCOORD0; float3 view: TEXCOORD1; }; struct pixel { float4 color: COLOR0; float3 normal: COLOR1; float3 diffVal: COLOR2; }; float2 myreflect(float2 pt, float2 n) { // distance to plane float d = dot(n, pt); // reflect around plane float2 rpt = pt - d * 2.0f * n; return rpt; } /** function for standard deferred shading */ float4 shade(fragment IN, uniform float4 color, uniform float3 normal, float3 lightDir) { // diffuse intensity const float angle = saturate(dot(normal, lightDir)); float4 lightDiffuse = glstate.light[0].diffuse; float4 diffuse = angle * lightDiffuse; // global ambient const float4 ambient = glstate.light[0].ambient; float4 outColor; // hack: prevent shading the sky if (color.w > 1e19f) outColor = color; else outColor = (ambient + diffuse) * color; return outColor; } /** The mrt shader for standard rendering */ pixel main(fragment IN, uniform sampler2D colors, uniform sampler2D normals, uniform float3 lightDir ) { pixel OUT; float4 norm = tex2D(normals, IN.texCoord); float4 color = tex2Dlod(colors, float4(IN.texCoord, 0, 0)); float3 normal = normalize(norm.xyz); float4 col = shade(IN, color, normal, lightDir); OUT.color = col; // store scaled view vector so wie don't have to normalize for e.g., ssao OUT.color.w = color.w;// / length(IN.view); //OUT.color = color; return OUT; } float CalcShadowTerm(fragment IN, uniform sampler2D shadowMap, uniform float scale, uniform float2 lightSpacePos, uniform float depth, uniform float2 samples[NUM_PCF_TABS], uniform float weights[NUM_PCF_TABS], uniform sampler2D noiseTexture ) { //float shadowDepth = tex2D(shadowMap, lightSpacePos).x; //return step(depth, shadowDepth); float total_d = .0f; float total_w = .0f; for (int i = 0; i < NUM_PCF_TABS; ++ i) { const float2 offset = samples[i]; const float w = weights[i]; #if 1 //////////////////// //-- add random noise: reflect around random normal vector (warning: slow!) float2 mynoise = tex2D(noiseTexture, IN.texCoord).xy; const float2 offsetTransformed = myreflect(offset, mynoise); #else const float2 offsetTransformed = offset; #endif // weight with projected coordinate to reach similar kernel size for near and far float2 texcoord = lightSpacePos + offsetTransformed * scale; float shadowDepth = tex2D(shadowMap, texcoord).x; total_d += w * step(depth, shadowDepth); total_w += w; } total_d /= (float)total_w; return total_d; } inline float3 Interpol(float2 w, float3 bl, float3 br, float3 tl, float3 tr) { float3 x1 = lerp(bl, tl, w.y); float3 x2 = lerp(br, tr, w.y); float3 v = lerp(x1, x2, w.x); return v; } pixel main_shadow(fragment IN, uniform sampler2D colors, uniform sampler2D positions, uniform sampler2D normals, uniform sampler2D shadowMap, uniform float4x4 shadowMatrix, uniform float sampleWidth, uniform sampler2D noiseTex, uniform float2 samples[NUM_PCF_TABS], uniform float weights[NUM_PCF_TABS], uniform float3 lightDir, uniform float3 eyePos, uniform float3 bl, uniform float3 br, uniform float3 tl, uniform float3 tr ) { pixel OUT; const float3 normal = tex2D(normals, IN.texCoord.xy); float4 color = tex2Dlod(colors, float4(IN.texCoord, 0, 0)); /// reconstruct position from the eye space depth float3 viewDir = IN.view; const float lenView = length(viewDir); viewDir /= lenView; const float eyeDepth = tex2Dlod(colors, float4(IN.texCoord, 0, 0)).w; const float4 worldPos = float4(eyePos - viewDir * eyeDepth, 1); // diffuse intensity const float angle = saturate(dot(normal, lightDir)); const float4 lightDiffuse = glstate.light[0].diffuse; float4 diffuse = lightDiffuse * angle; // hack: prevent shadowing the sky const bool useShading = (color.w < 1e19f); // calc diffuse illumination + shadow term if (useShading && (angle > 1e-3f) // shadow only if diffuse color has some minimum intensity ) { float4 lightSpacePos = mul(shadowMatrix, worldPos); lightSpacePos /= lightSpacePos.w; float shadowTerm = CalcShadowTerm(IN, shadowMap, sampleWidth, lightSpacePos.xy, lightSpacePos.z, samples, weights, noiseTex); diffuse *= shadowTerm; } // light ambient term const float4 ambient = glstate.light[0].ambient; // compute shading OUT.color = useShading ? (ambient + diffuse) * color : color; // store scaled view vector from now on so wie don't have to normalize later (e.g., for ssao) //OUT.color.w = color.w / lenView; return OUT; } float4 Output(fragment IN, uniform sampler2D colors): COLOR { return tex2Dlod(colors, float4(IN.texCoord, 0, 0)); } float4 ScaleDepth(fragment IN, uniform sampler2D colors): COLOR { float4 color = tex2Dlod(colors, float4(IN.texCoord, 0, 0)); // store scaled view vector so wie don't have to normalize for e.g., ssao color.w /= length(IN.view); return color; } inline float SqrLen(float3 v) { return v.x * v.x + v.y * v.y + v.z * v.z; } /** This shader computes the reprojection and checks if the reprojected pixel from last frame is still valid in the current frame */ inline float PixelValid(sampler2D oldTex, float4 color, float3 diffVec, float2 texCoord, float3 viewDir, float3 oldEyePos, float4x4 modelViewProj, float4x4 oldModelViewProj, float3 oldbl, float3 oldbr, float3 oldtl, float3 oldtr ) { // reconstruct position from the eye space depth const float eyeSpaceDepth = color.w; const float4 worldPos = float4(-viewDir * eyeSpaceDepth, 1.0f); //////////////// //-- calculcate the current projected posiion (also used for next frame) float4 projPos = mul(modelViewProj, worldPos); const float invw = 1.0f / projPos.w; projPos *= invw; // compute position from old frame for dynamic objects + translational portion const float3 translatedPos = diffVec - oldEyePos + worldPos.xyz; ///////////////// //-- reproject into old frame and calculate texture position of sample in old frame // note: the old model view matrix only holds the view orientation part float4 backProjPos = mul(oldModelViewProj, float4(translatedPos, 1.0f)); backProjPos /= backProjPos.w; // fit from unit cube into 0 .. 1 const float2 oldTexCoords = backProjPos.xy * 0.5f + 0.5f; //const float2 oldTexCoords = texCoord; // retrieve the sample from the last frame const float4 oldPixel = tex2Dlod(oldTex, float4(oldTexCoords, .0f, .0f)); // calculate eye space position of sample in old frame const float oldEyeSpaceDepth = oldPixel.w; // vector from eye pos to old sample const float3 oldViewDir = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr); const float invLen = 1.0f / length(oldViewDir); const float projectedEyeSpaceDepth = invLen * length(translatedPos); const float depthDif = abs(1.0f - oldEyeSpaceDepth / projectedEyeSpaceDepth); const float squaredLen = SqrLen(diffVec); // test if this pixel was not valid in the old frame float validPixel; if ((((squaredLen <= DYNAMIC_OBJECTS_THRESHOLD) && (oldPixel.z <= DYNAMIC_OBJECTS_THRESHOLD)) || (depthDif <= MIN_DEPTH_DIFF)) && (oldTexCoords.x >= 0.0f) && (oldTexCoords.x < 1.0f) && (oldTexCoords.y >= 0.0f) && (oldTexCoords.y < 1.0f) ) { validPixel = 0.0f; } else { validPixel = 10.5f; } //return depthDif; return validPixel; } pixel PrepareSsao(fragment IN, uniform sampler2D colorsTex, uniform sampler2D normalsTex, uniform sampler2D diffVals, uniform sampler2D oldTex, uniform float4x4 modelViewProj, uniform float4x4 oldModelViewProj, uniform float3 oldbl, uniform float3 oldbr, uniform float3 oldtl, uniform float3 oldtr, uniform float3 oldEyePos ) { pixel pix; const float3 normal = normalize(tex2Dlod(normalsTex, float4(IN.texCoord, 0 ,0)).xyz); const float3 difVec = tex2Dlod(diffVals, float4(IN.texCoord, 0 ,0)).xyz; const float3 viewDir = IN.view; float4 color = tex2Dlod(colorsTex, float4(IN.texCoord, 0, 0)); // store scaled view vector so wie don't have to normalize for e.g., ssao color.w /= length(IN.view); //color.w = 1; // do reprojection and filter out the pixels that are not save float pValid = PixelValid( oldTex, color, difVec.xyz, IN.texCoord, viewDir, oldEyePos, modelViewProj, oldModelViewProj, oldbl, oldbr, oldtl, oldtr ); pix.color = color; pix.color.x = pValid; pix.normal = normal; pix.diffVal = difVec; return pix; } float4 DownSample(fragment IN, uniform sampler2D colors, uniform float2 downSampleOffs[NUM_DOWNSAMPLES]): COLOR { // let bilinear filtering do its work float4 color = tex2Dlod(colors, float4(IN.texCoord, 0, 0)); return color; }