From f82b7005984d23de941bda0318003e55fd84188c Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Wed, 13 Jan 2016 20:33:16 +0100 Subject: [PATCH] Improved linear RGB lighting and added ACES tonemap --- base/renderprogs/AmbientOcclusion_AO.pixel | 2 +- .../DeepGBufferRadiosity_radiosity.pixel | 10 +- base/renderprogs/ambient_lighting.pixel | 9 +- base/renderprogs/global.inc | 7 +- base/renderprogs/interaction.pixel | 139 +++++++---------- base/renderprogs/interactionSM.pixel | 142 +++++++----------- base/renderprogs/texture_color.pixel | 2 +- base/renderprogs/texture_color_skinned.pixel | 2 +- base/renderprogs/texture_color_texgen.pixel | 2 +- base/renderprogs/tonemap.pixel | 49 ++++-- neo/renderer/RenderSystem_init.cpp | 4 +- neo/renderer/tr_backend_draw.cpp | 4 +- 12 files changed, 170 insertions(+), 202 deletions(-) diff --git a/base/renderprogs/AmbientOcclusion_AO.pixel b/base/renderprogs/AmbientOcclusion_AO.pixel index 189f3944..3afb1a56 100644 --- a/base/renderprogs/AmbientOcclusion_AO.pixel +++ b/base/renderprogs/AmbientOcclusion_AO.pixel @@ -75,7 +75,7 @@ const float invRadius2 = 1.0 / radius2; const float bias = 0.01 * METERS_TO_DOOM; /** intensity / radius^6 */ -const float intensity = 0.3; +const float intensity = 0.6; const float intensityDivR6 = intensity / ( radius* radius* radius* radius* radius* radius ); /** The height in pixels of a 1m object if viewed from 1m away. diff --git a/base/renderprogs/DeepGBufferRadiosity_radiosity.pixel b/base/renderprogs/DeepGBufferRadiosity_radiosity.pixel index 5bd3cda9..c82331b9 100644 --- a/base/renderprogs/DeepGBufferRadiosity_radiosity.pixel +++ b/base/renderprogs/DeepGBufferRadiosity_radiosity.pixel @@ -12,7 +12,7 @@ #define USE_OCT16 0 #define COMPUTE_PEELED_LAYER 0 #define USE_MIPMAPS 1 -#define USE_TAP_NORMAL 0 +#define USE_TAP_NORMAL 1 #define HIGH_QUALITY 0 @@ -473,8 +473,8 @@ void sampleIndirectLight numSamplesUsed += weight_Y; #endif - //irradianceSum += E; - irradianceSum += pow( E, float3( 2.2 ) ); // RB: to linear RGB + irradianceSum += E; + //irradianceSum += pow( E, float3( 2.2 ) ); // RB: to linear RGB } @@ -535,8 +535,8 @@ void main( PS_IN fragment, out PS_OUT result ) const float solidAngleHemisphere = 2 * PI; float3 E_X = irradianceSum * solidAngleHemisphere / ( numSamplesUsed + 0.00001 ); - //indirectColor = E_X; - indirectColor = pow( E_X, float3( 1.0 / 2.2 ) ); // RB: to sRGB + indirectColor = E_X; + //indirectColor = pow( E_X, float3( 1.0 / 2.2 ) ); // RB: to sRGB // What is the ambient visibility of this location visibility = 1 - numSamplesUsed / float( NUM_SAMPLES ); diff --git a/base/renderprogs/ambient_lighting.pixel b/base/renderprogs/ambient_lighting.pixel index e1cbd175..11115299 100644 --- a/base/renderprogs/ambient_lighting.pixel +++ b/base/renderprogs/ambient_lighting.pixel @@ -75,8 +75,8 @@ void main( PS_IN fragment, out PS_OUT result ) { // RB: added abs half3 specularContribution = _half3( pow( abs( hDotN ), specularPower ) ); - half3 diffuseColor = diffuseMap * sRGBToLinearRGB( rpDiffuseModifier.xyz ) * 1.5f; - half3 specularColor = specMap.xyz * specularContribution * sRGBToLinearRGB( rpSpecularModifier.xyz ); + half3 diffuseColor = diffuseMap * ( rpDiffuseModifier.xyz ) * 1.5f; + half3 specularColor = specMap.xyz * specularContribution * ( rpSpecularModifier.xyz ); // RB: http://developer.valvesoftware.com/wiki/Half_Lambert float halfLdotN = dot3( localNormal, lightVector ) * 0.5 + 0.5; @@ -92,6 +92,7 @@ void main( PS_IN fragment, out PS_OUT result ) { half3 rimColor = sRGBToLinearRGB( half3( 0.125 ) * 1.2 ) * lightColor * pow( rim, rimPower ); //result.color.rgb = localNormal.xyz * 0.5 + 0.5; - result.color.xyz = ( ( diffuseColor + specularColor ) * halfLdotN * lightColor + rimColor ) * fragment.color.rgb;; - result.color.w = 1.0; + result.color.xyz = ( ( diffuseColor + specularColor ) * halfLdotN * lightColor + rimColor ) * fragment.color.rgb; + //result.color = ( ( diffuseColor + specularColor ) * halfLdotN * lightColor + rimColor ) * fragment.color.rgba; + result.color.w = fragment.color.a; } diff --git a/base/renderprogs/global.inc b/base/renderprogs/global.inc index 552db354..c705c508 100644 --- a/base/renderprogs/global.inc +++ b/base/renderprogs/global.inc @@ -134,7 +134,7 @@ static float dot4( float2 a, float4 b ) { return dot( float4( a, 0, 1 ), b ); } half3 sRGBToLinearRGB( half3 rgb ) { #if defined(USE_SRGB) - return pow( rgb, half3( 2.2 ) ); + return max( pow( rgb, half3( 2.2 ) ), half3( 0.0 ) ); #else return rgb; #endif @@ -143,7 +143,7 @@ half3 sRGBToLinearRGB( half3 rgb ) half4 sRGBAToLinearRGBA( half4 rgba ) { #if defined(USE_SRGB) - return pow( rgba, half4( 2.2 ) ); + return float4( max( pow( rgba.rgb, half3( 2.2 ) ), half3( 0.0 ) ), rgba.a ); #else return rgba; #endif @@ -243,7 +243,8 @@ static const half4 LUMINANCE_LINEAR = half4( 0.299, 0.587, 0.144, 0.0 ); static float4 idtex2Dproj( sampler2D samp, float4 texCoords ) { return tex2Dproj( samp, texCoords.xyw ); } static float4 swizzleColor( float4 c ) { - return sRGBAToLinearRGBA( c ); + return c; + //return sRGBAToLinearRGBA( c ); } static float2 vposToScreenPosTexCoord( float2 vpos ) { return vpos.xy * rpWindowCoord.xy; } diff --git a/base/renderprogs/interaction.pixel b/base/renderprogs/interaction.pixel index 2b58950a..e6ecb0c2 100644 --- a/base/renderprogs/interaction.pixel +++ b/base/renderprogs/interaction.pixel @@ -60,12 +60,12 @@ void main( PS_IN fragment, out PS_OUT result ) half4 lightFalloff = ( idtex2Dproj( samp1, fragment.texcoord2 ) ); half4 lightProj = ( idtex2Dproj( samp2, fragment.texcoord3 ) ); half4 YCoCG = tex2D( samp3, fragment.texcoord4.xy ); - half4 specMap = sRGBAToLinearRGBA( tex2D( samp4, fragment.texcoord5.xy ) ); + half4 specMapSRGB = tex2D( samp4, fragment.texcoord5.xy ); + half4 specMap = sRGBAToLinearRGBA( specMapSRGB ); half3 lightVector = normalize( fragment.texcoord0.xyz ); half3 viewVector = normalize( fragment.texcoord6.xyz ); half3 diffuseMap = sRGBToLinearRGB( ConvertYCoCgToRGB( YCoCG ) ); - //diffuseMap.r = 1.0; half3 localNormal; // RB begin @@ -95,105 +95,76 @@ void main( PS_IN fragment, out PS_OUT result ) half3 halfAngleVector = normalize( lightVector + viewVector ); half hdotN = saturate( dot3( halfAngleVector, localNormal ) ); -#if 1 - /* - Physically based shading +#if 0 //defined(USE_PBR) + +#if 0 //defined(USE_METALNESS) + const half metallic = specMapSRGB.g; + const half roughness = specMapSRGB.r; + const half glossiness = 1.0 - roughness; + + // the vast majority of real-world materials (anything not metal or gems) have F(0°) + // values in a very narrow range (~0.02 - 0.08) - Lambert diffuse BRDF combined with Cook-Torrance microfacet specular BRDF + // approximate non-metals with linear RGB 0.04 which is 0.08 * 0.5 (default in UE4) + const half3 dielectricColor = half3( 0.04 ); - D( h ) * F( v, h ) * G( l, v, h ) - f( l, v ) = diffuse + --------------------------------- - 4 * ( n * l ) ( n * v ) - */ - - // RB: compensate r_lightScale 3 and the division of Pi - lambert *= 1.3; - - const half3 goldColor = half3( 1.00, 0.71, 0.29 ); - - //const half3 baseColor = goldColor; + // derive diffuse and specular from albedo(m) base color const half3 baseColor = diffuseMap; - const half metallic = 0.0; - - // rpDiffuseModifier contains light color - half3 lightColor = lightProj.xyz * lightFalloff.xyz * rpDiffuseModifier.xyz; - - half vdotN = saturate( dot3( viewVector, localNormal ) ); - half vdotH = saturate( dot3( viewVector, halfAngleVector ) ); - - // the vast majority of real-world materials (anything not metal or gems) have F(0°) values in a very narrow range (~0.02 - 0.06) - + half3 diffuseColor = baseColor * ( 1.0 - metallic ); + half3 specularColor = lerp( dielectricColor, baseColor, metallic ); +#else // HACK calculate roughness from D3 gloss maps - // converting from linear to sRGB space give pretty results - const half glossiness = clamp( pow( dot( LUMINANCE_VECTOR.rgb, specMap.rgb ) * 0.4, 1.0 / 2.2 ) * 1.0, 0.0, 0.98 ); + float Y = dot( LUMINANCE_SRGB.rgb, specMapSRGB.rgb ); - const half roughness = 1.0 - glossiness; + //const float glossiness = clamp( 1.0 - specMapSRGB.r, 0.0, 0.98 ); + const float glossiness = clamp( pow( Y, 1.0 / 2.0 ), 0.0, 0.98 ); + + const float roughness = 1.0 - glossiness; + + half3 diffuseColor = diffuseMap; + half3 specularColor = specMap.rgb; +#endif + + + // RB: compensate r_lightScale 3 and the division of Pi + //lambert *= 1.3; + + // rpDiffuseModifier contains light color multiplier + half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );// * rpDiffuseModifier.xyz; + + half vdotN = clamp( dot3( viewVector, localNormal ), 0.0, 1.0 ); + half vdotH = clamp( dot3( viewVector, halfAngleVector ), 0.0, 1.0 ); + half ldotH = clamp( dot3( lightVector, halfAngleVector ), 0.0, 1.0 ); // compensate r_lightScale 3 * 2 - half3 reflectColor = specMap.rgb * rpSpecularModifier.rgb * 0.5; + half3 reflectColor = specMap.rgb * rpSpecularModifier.rgb * 1.0;// * 0.5; - // alpha modifications by Disney - s2012_pbs_disney_brdf_notes_v2.pdf - const half alpha = roughness * roughness; + // cheap approximation by ARM with only one division + // http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf + // page 26 - // reduce roughness range from [0 .. 1] to [0.5 .. 1] - const half alphaG = pow( 0.5 + roughness * 0.5, 2.0 ); - - //half3 D = _half3( pow( abs( hdotN ), 10.0f ) ); - half3 D = _half3( Distribution_GGX( hdotN, alpha ) ); - //half3 D = _half3( Distribution_GGX_1886( hdotN, alpha ) ); - half3 G = _half3( Visibility_Schlick( ldotN, vdotN, alpha ) ); - //half3 G = _half3( Visibility_SmithGGX( ldotN, vdotN, alpha ) ); - half3 F = Fresnel_Schlick( reflectColor, vdotH ); - - // horizon - float horizon = 1.0 - ldotN; - horizon *= horizon; - horizon *= horizon; - half3 specLightColor = lightColor.rgb - lightColor.rgb * horizon; - - float3 specularColor = saturate( D * G * ( F * ( specLightColor.rgb * lambert ) ) ); - - //specularColor = EnvironmentBRDFApprox( roughness, vdotN, specularColor.rgb );// * 0.45; + float rr = roughness * roughness; + float rrrr = rr * rr; + // disney GGX + float D = ( hdotN * hdotN ) * ( rrrr - 1.0 ) + 1.0; + float VFapprox = ( ldotH * ldotH ) * ( roughness + 0.5 ); + half3 specularBRDF = ( rrrr / ( 4.0 * PI * D * D * VFapprox ) ) * reflectColor; + //specularBRDF = half3( 0.0 ); #if 0 - result.color = float4( _half3( F ), 1.0 ); + result.color = float4( _half3( VFapprox ), 1.0 ); return; #endif // see http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ - lambert /= PI; + //lambert /= PI; //half3 diffuseColor = mix( diffuseMap, F0, metal ) * rpDiffuseModifier.xyz; - half3 diffuseColor = baseColor * rpDiffuseModifier.xyz; - diffuseColor *= lightColor * lambert; - - - - /* - maintain energy conservation - - Energy conservation is a restriction on the reflection model - that requires that the total amount of reflected light - cannot be more than the incoming light. + half3 diffuseBRDF = diffuseColor * lambert * sRGBToLinearRGB( rpDiffuseModifier.xyz ); - http://www.rorydriscoll.com/2009/01/25/energy-conservation-in-games/ - - Cdiff + Cspec <= 1 - */ - //diffuseColor.rgb *= ( half3( 1.0 ) - specularColor.rgb ); - - -#if 0 //defined(USE_METALNESS) - //specularColor *= ( 0.96 * metallic ) * diffuseColor + half( 0.04 ); - diffuseColor.rgb *= ( 1.0 - metallic ); - - //diffuseColor.rgb = mix( diffuseColor, specularColor, metallic ); -#endif - - // apply r_lightScale overbright for both diffuse and specular - result.color.xyz = ( diffuseColor + specularColor ) * fragment.color.rgb;// + rimColor; + result.color.xyz = ( diffuseBRDF + specularBRDF ) * lightColor * fragment.color.rgb * shadow; result.color.w = 1.0; #else @@ -205,11 +176,11 @@ void main( PS_IN fragment, out PS_OUT result ) const half specularPower = 10.0f; // RB: added abs - half3 specularContribution = _half3( pow( abs( hdotN ), specularPower ) ); + half3 specularContribution = _half3( pow( hdotN, specularPower ) ); half3 diffuseColor = diffuseMap * sRGBToLinearRGB( rpDiffuseModifier.xyz ); - half3 specularColor = specMap.xyz * specularContribution * sRGBToLinearRGB( rpSpecularModifier.xyz * 1.0 ); - half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz ); + half3 specularColor = specMap.xyz * specularContribution * sRGBToLinearRGB( rpSpecularModifier.xyz ); + half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz ); /* half rim = 1.0f - saturate( hdotN ); diff --git a/base/renderprogs/interactionSM.pixel b/base/renderprogs/interactionSM.pixel index b1adc20f..3a8b79e4 100644 --- a/base/renderprogs/interactionSM.pixel +++ b/base/renderprogs/interactionSM.pixel @@ -67,7 +67,8 @@ void main( PS_IN fragment, out PS_OUT result ) half4 lightFalloff = ( idtex2Dproj( samp1, fragment.texcoord2 ) ); half4 lightProj = ( idtex2Dproj( samp2, fragment.texcoord3 ) ); half4 YCoCG = tex2D( samp3, fragment.texcoord4.xy ); - half4 specMap = sRGBAToLinearRGBA( tex2D( samp4, fragment.texcoord5.xy ) ); + half4 specMapSRGB = tex2D( samp4, fragment.texcoord5.xy ); + half4 specMap = sRGBAToLinearRGBA( specMapSRGB ); half3 lightVector = normalize( fragment.texcoord0.xyz ); half3 viewVector = normalize( fragment.texcoord6.xyz ); @@ -272,107 +273,78 @@ void main( PS_IN fragment, out PS_OUT result ) half3 halfAngleVector = normalize( lightVector + viewVector ); - half hdotN = saturate( dot3( halfAngleVector, localNormal ) ); + half hdotN = clamp( dot3( halfAngleVector, localNormal ), 0.0, 1.0 ); -#if 1 - /* - Physically based shading +#if 0 //defined(USE_PBR) + +#if 0 //defined(USE_METALNESS) + const half metallic = specMapSRGB.g; + const half roughness = specMapSRGB.r; + const half glossiness = 1.0 - roughness; + + // the vast majority of real-world materials (anything not metal or gems) have F(0°) + // values in a very narrow range (~0.02 - 0.08) - Lambert diffuse BRDF combined with Cook-Torrance microfacet specular BRDF + // approximate non-metals with linear RGB 0.04 which is 0.08 * 0.5 (default in UE4) + const half3 dielectricColor = half3( 0.04 ); - D( h ) * F( v, h ) * G( l, v, h ) - f( l, v ) = diffuse + --------------------------------- - 4 * ( n * l ) ( n * v ) - */ - - // RB: compensate r_lightScale 3 and the division of Pi - lambert *= 1.3; - - const half3 goldColor = half3( 1.00, 0.71, 0.29 ); - - //const half3 baseColor = goldColor; + // derive diffuse and specular from albedo(m) base color const half3 baseColor = diffuseMap; - const half metallic = 0.0; - - // rpDiffuseModifier contains light color - half3 lightColor = lightProj.xyz * lightFalloff.xyz * rpDiffuseModifier.xyz; - - half vdotN = saturate( dot3( viewVector, localNormal ) ); - half vdotH = saturate( dot3( viewVector, halfAngleVector ) ); - - // the vast majority of real-world materials (anything not metal or gems) have F(0°) values in a very narrow range (~0.02 - 0.06) - + half3 diffuseColor = baseColor * ( 1.0 - metallic ); + half3 specularColor = lerp( dielectricColor, baseColor, metallic ); +#else // HACK calculate roughness from D3 gloss maps - // converting from linear to sRGB space give pretty results - const half glossiness = clamp( pow( dot( LUMINANCE_VECTOR.rgb, specMap.rgb ) * 0.4, 1.0 / 2.2 ) * 1.0, 0.0, 0.98 ); + float Y = dot( LUMINANCE_SRGB.rgb, specMapSRGB.rgb ); - const half roughness = 1.0 - glossiness; + //const float glossiness = clamp( 1.0 - specMapSRGB.r, 0.0, 0.98 ); + const float glossiness = clamp( pow( Y, 1.0 / 2.0 ), 0.0, 0.98 ); + + const float roughness = 1.0 - glossiness; + + half3 diffuseColor = diffuseMap; + half3 specularColor = specMap.rgb; +#endif + + + // RB: compensate r_lightScale 3 and the division of Pi + //lambert *= 1.3; + + // rpDiffuseModifier contains light color multiplier + half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );// * rpDiffuseModifier.xyz; + + half vdotN = clamp( dot3( viewVector, localNormal ), 0.0, 1.0 ); + half vdotH = clamp( dot3( viewVector, halfAngleVector ), 0.0, 1.0 ); + half ldotH = clamp( dot3( lightVector, halfAngleVector ), 0.0, 1.0 ); // compensate r_lightScale 3 * 2 - half3 reflectColor = specMap.rgb * rpSpecularModifier.rgb * 0.5; + half3 reflectColor = specMap.rgb * rpSpecularModifier.rgb * 1.0;// * 0.5; - // alpha modifications by Disney - s2012_pbs_disney_brdf_notes_v2.pdf - const half alpha = roughness * roughness; + // cheap approximation by ARM with only one division + // http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf + // page 26 - // reduce roughness range from [0 .. 1] to [0.5 .. 1] - const half alphaG = pow( 0.5 + roughness * 0.5, 2.0 ); - - //half3 D = _half3( pow( abs( hdotN ), 10.0f ) ); - half3 D = _half3( Distribution_GGX( hdotN, alpha ) ); - //half3 D = _half3( Distribution_GGX_1886( hdotN, alpha ) ); - half3 G = _half3( Visibility_Schlick( ldotN, vdotN, alpha ) ); - //half3 G = _half3( Visibility_SmithGGX( ldotN, vdotN, alpha ) ); - half3 F = Fresnel_Schlick( reflectColor, vdotH ); - - // horizon - float horizon = 1.0 - ldotN; - horizon *= horizon; - horizon *= horizon; - half3 specLightColor = lightColor.rgb - lightColor.rgb * horizon; - - float3 specularColor = saturate( D * G * ( F * ( specLightColor.rgb * lambert ) ) ); - - //specularColor = EnvironmentBRDFApprox( roughness, vdotN, specularColor.rgb );// * 0.45; + float rr = roughness * roughness; + float rrrr = rr * rr; + // disney GGX + float D = ( hdotN * hdotN ) * ( rrrr - 1.0 ) + 1.0; + float VFapprox = ( ldotH * ldotH ) * ( roughness + 0.5 ); + half3 specularBRDF = ( rrrr / ( 4.0 * PI * D * D * VFapprox ) ) * reflectColor; + //specularBRDF = half3( 0.0 ); #if 0 - result.color = float4( _half3( F ), 1.0 ); + result.color = float4( _half3( VFapprox ), 1.0 ); return; #endif // see http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ - lambert /= PI; + //lambert /= PI; //half3 diffuseColor = mix( diffuseMap, F0, metal ) * rpDiffuseModifier.xyz; - half3 diffuseColor = baseColor * rpDiffuseModifier.xyz; - diffuseColor *= lightColor * lambert; - - - - /* - maintain energy conservation - - Energy conservation is a restriction on the reflection model - that requires that the total amount of reflected light - cannot be more than the incoming light. + half3 diffuseBRDF = diffuseColor * lambert * sRGBToLinearRGB( rpDiffuseModifier.xyz ); - http://www.rorydriscoll.com/2009/01/25/energy-conservation-in-games/ - - Cdiff + Cspec <= 1 - */ - //diffuseColor.rgb *= ( half3( 1.0 ) - specularColor.rgb ); - - -#if 0 //defined(USE_METALNESS) - //specularColor *= ( 0.96 * metallic ) * diffuseColor + half( 0.04 ); - diffuseColor.rgb *= ( 1.0 - metallic ); - - //diffuseColor.rgb = mix( diffuseColor, specularColor, metallic ); -#endif - - // apply r_lightScale overbright for both diffuse and specular - result.color.xyz = ( diffuseColor + specularColor ) * fragment.color.rgb * shadow;// + rimColor; + result.color.xyz = ( diffuseBRDF + specularBRDF ) * lightColor * fragment.color.rgb * shadow; result.color.w = 1.0; #else @@ -384,11 +356,11 @@ void main( PS_IN fragment, out PS_OUT result ) const half specularPower = 10.0f; // RB: added abs - half3 specularContribution = _half3( pow( abs( hdotN ), specularPower ) ); + half3 specularContribution = _half3( pow( hdotN, specularPower ) ); - half3 diffuseColor = diffuseMap * rpDiffuseModifier.xyz; - half3 specularColor = specMap.xyz * specularContribution * rpSpecularModifier.xyz; - half3 lightColor = lightProj.xyz * lightFalloff.xyz; + half3 diffuseColor = diffuseMap * sRGBToLinearRGB( rpDiffuseModifier.xyz ); + half3 specularColor = specMap.xyz * specularContribution * sRGBToLinearRGB( rpSpecularModifier.xyz ); + half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz ); /* half rim = 1.0f - saturate( hdotN ); diff --git a/base/renderprogs/texture_color.pixel b/base/renderprogs/texture_color.pixel index e2e8316e..625872ee 100644 --- a/base/renderprogs/texture_color.pixel +++ b/base/renderprogs/texture_color.pixel @@ -43,5 +43,5 @@ struct PS_OUT { void main( PS_IN fragment, out PS_OUT result ) { float4 color = tex2D( samp0, fragment.texcoord0 ) * fragment.color; clip( color.a - rpAlphaTest.x ); - result.color = color; + result.color = sRGBAToLinearRGBA( color ); } \ No newline at end of file diff --git a/base/renderprogs/texture_color_skinned.pixel b/base/renderprogs/texture_color_skinned.pixel index e2e8316e..625872ee 100644 --- a/base/renderprogs/texture_color_skinned.pixel +++ b/base/renderprogs/texture_color_skinned.pixel @@ -43,5 +43,5 @@ struct PS_OUT { void main( PS_IN fragment, out PS_OUT result ) { float4 color = tex2D( samp0, fragment.texcoord0 ) * fragment.color; clip( color.a - rpAlphaTest.x ); - result.color = color; + result.color = sRGBAToLinearRGBA( color ); } \ No newline at end of file diff --git a/base/renderprogs/texture_color_texgen.pixel b/base/renderprogs/texture_color_texgen.pixel index 90967ba9..432a75ee 100644 --- a/base/renderprogs/texture_color_texgen.pixel +++ b/base/renderprogs/texture_color_texgen.pixel @@ -48,5 +48,5 @@ void main( PS_IN fragment, out PS_OUT result ) { // gets called. float4 texSample = idtex2Dproj( samp0, fragment.texcoord0 ); - result.color = texSample * fragment.color; + result.color = sRGBAToLinearRGBA( texSample ) * fragment.color; } \ No newline at end of file diff --git a/base/renderprogs/tonemap.pixel b/base/renderprogs/tonemap.pixel index 272f78bd..607a1b5b 100644 --- a/base/renderprogs/tonemap.pixel +++ b/base/renderprogs/tonemap.pixel @@ -43,19 +43,32 @@ struct PS_OUT float4 color : COLOR; }; -float A = 0.22; // shoulder strength -float B = 0.3; // linear strength -float C = 0.10; // linear angle -float D = 0.20; // toe strength -float E = 0.01; // toe numerator -float F = 0.30; // toe denominator -float W = 11.2; // linear white point + float3 Uncharted2Tonemap( float3 x ) { + float A = 0.22; // shoulder strength + float B = 0.3; // linear strength + float C = 0.10; // linear angle + float D = 0.20; // toe strength + float E = 0.01; // toe numerator + float F = 0.30; // toe denominator + float W = 11.2; // linear white point + return ( ( x * ( A * x + C * B ) + D * E ) / ( x * ( A * x + B ) + D * F ) ) - E / F; } +// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ +float3 ACESFilm( float3 x ) +{ + float a = 2.51; + float b = 0.03; + float c = 2.43; + float d = 0.59; + float e = 0.14; + return saturate( ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e ) ); +} + void main( PS_IN fragment, out PS_OUT result ) { float2 tCoords = fragment.texcoord0; @@ -98,18 +111,20 @@ void main( PS_IN fragment, out PS_OUT result ) float Ymax = hdrMaxLuminance; +#define OPERATOR 2 -#if 0 +#if OPERATOR == 0 // advanced Reinhard operator, artistically desirable to burn out bright areas float L = Yr * ( 1.0 + Yr / ( Ymax * Ymax ) ) / ( 1.0 + Yr ); color.rgb *= L; - + +#elif OPERATOR == 1 // http://freespace.virgin.net/hugo.elias/graphics/x_posure.htm // exponential tone mapper that is very similar to the Uncharted one // very good in keeping the colors natural - //float exposure = 1.0; - //float L = ( 1.0 - exp( -Yr * exposure ) ); - //color.rgb *= L; + float exposure = 1.0; + float L = ( 1.0 - exp( -Yr * exposure ) ); + color.rgb *= L; // Kodak filmic tone mappping, includes gamma correction //float3 rgb = max( float3( 0 ), color.rgb - float3( 0.004 ) ); @@ -120,7 +135,15 @@ void main( PS_IN fragment, out PS_OUT result ) //color.rgb += ( cutoff * 2.0 - color.rgb ) * saturate( cutoff * 2 - color.rgb ) * ( 0.25 / cutoff ) - cutoff; //color.rgb = color.rgb * ( float3( 0.5 ) + 6.2 * color.rgb ) / ( float3( 0.06 ) + color.rgb * ( float3( 1.7 ) + 6.2 * color.rgb ) ); -#else +#elif OPERATOR == 2 + float exposure = 1.0; + float3 exposedColor = exposure * color.rgb; + + float3 curr = ACESFilm( exposedColor ); + + float3 whiteScale = 1.0 / ACESFilm( float3( Ymax ) ); + color.rgb = curr * whiteScale; +#elif OPERATOR == 3 // Uncharted 2 tone mapping based on Kodak film curve //float exposure = ( hdrKey / hdrAverageLuminance ) * 0.2; diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index 10bcb03f..cb938891 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -248,8 +248,8 @@ idCVar r_shadowMapSunDepthBiasScale( "r_shadowMapSunDepthBiasScale", "0.999991", idCVar r_useHDR( "r_useHDR", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "use high dynamic range rendering" ); idCVar r_hdrMinLuminance( "r_hdrMinLuminance", "0.05", CVAR_RENDERER | CVAR_FLOAT, "" ); idCVar r_hdrMaxLuminance( "r_hdrMaxLuminance", "300", CVAR_RENDERER | CVAR_FLOAT, "" ); -idCVar r_hdrKey( "r_hdrKey", "0.5", CVAR_RENDERER | CVAR_FLOAT, "mid-gray 0.5 in linear RGB space (without gamma curve applied)" ); -idCVar r_hdrContrastThreshold( "r_hdrContrastThreshold", "13", CVAR_RENDERER | CVAR_FLOAT, "all pixels brighter than this cause HDR bloom glares" ); +idCVar r_hdrKey( "r_hdrKey", "1.0", CVAR_RENDERER | CVAR_FLOAT, "mid-gray 0.5 in linear RGB space (without gamma curve applied)" ); +idCVar r_hdrContrastThreshold( "r_hdrContrastThreshold", "33", CVAR_RENDERER | CVAR_FLOAT, "all pixels brighter than this cause HDR bloom glares" ); idCVar r_hdrContrastOffset( "r_hdrContrastOffset", "100", CVAR_RENDERER | CVAR_FLOAT, "" ); idCVar r_hdrGlarePasses( "r_hdrGlarePasses", "8", CVAR_RENDERER | CVAR_INTEGER, "how many times the bloom blur is rendered offscreen. number should be even" ); idCVar r_hdrDebug( "r_hdrDebug", "0", CVAR_RENDERER | CVAR_FLOAT, "show scene luminance as heat map" ); diff --git a/neo/renderer/tr_backend_draw.cpp b/neo/renderer/tr_backend_draw.cpp index 4b9e9fd3..3ae837cf 100644 --- a/neo/renderer/tr_backend_draw.cpp +++ b/neo/renderer/tr_backend_draw.cpp @@ -5244,7 +5244,7 @@ void RB_DrawViewInternal( const viewDef_t* viewDef, const int stereoEye ) //------------------------------------------------- // darken the scene using the screen space ambient occlusion result //------------------------------------------------- - //RB_SSAO( viewDef ); + RB_SSAO( viewDef ); //RB_SSGI( viewDef ); //------------------------------------------------- @@ -5271,7 +5271,7 @@ void RB_DrawViewInternal( const viewDef_t* viewDef, const int stereoEye ) //------------------------------------------------- // use direct light and emissive light contributions to add indirect screen space light //------------------------------------------------- - RB_SSGI( viewDef ); + //RB_SSGI( viewDef ); //------------------------------------------------- // fog and blend lights, drawn after emissive surfaces