#include "../shaderenv.h" struct frag { // normalized screen position float2 texCoord: TEXCOORD0; float2 lt: TEXCOORD1; // left top float2 rb: TEXCOORD2; // right bottom float2 rt: TEXCOORD3; // right top float2 lb: TEXCOORD4; // left bottom }; struct pixel { float4 col: COLOR0; }; /** Does the first downsampling step and on the same time calculates the intensity. */ float4 GreyScaleDownSample(frag IN, uniform sampler2D colors, uniform float2 downSampleOffs[4] ): COLOR { // Compute the average of the 4 necessary samples float average = .0f; float maximum = .0f; // the rgb-to-luminance weightings const float3 w = float3(0.299f, 0.587f, 0.114f); //const float3 w = float3(0.2125f, 0.7154f, 0.0721f); float4 color; for (int i = 0; i < 4; ++ i) { color = tex2D(colors, downSampleOffs[i]); const float intensity = dot(cols[i].rgb, w); maximum = max(maximum, intensity); average += log(1e-5f + intensity); } average *= 0.25f; // Output the luminance to the render target return float4(average, maximum, 0.0f, 1.0f); } /** Used for downsampling the tone map parameters (average loglum, maximum) to the next lower level. This has to be applied until there is only a 1x1 texture which holds the required numbers. */ float4 DownSampleForToneMapping(frag IN, uniform sampler2D colors, uniform float2 downSampleOffs[4]): COLOR { float average = .0f; float maximum = .0f; float4 color; for (int i = 0; i < 4; ++ i) { color = tex2D(colors, downSampleOffs[i]); maximum = max(maximum, color.y); average += color.x; } average *= 1.0f / (float)NUM_DOWNSAMPLES; return float4(average, maximum, 0.0f, 1.0f); } pixel ToneMap(frag IN, uniform sampler2D colors, uniform float imageKey, uniform float whiteLum, uniform float middleGrey) { pixel OUT; float4 color = tex2D(colors, IN.texCoord); const float pixLum = 0.2125f * color.x + 0.7154f * color.y + 0.0721f * color.z; // obtain new image key from highest mipmap level float logLumScaled = tex2Dlod(colors, float4(.5f, .5f, 0, MAX_LOD_LEVEL)).w; float logLum = logLumScaled * LOGLUM_RANGE + MINLOGLUM; float newImageKey = max(exp(logLum), 1e-3f); // adjust to middle gray const float lum = middleGrey * pixLum / newImageKey; // map to range and calc burnout const float scaleLum = lum * (1.0f + lum / whiteLum * whiteLum) / (1.0f + lum); OUT.col = color * scaleLum / pixLum; OUT.col.w = color.w; return OUT; } pixel CalcAvgLogLum(frag IN, uniform sampler2D colors) { //////////// //-- write out logaritmic luminance for tone mapping pixel OUT; const float4 color = tex2Dlod(colors, float4(IN.texCoord.xy, 0, 0)); OUT.col = color; // the old loglum is stored in the hightest mipmap-level float oldLogLum = tex2Dlod(colors, float4(IN.texCoord.xy, 0, MAX_LOD_LEVEL)).w; // the intensity weights const float3 w = float3(0.299f, 0.587f, 0.114f); float lum = dot(color.rgb, w); float logLum = log(max(1e-3f, lum)); float logLumOffset = MINLOGLUM * INV_LOGLUM_RANGE; float logLumScaled = logLum * INV_LOGLUM_RANGE - logLumOffset; ///////////// //-- exponential smoothing of the tone mapping over time if (oldLogLum > 1e-3f) // check if loglum from last frame too small (=> tm too bright) OUT.col.w = lerp(oldLogLum, logLumScaled, TONE_MAPPING_EXPONENTIAL_FACTOR); else OUT.col.w = logLumScaled; return OUT; }