// // Basic HDR functions // Only 'ToneMapHDR()' is used - the rest is experimentation // RvG, 11-3-09 // float4 ToneMapHDR_Linear(float4 color,float exposure) // Linear (more like LDR) { return exposure*color; } float4 ToneMapHDR_Ogre(float4 color,float exposure) // Linear (more like LDR) // From 'Photographic Tone Reproduction For Digital Images' and Ogre { /*const float MIDDLE_GREY = 0.72; const float FUDGE = 0.001; const float L_WHITE = 0.2;*/ /* const float MIDDLE_GREY = 1.5; const float FUDGE = 0.001; const float L_WHITE = 0.5;*/ // Nice /* const float MIDDLE_GREY = 0.5; const float FUDGE = 0.001; const float L_WHITE = 0.4; */ const float MIDDLE_GREY = 0.72; const float FUDGE = 0.001; const float L_WHITE = 0.5; // Initial luminence scaling (equation 2) color.rgb *= MIDDLE_GREY / (FUDGE + (1.0/exposure)); // Control white out (equation 4 nom) color.rgb *= (1.0 + color.rgb / L_WHITE); // Final mapping (equation 4 denom) color.rgb /= (1.0 + color.rgb); return color; } float4 ToneMapHDR0(float4 color,float exposure) // Easy trick { color/=color+1.0; // Gamma correction (pow(2.0)) const float gamma=2.2; color=pow(color,gamma); return color; } float4 ToneMapHDR1(float4 color,float exposure) { // Currently unchanged (LDR) // Future: map HDR color to LDR color return color; } float4 ToneMapHDR2(float4 color,float exposure) // Simple mapping from 0..inf -> 0..1 // Darkens image but bright colors remain visible { float4 c; c.r=color.r/(color.r+1.0); c.g=color.g/(color.g+1.0); c.b=color.b/(color.b+1.0); c.a=color.a; return c; } float4 ToneMapHDR3(float4 color,float exposure) // Simple mapping from 0..inf -> 0..1 // Darkens image but bright colors remain visible { float4 c; c=color*0.5; c.a=1; return c; } float4 ToneMapHDR4(float4 color,float exposure) // Exponential diminish { return 1.0-exp(-exposure*color); } float4 ToneMapHDR5(float4 color,float exposure) // From HDRRenderingInOpenGL.pdf { float Y = dot(vec4(0.30, 0.59, 0.11, 0.0), color); float YD = exposure * (exposure/brightMax + 1.0) / (exposure + 1.0); color *= YD; return color; } float4 ToneMapHDR6(float4 color,float exposure) // Exponential (more contrast than L=L/(L+1) // Used in Racer v0.8.8 for example { float3 c; //c=1.1-1.2*exp(-exposure*color); c=1.0-exp(-2.0*exposure*color.rgb); //do we want alpha to be 1 for sure? // Gamma correction (pow(2.0)) const float gamma=2.2; c=pow(c,gamma); //c*=c; return float4(c,1); //return color; //return 1.1-1.2*exp(-exposure*color); //return 1.0-exp(-exposure*color); //return 1.05-1.1*exp(-exposure*color); //return 1.2-1.3*exp(-exposure*color); //return 1.0-color; } float4 ToneMapHDR7(float4 color,float exposure) // Exponential (more contrast than L=L/(L+1) // Used in Racer v0.8.17+ for lux light unit { float3 c; c=1.0-exp(-exposure*color.rgb); // do we want alpha to be 1 for sure? //c=1.0-0.01*exp(-exposure*color.rgb); // do we want alpha to be 1 for sure? // Gamma correction (pow(2.0)) const float gamma=2.0; c=pow(c,gamma); //c*=c; return float4(c,1); } float4 ToneMapHDR8(float4 color,float exposure) // Exponential (more contrast than L=L/(L+1) // Desaturates in low-light to mimic night // Used in Racer v0.8.17+ for lux light unit { float3 c; // Desaturate low-light pixels (per-pixel, so lit areas are unaffected) // Calculate black & white value, looking at brightness of red/green/blue individually float bw=0.28*color.r+0.59*color.g+0.13*color.b; // Fully desaturated color to interpolate to - add a bit of a blue shift // that seems to give a 'night' feeling float3 bwColor=float3(bw*0.8,bw*0.8,bw*1.1); // Desaturation amount float desat=exp(-0.9*bw); // Always leave a bit of color desat=min(desat,0.9); color.rgb=lerp(color.rgb,bwColor,desat); // HDR->LDR tonemap c=1.0-exp(-exposure*color.rgb); //c=color/(color+1); //c=exposure*color/(exposure*color+1); // Gamma correction? //const float gamma=2.2; //c=pow(c,gamma); //c = max(0, c-0.004); //c = (c*(6.2*c+0.5))/(c*(6.2*c+1.7)+0.06); return float4(c,1); } float4 ToneMapHDR_Uncharted_v0821(float4 color,float exposure) // Filmic tonemapping from Uncharted 2 // Desaturates in low-light to mimic night // Used in Racer v0.8.21 { float3 c; // Desaturate low-light pixels (per-pixel, so lit areas are unaffected) // Calculate black & white value, looking at brightness of red/green/blue individually float bw=0.28*color.r+0.59*color.b+0.13*color.b; // Fully desaturated color to interpolate to - add a bit of a blue shift // that seems to give a 'night' feeling float3 bwColor=float3(bw*0.8,bw*0.8,bw*1.1); // Desaturation amount float desat=exp(-5.0*bw); // Always leave a bit of color desat=min(desat,0.9); color.rgb=lerp(color.rgb,bwColor,desat); // HDR->LDR tonemap //float3 x=max(0,color.rgb-float3(0.004,0.004,0.004)); c=1.0-exp(-exposure*color.rgb); // c*=0.5; // float3 x=max(float3(0,0,0),c.rgb-float3(0.004,0.004,0.004)); // c.rgb=(x*(float3(6.2,6.2,6.2)*x+float3(0.5,0.5,0.5) ))/(x*(float3(6.2,6.2,6.2)*x+float3(1.7,1.7,1.7) )+float3(0.06,0.06,0.06) ); // c.rgb=x*float3(6.2,6.2,6.2); //c.rgb*=0.5; //c.gb=color.gb; //c=color; //c=x; //c=color/(color+1); //c=exposure*color/(exposure*color+1); // Gamma correction? //const float gamma=2.2; //c=pow(c,gamma); //c = max(0, c-0.004); //c = (c*(6.2*c+0.5))/(c*(6.2*c+1.7)+0.06); return float4(c,1); } float3 NightDesaturate(float3 color) // Given a color, desaturate low-light color to simulate night-time // and eyes not being able to distinguish color anymore { // Desaturate low-light pixels (per-pixel, so lit areas are unaffected) // Calculate black & white value, looking at brightness of red/green/blue individually float bw=0.28*color.r+0.59*color.b+0.13*color.b; // Fully desaturated color to interpolate to - add a bit of a blue shift // that seems to give a 'night' feeling float3 bwColor=float3(bw*0.8,bw*0.8,bw*1.1); // Desaturation amount float desat=exp(-5.0*bw); // Always leave a bit of color desat=min(desat,0.9); color=lerp(color,bwColor,desat); return color; } // // atan() mapping // float4 ToneMapHDR_atan(float4 color,float exposure) // Filmic tonemapping // Desaturates in low-light to mimic night { float3 c; // Night time gives blue shift //color.rgb=NightDesaturate(color.rgb); // Filmic tonemapping c=color; //c.rgb-=exposure; float3 x=max(float3(0,0,0),c.rgb-float3(0.004,0.004,0.004)); x=c.rgb; //c=(x*(float3(6.2,6.2,6.2)*x+float3(0.5,0.5,0.5) ))/(x*(float3(6.2,6.2,6.2)*x+float3(1.7,1.7,1.7) ) // + float3(0.06,0.06,0.06) ); // Marno function const float pi=3.14159265; float middleCol=exposure; c=(atan(0.5*(x-middleCol))/pi)+0.5; //c=x; // Gamma correction? const float gamma=1.0/2.2; //c=pow(c,gamma); //c = max(0, c-0.004); //c = (c*(6.2*c+0.5))/(c*(6.2*c+1.7)+0.06); return float4(c,1); } // // Uncharted 2 toe/shoulder // float3 Film(float3 x) { // A = Shoulder Strength // B = Linear Strength // C = Linear Angle // D = Toe Strength // E = Toe Numerator // F = Toe Denominator const float A=0.22,B=0.30,C=0.10,D=0.20,E=0.01,F=0.30; float3 r=((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F)) - E/F; return r; } float4 ToneMapHDR_U2(float4 color,float exposure) // Filmic tonemapping // Desaturates in low-light to mimic night { float3 c; // Night time gives blue shift //color.rgb=NightDesaturate(color.rgb); // Filmic tonemapping c=color; //c.rgb-=exposure; float3 x=max(float3(0,0,0),c.rgb-float3(0.004,0.004,0.004)); x=c.rgb; //c=(x*(float3(6.2,6.2,6.2)*x+float3(0.5,0.5,0.5) ))/(x*(float3(6.2,6.2,6.2)*x+float3(1.7,1.7,1.7) ) // + float3(0.06,0.06,0.06) ); // Marno function const float whitePoint=exposure; //11.2; c=Film(c)/Film(whitePoint); //c/=exposure; // Gamma correction? const float gamma=2.2; //c=pow(c,gamma); //c = max(0, c-0.004); //c = (c*(6.2*c+0.5))/(c*(6.2*c+1.7)+0.06); return float4(c,1); } float4 ToneMapHDR(float4 color,float exposure) { return ToneMapHDR_U2(color,exposure); return ToneMapHDR_atan(color,exposure); //return ToneMapHDR_Uncharted_v0821(color,exposure); }