diff --git a/base/renderprogs/BRDF.inc.hlsl b/base/renderprogs/BRDF.inc.hlsl index 0bfc1601..d2a2706d 100644 --- a/base/renderprogs/BRDF.inc.hlsl +++ b/base/renderprogs/BRDF.inc.hlsl @@ -55,14 +55,23 @@ half Distribution_GGX_1886( half hdotN, half alpha ) // Fresnel term F( v, h ) // Fnone( v, h ) = F(0°) = specularColor -half3 Fresnel_Schlick( half3 specularColor, half vdotH ) +half3 Fresnel_Schlick( half3 specularColor, half vDotN ) { - return specularColor + ( 1.0 - specularColor ) * pow( 1.0 - vdotH, 5.0 ); + return specularColor + ( 1.0 - specularColor ) * pow( 1.0 - vDotN, 5.0 ); } -half3 Fresnel_Glossy( half3 specularColor, half roughness, half vdotH ) +// Fresnel term that takes roughness into account so rough non-metal surfaces aren't too shiny [Lagarde11] +half3 Fresnel_SchlickRoughness( half3 specularColor, half vDotN, half roughness ) { - return specularColor + ( max( half3( 1.0 - roughness ), specularColor ) - specularColor ) * pow( 1.0 - vdotH, 5.0 ); + return specularColor + ( max( half3( 1.0 - roughness ), specularColor ) - specularColor ) * pow( 1.0 - vDotN, 5.0 ); +} + +// Sébastien Lagarde proposes an empirical approach to derive the specular occlusion term from the diffuse occlusion term in [Lagarde14]. +// The result does not have any physical basis but produces visually pleasant results. +// See Sébastien Lagarde and Charles de Rousiers. 2014. Moving Frostbite to PBR. +float ComputeSpecularAO( float vDotN, float ao, float roughness) +{ + return clamp( pow( vDotN + ao, exp2( -16.0 * roughness - 1.0) ) - 1.0 + ao, 0.0, 1.0 ); } // Visibility term G( l, v, h ) diff --git a/base/renderprogs/ambient_lighting_IBL.ps.hlsl b/base/renderprogs/ambient_lighting_IBL.ps.hlsl index 5cf1c968..929902bc 100644 --- a/base/renderprogs/ambient_lighting_IBL.ps.hlsl +++ b/base/renderprogs/ambient_lighting_IBL.ps.hlsl @@ -2,10 +2,10 @@ =========================================================================== Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. Copyright (C) 2013-2020 Robert Beckebans -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). Doom 3 BFG Edition 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 @@ -30,6 +30,7 @@ If you have questions concerning this license or the applicable additional terms #include "global.inc.hlsl" #include "BRDF.inc.hlsl" +// *INDENT-OFF* uniform sampler2D samp0 : register(s0); // texture 1 is the per-surface normal map uniform sampler2D samp1 : register(s1); // texture 3 is the per-surface specular or roughness/metallic/AO mixer map uniform sampler2D samp2 : register(s2); // texture 2 is the per-surface baseColor map @@ -39,7 +40,8 @@ uniform sampler2D samp4 : register(s4); // texture 5 is unused uniform samplerCUBE samp7 : register(s7); // texture 6 is the irradiance cube map uniform samplerCUBE samp8 : register(s8); // texture 7 is the radiance cube map -struct PS_IN { +struct PS_IN +{ half4 position : VPOS; half4 texcoord0 : TEXCOORD0_centroid; half4 texcoord1 : TEXCOORD1_centroid; @@ -51,9 +53,11 @@ struct PS_IN { half4 color : COLOR0; }; -struct PS_OUT { +struct PS_OUT +{ half4 color : COLOR; }; +// *INDENT-ON* void main( PS_IN fragment, out PS_OUT result ) { @@ -82,15 +86,15 @@ void main( PS_IN fragment, out PS_OUT result ) //half3 specularContribution = _half3( pow( abs( hDotN ), specularPower ) ); //half3 diffuseColor = diffuseMap * ( rpDiffuseModifier.xyz ) * 1.5f; - //half3 specularColor = specMap.xyz * specularContribution * ( rpSpecularModifier.xyz ); - + //half3 specularColor = specMap.xyz * specularContribution * ( rpSpecularModifier.xyz ); + // RB: http://developer.valvesoftware.com/wiki/Half_Lambert //float halfLdotN = dot3( localNormal, lightVector ) * 0.5 + 0.5; //halfLdotN *= halfLdotN; - + // traditional very dark Lambert light model used in Doom 3 //float ldotN = dot3( localNormal, lightVector ); - + float3 globalNormal; globalNormal.x = dot3( localNormal, fragment.texcoord4 ); globalNormal.y = dot3( localNormal, fragment.texcoord5 ); @@ -100,7 +104,8 @@ void main( PS_IN fragment, out PS_OUT result ) float3 reflectionVector = globalNormal * dot3( globalEye, globalNormal ); reflectionVector = ( reflectionVector * 2.0f ) - globalEye; - + + half vDotN = saturate( dot3( globalEye, globalNormal ) ); #if defined( USE_PBR ) const half metallic = specMapSRGB.g; @@ -109,16 +114,19 @@ void main( PS_IN fragment, out PS_OUT result ) // 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) - + // approximate non-metals with linear RGB 0.04 which is 0.08 * 0.5 (default in UE4) const half3 dielectricColor = half3( 0.04 ); - + // derive diffuse and specular from albedo(m) base color const half3 baseColor = diffuseMap; - + half3 diffuseColor = baseColor * ( 1.0 - metallic ); half3 specularColor = lerp( dielectricColor, baseColor, metallic ); + float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness ); + float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ) * ( 1.0 - metallic ); + #if defined( DEBUG_PBR ) diffuseColor = half3( 0.0, 0.0, 0.0 ); specularColor = half3( 0.0, 1.0, 0.0 ); @@ -127,47 +135,63 @@ void main( PS_IN fragment, out PS_OUT result ) #else // HACK calculate roughness from D3 gloss maps float Y = dot( LUMINANCE_SRGB.rgb, specMapSRGB.rgb ); - + //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; + float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness ); + + // metalness is missing + float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ); + #if defined( DEBUG_PBR ) diffuseColor = half3( 0.0, 0.0, 0.0 ); specularColor = half3( 1.0, 0.0, 0.0 ); #endif #endif - - float3 diffuseLight = ( texCUBE( samp7, globalNormal ).rgb ) * diffuseColor * ( rpDiffuseModifier.xyz ) * 3.5; - - float mip = clamp( ( roughness * 7.0 ) + 0.0, 0.0, 10.0 ); - float3 envColor = ( textureLod( samp8, reflectionVector, mip ).rgb ) * ( rpSpecularModifier.xyz ) * 0.5; - - float3 specularLight = envColor * specularColor; - - // add glossy fresnel - half hDotN = saturate( dot3( globalEye, globalNormal ) ); - - half3 specularColor2 = half3( 0.0 ); - float3 glossyFresnel = Fresnel_Glossy( specularColor2, roughness, hDotN ); - - // horizon fade + float3 ao = float3( 1.0, 1.0, 1.0 ); + + // evaluate diffuse IBL + + float3 irradiance = texCUBE( samp7, globalNormal ).rgb; + float3 diffuseLight = ( kD * irradiance * diffuseColor ) * ( rpDiffuseModifier.xyz * 3.0 ); + + // evaluate specular IBL + + // should be 4.0 + const float MAX_REFLECTION_LOD = 10.0; + float mip = clamp( ( roughness * MAX_REFLECTION_LOD ) + 0.0, 0.0, 10.0 ); + float3 radiance = textureLod( samp8, reflectionVector, mip ).rgb; + + // our LUT is upside down + float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg; + //float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0), 1.0 - roughness ) ).rg; + +#if 0 + result.color.rgb = float3( envBRDF.x, envBRDF.y, 0.0 ); + result.color.w = fragment.color.a; + return; +#endif + + float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * ( rpSpecularModifier.xyz * 0.75 ); + +#if 0 + // Marmoset Horizon Fade trick const half horizonFade = 1.3; half horiz = saturate( 1.0 + horizonFade * saturate( dot3( reflectionVector, globalNormal ) ) ); horiz *= horiz; //horiz = clamp( horiz, 0.0, 1.0 ); - - //specularLight = glossyFresnel * envColor; - specularLight += glossyFresnel * envColor * ( rpSpecularModifier.xyz ) * 0.9 * horiz; +#endif half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb ); - + //result.color.rgb = diffuseLight; //result.color.rgb = diffuseLight * lightColor; //result.color.rgb = specularLight; diff --git a/base/renderprogs/postprocess.ps.hlsl b/base/renderprogs/postprocess.ps.hlsl index b0d0e81b..08e6a806 100644 --- a/base/renderprogs/postprocess.ps.hlsl +++ b/base/renderprogs/postprocess.ps.hlsl @@ -47,6 +47,7 @@ struct PS_OUT // *INDENT-ON* #define USE_CHROMATIC_ABERRATION 1 +#define Chromatic_Amount 0.075 #define USE_TECHNICOLOR 0 // [0 or 1] @@ -146,7 +147,7 @@ float3 SpectrumOffset( float t ) void ChromaticAberrationPass( inout float4 color ) { - float amount = 0.1; //color.a * 1.0; //rpUser0.x; + float amount = Chromatic_Amount; //color.a * 1.0; //rpUser0.x; float3 sum = float3( 0.0 ); float3 sumColor = float3( 0.0 ); diff --git a/neo/astyle-code.bat b/neo/astyle-code.bat index ea40b02a..fb27417d 100644 --- a/neo/astyle-code.bat +++ b/neo/astyle-code.bat @@ -4,6 +4,7 @@ astyle.exe -v --formatted --options=astyle-options.ini --exclude="libs" --exclud astyle.exe -v --formatted --options=astyle-options.ini --recursive libs/imgui/*.h astyle.exe -v --formatted --options=astyle-options.ini --recursive libs/imgui/*.cpp +astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/ambient_lighting_IBL.ps.hlsl astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/postprocess.ps.hlsl astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/AmbientOcclusion_AO.ps.hlsl astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/AmbientOcclusion_blur.ps.hlsl diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 00356701..c0048971 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -1704,8 +1704,8 @@ void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const view } // RB end - //float lightScale = r_useHDR.GetBool() ? 3.0f : r_lightScale.GetFloat(); - float lightScale = r_lightScale.GetFloat(); + float lightScale = r_useHDR.GetBool() ? r_lightScale.GetFloat() * 0.666f : r_lightScale.GetFloat(); + //float lightScale = r_lightScale.GetFloat(); for( int lightStageNum = 0; lightStageNum < lightShader->GetNumStages(); lightStageNum++ ) { diff --git a/neo/renderer/RenderProgs_embedded.h b/neo/renderer/RenderProgs_embedded.h index c258f09d..51bbc889 100644 --- a/neo/renderer/RenderProgs_embedded.h +++ b/neo/renderer/RenderProgs_embedded.h @@ -1742,7 +1742,7 @@ static const cgShaderDef_t cg_renderprogs[] = "===========================================================================\n" "\n" "Doom 3 BFG Edition GPL Source Code\n" - "Copyright (C) 2014 Robert Beckebans\n" + "Copyright (C) 2014-2020 Robert Beckebans\n" "\n" "This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\"). \n" "\n" @@ -1795,14 +1795,23 @@ static const cgShaderDef_t cg_renderprogs[] = "\n" "// Fresnel term F( v, h )\n" "// Fnone( v, h ) = F(0°) = specularColor\n" - "half3 Fresnel_Schlick( half3 specularColor, half vdotH )\n" + "half3 Fresnel_Schlick( half3 specularColor, half vDotN )\n" "{\n" - " return specularColor + ( 1.0 - specularColor ) * pow( 1.0 - vdotH, 5.0 );\n" + " return specularColor + ( 1.0 - specularColor ) * pow( 1.0 - vDotN, 5.0 );\n" "}\n" "\n" - "half3 Fresnel_Glossy( half3 specularColor, half roughness, half vdotH )\n" + "// Fresnel term that takes roughness into account so rough non-metal surfaces aren't too shiny [Lagarde11]\n" + "half3 Fresnel_SchlickRoughness( half3 specularColor, half vDotN, half roughness )\n" "{\n" - " return specularColor + ( max( half3( 1.0 - roughness ), specularColor ) - specularColor ) * pow( 1.0 - vdotH, 5.0 );\n" + " return specularColor + ( max( half3( 1.0 - roughness ), specularColor ) - specularColor ) * pow( 1.0 - vDotN, 5.0 );\n" + "}\n" + "\n" + "// Sébastien Lagarde proposes an empirical approach to derive the specular occlusion term from the diffuse occlusion term in [Lagarde14].\n" + "// The result does not have any physical basis but produces visually pleasant results.\n" + "// See Sébastien Lagarde and Charles de Rousiers. 2014. Moving Frostbite to PBR.\n" + "float ComputeSpecularAO( float vDotN, float ao, float roughness)\n" + "{\n" + " return clamp( pow( vDotN + ao, exp2( -16.0 * roughness - 1.0) ) - 1.0 + ao, 0.0, 1.0 );\n" "}\n" "\n" "// Visibility term G( l, v, h )\n" @@ -2196,10 +2205,10 @@ static const cgShaderDef_t cg_renderprogs[] = "===========================================================================\n" "\n" "Doom 3 BFG Edition GPL Source Code\n" - "Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. \n" + "Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n" "Copyright (C) 2013-2020 Robert Beckebans\n" "\n" - "This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\"). \n" + "This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n" "\n" "Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" @@ -2224,16 +2233,18 @@ static const cgShaderDef_t cg_renderprogs[] = "#include \"global.inc.hlsl\"\n" "#include \"BRDF.inc.hlsl\"\n" "\n" + "// *INDENT-OFF*\n" "uniform sampler2D samp0 : register(s0); // texture 1 is the per-surface normal map\n" "uniform sampler2D samp1 : register(s1); // texture 3 is the per-surface specular or roughness/metallic/AO mixer map\n" "uniform sampler2D samp2 : register(s2); // texture 2 is the per-surface baseColor map \n" - "uniform sampler2D samp3 : register(s3); // texture 4 is the light falloff texture\n" - "uniform sampler2D samp4 : register(s4); // texture 5 is the light projection texture\n" + "uniform sampler2D samp3 : register(s3); // texture 4 is the BRDF LUT\n" + "uniform sampler2D samp4 : register(s4); // texture 5 is unused\n" "\n" - "uniform samplerCUBE samp7 : register(s7); // texture 0 is the cube map\n" - "uniform samplerCUBE samp8 : register(s8); // texture 0 is the cube map\n" + "uniform samplerCUBE samp7 : register(s7); // texture 6 is the irradiance cube map\n" + "uniform samplerCUBE samp8 : register(s8); // texture 7 is the radiance cube map\n" "\n" - "struct PS_IN {\n" + "struct PS_IN \n" + "{\n" " half4 position : VPOS;\n" " half4 texcoord0 : TEXCOORD0_centroid;\n" " half4 texcoord1 : TEXCOORD1_centroid;\n" @@ -2245,9 +2256,11 @@ static const cgShaderDef_t cg_renderprogs[] = " half4 color : COLOR0;\n" "};\n" "\n" - "struct PS_OUT {\n" + "struct PS_OUT\n" + "{\n" " half4 color : COLOR;\n" "};\n" + "// *INDENT-ON*\n" "\n" "void main( PS_IN fragment, out PS_OUT result )\n" "{\n" @@ -2276,15 +2289,15 @@ static const cgShaderDef_t cg_renderprogs[] = " //half3 specularContribution = _half3( pow( abs( hDotN ), specularPower ) );\n" "\n" " //half3 diffuseColor = diffuseMap * ( rpDiffuseModifier.xyz ) * 1.5f;\n" - " //half3 specularColor = specMap.xyz * specularContribution * ( rpSpecularModifier.xyz ); \n" - " \n" + " //half3 specularColor = specMap.xyz * specularContribution * ( rpSpecularModifier.xyz );\n" + "\n" " // RB: http://developer.valvesoftware.com/wiki/Half_Lambert\n" " //float halfLdotN = dot3( localNormal, lightVector ) * 0.5 + 0.5;\n" " //halfLdotN *= halfLdotN;\n" - " \n" + "\n" " // traditional very dark Lambert light model used in Doom 3\n" " //float ldotN = dot3( localNormal, lightVector );\n" - " \n" + "\n" " float3 globalNormal;\n" " globalNormal.x = dot3( localNormal, fragment.texcoord4 );\n" " globalNormal.y = dot3( localNormal, fragment.texcoord5 );\n" @@ -2294,7 +2307,8 @@ static const cgShaderDef_t cg_renderprogs[] = "\n" " float3 reflectionVector = globalNormal * dot3( globalEye, globalNormal );\n" " reflectionVector = ( reflectionVector * 2.0f ) - globalEye;\n" - " \n" + "\n" + " half vDotN = saturate( dot3( globalEye, globalNormal ) );\n" "\n" "#if defined( USE_PBR )\n" " const half metallic = specMapSRGB.g;\n" @@ -2303,16 +2317,19 @@ static const cgShaderDef_t cg_renderprogs[] = "\n" " // the vast majority of real-world materials (anything not metal or gems) have F(0°)\n" " // values in a very narrow range (~0.02 - 0.08)\n" - " \n" + "\n" " // approximate non-metals with linear RGB 0.04 which is 0.08 * 0.5 (default in UE4)\n" " const half3 dielectricColor = half3( 0.04 );\n" - " \n" + "\n" " // derive diffuse and specular from albedo(m) base color\n" " const half3 baseColor = diffuseMap;\n" - " \n" + "\n" " half3 diffuseColor = baseColor * ( 1.0 - metallic );\n" " half3 specularColor = lerp( dielectricColor, baseColor, metallic );\n" "\n" + " float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );\n" + " float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ) * ( 1.0 - metallic );\n" + "\n" "#if defined( DEBUG_PBR )\n" " diffuseColor = half3( 0.0, 0.0, 0.0 );\n" " specularColor = half3( 0.0, 1.0, 0.0 );\n" @@ -2321,47 +2338,63 @@ static const cgShaderDef_t cg_renderprogs[] = "#else\n" " // HACK calculate roughness from D3 gloss maps\n" " float Y = dot( LUMINANCE_SRGB.rgb, specMapSRGB.rgb );\n" - " \n" + "\n" " //const float glossiness = clamp( 1.0 - specMapSRGB.r, 0.0, 0.98 );\n" " const float glossiness = clamp( pow( Y, 1.0 / 2.0 ), 0.0, 0.98 );\n" - " \n" + "\n" " const float roughness = 1.0 - glossiness;\n" - " \n" + "\n" " half3 diffuseColor = diffuseMap;\n" " half3 specularColor = specMap.rgb;\n" "\n" + " float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );\n" + "\n" + " // metalness is missing\n" + " float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS );\n" + "\n" "#if defined( DEBUG_PBR )\n" " diffuseColor = half3( 0.0, 0.0, 0.0 );\n" " specularColor = half3( 1.0, 0.0, 0.0 );\n" "#endif\n" "\n" "#endif\n" - " \n" - " float3 diffuseLight = ( texCUBE( samp7, globalNormal ).rgb ) * diffuseColor * ( rpDiffuseModifier.xyz ) * 3.5;\n" - " \n" - " float mip = clamp( ( roughness * 7.0 ) + 0.0, 0.0, 10.0 );\n" - " float3 envColor = ( textureLod( samp8, reflectionVector, mip ).rgb ) * ( rpSpecularModifier.xyz ) * 0.5;\n" - " \n" - " float3 specularLight = envColor * specularColor;\n" - " \n" "\n" - " // add glossy fresnel\n" - " half hDotN = saturate( dot3( globalEye, globalNormal ) );\n" - " \n" - " half3 specularColor2 = half3( 0.0 );\n" - " float3 glossyFresnel = Fresnel_Glossy( specularColor2, roughness, hDotN );\n" - " \n" - " // horizon fade\n" + " float3 ao = float3( 1.0, 1.0, 1.0 );\n" + "\n" + " // evaluate diffuse IBL\n" + "\n" + " float3 irradiance = texCUBE( samp7, globalNormal ).rgb;\n" + " float3 diffuseLight = ( kD * irradiance * diffuseColor ) * ( rpDiffuseModifier.xyz * 3.0 );\n" + "\n" + " // evaluate specular IBL\n" + "\n" + " // should be 4.0\n" + " const float MAX_REFLECTION_LOD = 10.0;\n" + " float mip = clamp( ( roughness * MAX_REFLECTION_LOD ) + 0.0, 0.0, 10.0 );\n" + " float3 radiance = textureLod( samp8, reflectionVector, mip ).rgb;\n" + "\n" + " // our LUT is upside down\n" + " float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg;\n" + " //float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0), 1.0 - roughness ) ).rg;\n" + "\n" + "#if 0\n" + " result.color.rgb = float3( envBRDF.x, envBRDF.y, 0.0 );\n" + " result.color.w = fragment.color.a;\n" + " return;\n" + "#endif\n" + "\n" + " float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * ( rpSpecularModifier.xyz * 0.75 );\n" + "\n" + "#if 0\n" + " // Marmoset Horizon Fade trick\n" " const half horizonFade = 1.3;\n" " half horiz = saturate( 1.0 + horizonFade * saturate( dot3( reflectionVector, globalNormal ) ) );\n" " horiz *= horiz;\n" " //horiz = clamp( horiz, 0.0, 1.0 );\n" - " \n" - " //specularLight = glossyFresnel * envColor;\n" - " specularLight += glossyFresnel * envColor * ( rpSpecularModifier.xyz ) * 0.9 * horiz;\n" + "#endif\n" "\n" " half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n" - " \n" + "\n" " //result.color.rgb = diffuseLight;\n" " //result.color.rgb = diffuseLight * lightColor;\n" " //result.color.rgb = specularLight;\n" @@ -8688,7 +8721,7 @@ static const cgShaderDef_t cg_renderprogs[] = " const float roughness = 1.0 - glossiness;\n" " \n" " half3 diffuseColor = diffuseMap;\n" - " half3 specularColor = specMap.rgb;\n" + " half3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat\n" "#endif\n" "\n" " \n" @@ -9691,6 +9724,7 @@ static const cgShaderDef_t cg_renderprogs[] = " }\n" " \n" " shadow *= stepSize;\n" + "\n" "#elif 1\n" " \n" " const float2 poissonDisk[12] = float2[](\n" @@ -9773,7 +9807,7 @@ static const cgShaderDef_t cg_renderprogs[] = " const float roughness = 1.0 - glossiness;\n" " \n" " half3 diffuseColor = diffuseMap;\n" - " half3 specularColor = specMap.rgb;\n" + " half3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat\n" "#endif\n" "\n" " \n" @@ -10225,7 +10259,8 @@ static const cgShaderDef_t cg_renderprogs[] = "\n" "Doom 3 BFG Edition GPL Source Code\n" "Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n" - "Copyright (C) 2015 Robert Beckebans\n" + "Copyright (C) 2015-2020 Robert Beckebans\n" + "Copyright (C) 2014 Timothy Lottes (AMD)\n" "\n" "This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n" "\n" @@ -10267,7 +10302,10 @@ static const cgShaderDef_t cg_renderprogs[] = "};\n" "// *INDENT-ON*\n" "\n" - "#define USE_TECHNICOLOR 1 // [0 or 1]\n" + "#define USE_CHROMATIC_ABERRATION 1\n" + "#define Chromatic_Amount 0.075\n" + "\n" + "#define USE_TECHNICOLOR 0 // [0 or 1]\n" "\n" "#define Technicolor_Amount 0.5 // [0.00 to 1.00]\n" "#define Technicolor_Power 4.0 // [0.00 to 8.00]\n" @@ -10275,11 +10313,11 @@ static const cgShaderDef_t cg_renderprogs[] = "#define Technicolor_GreenNegativeAmount 0.88 // [0.00 to 1.00]\n" "#define Technicolor_BlueNegativeAmount 0.88 // [0.00 to 1.00]\n" "\n" - "#define USE_VIBRANCE 1\n" + "#define USE_VIBRANCE 0\n" "#define Vibrance 0.5 // [-1.00 to 1.00]\n" "#define Vibrance_RGB_Balance float3( 1.0, 1.0, 1.0 )\n" "\n" - "#define USE_FILMGRAIN 1\n" + "#define USE_DITHERING 1\n" "\n" "float3 overlay( float3 a, float3 b )\n" "{\n" @@ -10333,29 +10371,307 @@ static const cgShaderDef_t cg_renderprogs[] = "}\n" "\n" "\n" - "void FilmgrainPass( inout float4 color )\n" + "// CHROMATIC ABBERATION\n" + "\n" + "float2 BarrelDistortion( float2 xy, float amount )\n" "{\n" - " float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;\n" - " //float4 jitterTC = ( fragment.position * ( 1.0 / 128.0 ) ) + rpJitterTexOffset;\n" - " //float2 jitterTC = fragment.position.xy * 2.0;\n" - " //jitterTC.x *= rpWindowCoord.y / rpWindowCoord.x;\n" + " float2 cc = xy - 0.5;\n" + " float dist = dot2( cc, cc );\n" "\n" - " float4 noiseColor = tex2D( samp1, fragment.position.xy + jitterTC.xy );\n" - " float Y = noiseColor.r;\n" - " //float Y = dot( LUMINANCE_VECTOR, noiseColor );\n" - " //noiseColor.rgb = float3( Y, Y, Y );\n" - "\n" - " float exposureFactor = 1.0;\n" - " exposureFactor = sqrt( exposureFactor );\n" - " const float noiseIntensity = 1.7; //rpScreenCorrectionFactor.z;\n" - "\n" - " float t = lerp( 3.5 * noiseIntensity, 1.13 * noiseIntensity, exposureFactor );\n" - " color.rgb = overlay( color.rgb, lerp( float3( 0.5 ), noiseColor.rgb, t ) );\n" - "\n" - " //color.rgb = noiseColor.rgb;\n" - " //color.rgb = lerp( color.rgb, noiseColor.rgb, 0.3 );\n" + " return xy + cc * dist * amount;\n" "}\n" "\n" + "float Linterp( float t )\n" + "{\n" + " return saturate( 1.0 - abs( 2.0 * t - 1.0 ) );\n" + "}\n" + "\n" + "float Remap( float t, float a, float b )\n" + "{\n" + " return saturate( ( t - a ) / ( b - a ) );\n" + "}\n" + "\n" + "float3 SpectrumOffset( float t )\n" + "{\n" + " float lo = step( t, 0.5 );\n" + " float hi = 1.0 - lo;\n" + " float w = Linterp( Remap( t, 1.0 / 6.0, 5.0 / 6.0 ) );\n" + " float3 ret = float3( lo, 1.0, hi ) * float3( 1.0 - w, w, 1.0 - w );\n" + "\n" + " return pow( ret, float3( 1.0 / 2.2 ) );\n" + "}\n" + "\n" + "void ChromaticAberrationPass( inout float4 color )\n" + "{\n" + " float amount = Chromatic_Amount; //color.a * 1.0; //rpUser0.x;\n" + "\n" + " float3 sum = float3( 0.0 );\n" + " float3 sumColor = float3( 0.0 );\n" + "\n" + " //float samples = rpOverbright.x;\n" + " float samples = 12.0; // * 2;\n" + "\n" + " for( float i = 0.0; i < samples; i = i + 1.0 )\n" + " {\n" + " //float t = ( ( i / ( samples - 1.0 ) ) - 0.5 );\n" + " float t = ( i / ( samples - 1.0 ) );\n" + " //float t = log( i / ( samples - 1.0 ) );\n" + "\n" + " float3 so = SpectrumOffset( t );\n" + "\n" + " sum += so.xyz;\n" + " sumColor += so * tex2D( samp0, BarrelDistortion( fragment.texcoord0, ( 0.5 * amount * t ) ) ).rgb;\n" + " }\n" + "\n" + " color.rgb = ( sumColor / sum );\n" + " //color.rgb = lerp(color.rgb, (sumColor / sum), Technicolor_Amount);\n" + "}\n" + "\n" + "\n" + "\n" + "// https://gpuopen.com/vdr-follow-up-fine-art-of-film-grain/\n" + "\n" + "//\n" + "// TEMPORAL DITHERING TEST IN LINEAR\n" + "//\n" + "\n" + "//\n" + "// This is biased (saturates + adds contrast) because dithering done in non-linear space.\n" + "//\n" + "\n" + "// Shows proper dithering of a signal (overlapping of dither between bands).\n" + "// Results in about a 1-stop improvement in dynamic range over conventional dither\n" + "// which does not overlap dither across bands\n" + "// (try \"#define WIDE 0.5\" to see the difference below).\n" + "//\n" + "// This would work a lot better with a proper random number generator (flicker etc is bad).\n" + "// Sorry there is a limit to what can be done easily in shadertoy.\n" + "//\n" + "// Proper dithering algorithm,\n" + "//\n" + "// color = floor(color * steps + noise) * (1.0/(steps-1.0))\n" + "//\n" + "// Where,\n" + "//\n" + "// color ... output color {0 to 1}\n" + "// noise ... random number between {-1 to 1}\n" + "// steps ... quantization steps, ie 8-bit = 256\n" + "//\n" + "// The noise in this case is shaped by a high pass filter.\n" + "// This is to produce a better quality temporal dither.\n" + "\n" + "// Scale the width of the dither\n" + "\n" + "//-----------------------------------------------------------------------\n" + "\n" + "float Linear1( float c )\n" + "{\n" + " return ( c <= 0.04045 ) ? c / 12.92 : pow( ( c + 0.055 ) / 1.055, 2.4 );\n" + "}\n" + "\n" + "float3 Linear3( float3 c )\n" + "{\n" + " return float3( Linear1( c.r ), Linear1( c.g ), Linear1( c.b ) );\n" + "}\n" + "\n" + "float Srgb1( float c )\n" + "{\n" + " return ( c < 0.0031308 ? c * 12.92 : 1.055 * pow( c, 0.41666 ) - 0.055 );\n" + "}\n" + "\n" + "float3 Srgb3( float3 c )\n" + "{\n" + " return float3( Srgb1( c.r ), Srgb1( c.g ), Srgb1( c.b ) );\n" + "}\n" + "\n" + "float3 photoLuma = float3( 0.2126, 0.7152, 0.0722 );\n" + "float PhotoLuma( float3 c )\n" + "{\n" + " return dot( c, photoLuma );\n" + "}\n" + "\n" + "//note: works for structured patterns too\n" + "// [0;1[\n" + "float RemapNoiseTriErp( const float v )\n" + "{\n" + " float r2 = 0.5 * v;\n" + " float f1 = sqrt( r2 );\n" + " float f2 = 1.0 - sqrt( r2 - 0.25 );\n" + " return ( v < 0.5 ) ? f1 : f2;\n" + "}\n" + "\n" + "#if 1\n" + "float Noise( float2 n, float x )\n" + "{\n" + " // golden ratio\n" + " n += x;// * 1.61803398875;\n" + " return fract( sin( dot( n.xy, float2( 12.9898, 78.233 ) ) ) * 43758.5453 ) * 2.0 - 1.0;\n" + "}\n" + "\n" + "#else\n" + "\n" + "//note: returns [-intensity;intensity[, magnitude of 2x intensity\n" + "//note: from \"NEXT GENERATION POST PROCESSING IN CALL OF DUTY: ADVANCED WARFARE\"\n" + "// http://advances.realtimerendering.com/s2014/index.html\n" + "//float InterleavedGradientNoise( vec2 uv )\n" + "float Noise( float2 uv, float x )\n" + "{\n" + " // RB: golden ratio\n" + " uv += x;// * 1.61803398875;\n" + "\n" + " const float3 magic = vec3( 0.06711056, 0.00583715, 52.9829189 );\n" + " float rnd = fract( magic.z * fract( dot( uv, magic.xy ) ) );\n" + "\n" + " //rnd = RemapNoiseTriErp(rnd) * 2.0 - 0.5;\n" + "\n" + " return rnd;\n" + "}\n" + "#endif\n" + "\n" + "// Step 1 in generation of the dither source texture.\n" + "float Step1( float2 uv, float n )\n" + "{\n" + " float a = 1.0, b = 2.0, c = -12.0, t = 1.0;\n" + " return ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * (\n" + " Noise( uv + float2( -1.0, -1.0 ) * t, n ) * a +\n" + " Noise( uv + float2( 0.0, -1.0 ) * t, n ) * b +\n" + " Noise( uv + float2( 1.0, -1.0 ) * t, n ) * a +\n" + " Noise( uv + float2( -1.0, 0.0 ) * t, n ) * b +\n" + " Noise( uv + float2( 0.0, 0.0 ) * t, n ) * c +\n" + " Noise( uv + float2( 1.0, 0.0 ) * t, n ) * b +\n" + " Noise( uv + float2( -1.0, 1.0 ) * t, n ) * a +\n" + " Noise( uv + float2( 0.0, 1.0 ) * t, n ) * b +\n" + " Noise( uv + float2( 1.0, 1.0 ) * t, n ) * a +\n" + " 0.0 );\n" + "}\n" + "\n" + "// Step 2 in generation of the dither source texture.\n" + "float Step2( float2 uv, float n )\n" + "{\n" + " float a = 1.0, b = 2.0, c = -2.0, t = 1.0;\n" + " return ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * (\n" + " Step1( uv + float2( -1.0, -1.0 ) * t, n ) * a +\n" + " Step1( uv + float2( 0.0, -1.0 ) * t, n ) * b +\n" + " Step1( uv + float2( 1.0, -1.0 ) * t, n ) * a +\n" + " Step1( uv + float2( -1.0, 0.0 ) * t, n ) * b +\n" + " Step1( uv + float2( 0.0, 0.0 ) * t, n ) * c +\n" + " Step1( uv + float2( 1.0, 0.0 ) * t, n ) * b +\n" + " Step1( uv + float2( -1.0, 1.0 ) * t, n ) * a +\n" + " Step1( uv + float2( 0.0, 1.0 ) * t, n ) * b +\n" + " Step1( uv + float2( 1.0, 1.0 ) * t, n ) * a +\n" + " 0.0 );\n" + "}\n" + "\n" + "// Used for stills.\n" + "float3 Step3( float2 uv )\n" + "{\n" + " float a = Step2( uv, 0.07 );\n" + " float b = Step2( uv, 0.11 );\n" + " float c = Step2( uv, 0.13 );\n" + "#if 0\n" + " // Monochrome can look better on stills.\n" + " return float3( a );\n" + "#else\n" + " return float3( a, b, c );\n" + "#endif\n" + "}\n" + "\n" + "// Used for temporal dither.\n" + "float3 Step3T( float2 uv )\n" + "{\n" + " float a = Step2( uv, 0.07 * fract( rpJitterTexOffset.z ) );\n" + " float b = Step2( uv, 0.11 * fract( rpJitterTexOffset.z ) );\n" + " float c = Step2( uv, 0.13 * fract( rpJitterTexOffset.z ) );\n" + " return float3( a, b, c );\n" + "}\n" + "\n" + "#define STEPS 12.0\n" + "\n" + "void DitheringPass( inout float4 fragColor )\n" + "{\n" + " float2 uv = fragment.position.xy;\n" + " float2 uv2 = fragment.texcoord0;\n" + " //float2 uv3 = float2( uv2.x, 1.0 - uv2.y );\n" + "\n" + " float3 color = fragColor.rgb;\n" + " //float3 color = tex2D(samp0, uv2).rgb;\n" + "\n" + "#if 0\n" + "// BOTTOM: Show bands.\n" + " if( uv2.y >= 0.975 )\n" + " {\n" + " color = float3( uv2.x );\n" + " color = floor( color * STEPS + Step3( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );\n" + " }\n" + " else if( uv2.y >= 0.95 )\n" + " {\n" + " color = float3( uv2.x );\n" + " color = floor( color * STEPS ) * ( 1.0 / ( STEPS - 1.0 ) );\n" + " }\n" + " else if( uv2.y >= 0.925 )\n" + " {\n" + " color = float3( uv2.x );\n" + " color = floor( color * STEPS + Step3T( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );\n" + " }\n" + " // TOP: Show dither texture.\n" + " else if( uv2.y >= 0.9 )\n" + " {\n" + " color = Step3( uv ) * 1.0 + 0.5;\n" + " }\n" + " else\n" + "#endif\n" + " {\n" + " color = Linear3( color );\n" + "\n" + " // Add grain in linear space.\n" + "#if 0\n" + " // Slow more correct solutions.\n" + "#if 1\n" + " // Too expensive.\n" + " // Helps understand the fast solutions.\n" + " float3 amount = Linear3( Srgb3( color ) + ( 4.0 / STEPS ) ) - color;\n" + "#else\n" + " // Less too expensive.\n" + " float luma = PhotoLuma( color );\n" + "\n" + " // Implement this as a texture lookup table.\n" + " float amount = Linear1( Srgb1( luma ) + ( 4.0 / STEPS ) ) - luma;\n" + "#endif\n" + "\n" + "#else\n" + " // Fast solutions.\n" + "#if 1\n" + " // Hack 1 (fastest).\n" + " // For HDR need saturate() around luma.\n" + " float luma = PhotoLuma( color );\n" + " float amount = mix(\n" + " Linear1( 4.0 / STEPS ),\n" + " Linear1( ( 4.0 / STEPS ) + 1.0 ) - 1.0,\n" + " luma );\n" + "#else\n" + " // Hack 2 (slower?).\n" + " // For HDR need saturate() around color in mix().\n" + " float3 amount = mix(\n" + " float3( Linear1( 4.0 / STEPS ) ),\n" + " float3( Linear1( ( 4.0 / STEPS ) + 1.0 ) - 1.0 ),\n" + " color );\n" + "#endif\n" + "\n" + "#endif\n" + " color += Step3T( uv ) * amount;\n" + "\n" + " // The following represents hardware linear->sRGB xform\n" + " // which happens on sRGB formatted render targets,\n" + " // except using a lot less bits/pixel.\n" + " color = max( float3( 0.0 ), color );\n" + " color = Srgb3( color );\n" + " color = floor( color * STEPS ) * ( 1.0 / ( STEPS - 1.0 ) );\n" + " }\n" + "\n" + " fragColor.rgb = color;\n" + "}\n" + "\n" + "\n" "\n" "void main( PS_IN fragment, out PS_OUT result )\n" "{\n" @@ -10364,6 +10680,10 @@ static const cgShaderDef_t cg_renderprogs[] = " // base color with tone mapping and other post processing applied\n" " float4 color = tex2D( samp0, tCoords );\n" "\n" + "#if USE_CHROMATIC_ABERRATION\n" + " ChromaticAberrationPass( color );\n" + "#endif\n" + "\n" "#if USE_TECHNICOLOR\n" " TechnicolorPass( color );\n" "#endif\n" @@ -10372,8 +10692,8 @@ static const cgShaderDef_t cg_renderprogs[] = " VibrancePass( color );\n" "#endif\n" "\n" - "#if USE_FILMGRAIN\n" - " FilmgrainPass( color );\n" + "#if USE_DITHERING\n" + " DitheringPass( color );\n" "#endif\n" "\n" " result.color = color;\n" @@ -12796,8 +13116,37 @@ static const cgShaderDef_t cg_renderprogs[] = "#endif\n" " \n" "#if defined(HDR_DEBUG)\n" - " //color = tex2D( samp1, float2( L, 0.0 ) );\n" - " color = tex2D( samp1, float2( dot( LUMINANCE_SRGB, color ), 0.0 ) );\n" + " // https://google.github.io/filament/Filament.md.html#figure_luminanceviz\n" + " \n" + " const float3 debugColors[16] = float3[](\n" + " float3(0.0, 0.0, 0.0), // black\n" + " float3(0.0, 0.0, 0.1647), // darkest blue\n" + " float3(0.0, 0.0, 0.3647), // darker blue\n" + " float3(0.0, 0.0, 0.6647), // dark blue\n" + " float3(0.0, 0.0, 0.9647), // blue\n" + " float3(0.0, 0.9255, 0.9255), // cyan\n" + " float3(0.0, 0.5647, 0.0), // dark green\n" + " float3(0.0, 0.7843, 0.0), // green\n" + " float3(1.0, 1.0, 0.0), // yellow\n" + " float3(0.90588, 0.75294, 0.0), // yellow-orange\n" + " float3(1.0, 0.5647, 0.0), // orange\n" + " float3(1.0, 0.0, 0.0), // bright red\n" + " float3(0.8392, 0.0, 0.0), // red\n" + " float3(1.0, 0.0, 1.0), // magenta\n" + " float3(0.6, 0.3333, 0.7882), // purple\n" + " float3(1.0, 1.0, 1.0) // white\n" + " );\n" + " \n" + " // The 5th color in the array (cyan) represents middle gray (18%)\n" + " // Every stop above or below middle gray causes a color shift\n" + " float v = log2( Y / 0.18 );\n" + " v = clamp( v + 5.0, 0.0, 15.0 );\n" + " int index = int( floor( v ) );\n" + " \n" + " color.rgb = lerp( debugColors[index], debugColors[ min(15, index + 1) ], fract( v ) );\n" + " \n" + " //color = tex2D( samp1, float2( L, 0.0 ) );\n" + " //color = tex2D( samp1, float2( dot( LUMINANCE_SRGB, color ), 0.0 ) );\n" "#endif\n" "\n" " result.color = color;\n"