diff --git a/PBR/interface/PBR_Renderer.hpp b/PBR/interface/PBR_Renderer.hpp index 79304aa7..51d6c5be 100644 --- a/PBR/interface/PBR_Renderer.hpp +++ b/PBR/interface/PBR_Renderer.hpp @@ -81,6 +81,9 @@ class PBR_Renderer /// instead of a combined physical description texture. bool UseSeparateMetallicRoughnessTextures = false; + /// Manually convert shader output to sRGB color space. + bool ConvertOutputToSRGB = false; + static const SamplerDesc DefaultSampler; /// Immutable sampler for color map texture. @@ -108,6 +111,28 @@ class PBR_Renderer /// Optional input layout description. InputLayoutDesc InputLayout; + + /// Conversion mode applied to diffuse, specular and emissive textures. + /// + /// \note Normal map, ambient occlusion and physical description textures are + /// always assumed to be in linear color space. + enum TEX_COLOR_CONVERSION_MODE + { + /// Sampled texture colors are used as is. + /// + /// \remarks This mode should be used if the textures are in linear color space, + /// or if the texture is in sRGB color space and the texture view is + /// also in sRGB color space (which ensures that sRGB->linear conversion + /// is performed by the GPU). + TEX_COLOR_CONVERSION_MODE_NONE = 0, + + /// Manually convert texture colors from sRGB to linear color space. + /// + /// \remarks This mode should be used if the textures are in sRGB color space, + /// but the texture views are in linear color space. + TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR, + }; + TEX_COLOR_CONVERSION_MODE TexColorConversionMode = TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR; }; enum ALPHA_MODE diff --git a/PBR/src/PBR_Renderer.cpp b/PBR/src/PBR_Renderer.cpp index 5e022e1e..772c134d 100644 --- a/PBR/src/PBR_Renderer.cpp +++ b/PBR/src/PBR_Renderer.cpp @@ -532,6 +532,7 @@ void PBR_Renderer::CreatePSO(IRenderDevice* pDevice, IRenderStateCache* pStateCa ShaderMacroHelper Macros; Macros.AddShaderMacro("MAX_JOINT_COUNT", static_cast(m_Settings.MaxJointCount)); Macros.AddShaderMacro("ALLOW_DEBUG_VIEW", m_Settings.AllowDebugView); + Macros.AddShaderMacro("CONVERT_OUTPUT_TO_SRGB", m_Settings.ConvertOutputToSRGB); Macros.AddShaderMacro("TONE_MAPPING_MODE", "TONE_MAPPING_MODE_UNCHARTED2"); Macros.AddShaderMacro("PBR_USE_IBL", m_Settings.UseIBL); Macros.AddShaderMacro("PBR_USE_AO", m_Settings.UseAO); @@ -546,6 +547,10 @@ void PBR_Renderer::CreatePSO(IRenderDevice* pDevice, IRenderStateCache* pStateCa Macros.AddShaderMacro("USE_HDR_IBL_CUBEMAPS", true); Macros.AddShaderMacro("USE_SEPARATE_METALLIC_ROUGHNESS_TEXTURES", m_Settings.UseSeparateMetallicRoughnessTextures); + Macros.AddShaderMacro("TEX_COLOR_CONVERSION_MODE_NONE", CreateInfo::TEX_COLOR_CONVERSION_MODE_NONE); + Macros.AddShaderMacro("TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR", CreateInfo::TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR); + Macros.AddShaderMacro("TEX_COLOR_CONVERSION_MODE", m_Settings.TexColorConversionMode); + ShaderCI.Macros = Macros; RefCntAutoPtr pVS; { diff --git a/Shaders/Common/public/SRGBUtilities.fxh b/Shaders/Common/public/SRGBUtilities.fxh new file mode 100644 index 00000000..4a90954f --- /dev/null +++ b/Shaders/Common/public/SRGBUtilities.fxh @@ -0,0 +1,50 @@ +#ifndef _SRGB_UTILITIES_FXH_ +#define _SRGB_UTILITIES_FXH_ + +float3 SRGBToLinear(float3 sRGB) +{ + float3 bLess = step(float3(0.04045, 0.04045, 0.04045), sRGB); + return lerp(sRGB / 12.92, + pow(saturate((sRGB + float3(0.055, 0.055, 0.055)) / 1.055), float3(2.4, 2.4, 2.4)), + bLess); +} + +float4 SRGBAToLinear(float4 sRGBA) +{ + return float4(SRGBToLinear(sRGBA.rgb), sRGBA.a); +} + +float3 FastSRGBToLinear(float3 sRGB) +{ + return pow(sRGB, float3(2.2, 2.2, 2.2)); +} + +float4 FastSRGBAToLinear(float4 sRGBA) +{ + return float4(FastSRGBToLinear(sRGBA.rgb), sRGBA.a); +} + +float3 LinearToSRGB(float3 RGB) +{ + float3 bGreater = step(float3(0.0031308, 0.0031308, 0.0031308), RGB); + return lerp(RGB * 12.92, + (pow(RGB, float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - float3(0.055, 0.055, 0.055), + bGreater); +} + +float4 LinearToSRGBA(float4 RGBA) +{ + return float4(LinearToSRGB(RGBA.rgb), RGBA.a); +} + +float3 FastLinearToSRGB(float3 RGB) +{ + return pow(RGB, float3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2)); +} + +float4 FastLinearToSRGBA(float4 RGBA) +{ + return float4(FastLinearToSRGB(RGBA.rgb), RGBA.a); +} + +#endif // _SRGB_UTILITIES_FXH_ diff --git a/Shaders/PBR/private/RenderPBR.psh b/Shaders/PBR/private/RenderPBR.psh index 736f60fb..929f5ad2 100644 --- a/Shaders/PBR/private/RenderPBR.psh +++ b/Shaders/PBR/private/RenderPBR.psh @@ -118,7 +118,7 @@ void main(in PbrVsOutput VSOut, { float4 BaseColor = SampleTexture(g_ColorMap, g_ColorMap_sampler, VSOut.UV0, VSOut.UV1, g_PBRAttribs.Material.BaseColorTextureUVSelector, g_PBRAttribs.Material.BaseColorUVScaleBias, g_PBRAttribs.Material.BaseColorSlice, float4(1.0, 1.0, 1.0, 1.0)); - BaseColor = SRGBtoLINEAR(BaseColor) * g_PBRAttribs.Material.BaseColorFactor; + BaseColor = float4(TO_LINEAR(BaseColor.rgb), BaseColor.a) * g_PBRAttribs.Material.BaseColorFactor; //BaseColor *= getVertexColor(); float2 NormalMapUV = lerp(VSOut.UV0, VSOut.UV1, g_PBRAttribs.Material.NormalTextureUVSelector); @@ -177,6 +177,7 @@ void main(in PbrVsOutput VSOut, #if PBR_USE_EMISSIVE Emissive = SampleTexture(g_EmissiveMap, g_EmissiveMap_sampler, VSOut.UV0, VSOut.UV1, g_PBRAttribs.Material.EmissiveTextureUVSelector, g_PBRAttribs.Material.EmissiveUVScaleBias, g_PBRAttribs.Material.EmissiveSlice, float4(0.0, 0.0, 0.0, 0.0)).rgb; + Emissive = TO_LINEAR(Emissive); #endif float4 PhysicalDesc = float4(0.0, 0.0, 0.0, 0.0); @@ -199,12 +200,13 @@ void main(in PbrVsOutput VSOut, float metallic; if (g_PBRAttribs.Material.Workflow == PBR_WORKFLOW_SPECULAR_GLOSINESS) { - PhysicalDesc.rgb = SRGBtoLINEAR(PhysicalDesc.rgb) * g_PBRAttribs.Material.SpecularFactor.rgb; + PhysicalDesc.rgb = TO_LINEAR(PhysicalDesc.rgb) * g_PBRAttribs.Material.SpecularFactor.rgb; const float u_GlossinessFactor = 1.0; PhysicalDesc.a *= u_GlossinessFactor; } else if(g_PBRAttribs.Material.Workflow == PBR_WORKFLOW_METALLIC_ROUGHNESS) { + // PhysicalDesc should already be in linear space PhysicalDesc.g = saturate(PhysicalDesc.g * g_PBRAttribs.Material.RoughnessFactor); PhysicalDesc.b = saturate(PhysicalDesc.b * g_PBRAttribs.Material.MetallicFactor); } @@ -257,8 +259,6 @@ void main(in PbrVsOutput VSOut, #endif #if PBR_USE_EMISSIVE - const float u_EmissiveFactor = 1.0; - Emissive = SRGBtoLINEAR(Emissive); color += Emissive.rgb * g_PBRAttribs.Material.EmissiveFactor.rgb * g_PBRAttribs.Renderer.EmissionScale; #endif @@ -278,25 +278,28 @@ void main(in PbrVsOutput VSOut, { switch (g_PBRAttribs.Renderer.DebugViewType) { - case 1: OutColor.rgba = BaseColor; break; - case 2: OutColor.rgba = float4(BaseColor.a, BaseColor.a, BaseColor.a, 1.0); break; - // Apply extra srgb->linear transform to make the maps look better - case 3: OutColor.rgb = SRGBtoLINEAR(TSNormal.xyz); break; - case 4: OutColor.rgb = SRGBtoLINEAR(Occlusion * float3(1.0, 1.0, 1.0)); break; - case 5: OutColor.rgb = SRGBtoLINEAR(Emissive.rgb); break; - case 6: OutColor.rgb = SRGBtoLINEAR(metallic * float3(1.0, 1.0, 1.0) ); break; - case 7: OutColor.rgb = SRGBtoLINEAR(SrfInfo.PerceptualRoughness * float3(1.0, 1.0, 1.0)); break; - case 8: OutColor.rgb = SrfInfo.DiffuseColor; break; - case 9: OutColor.rgb = SrfInfo.Reflectance0; break; - case 10: OutColor.rgb = SrfInfo.Reflectance90; break; - case 11: OutColor.rgb = SRGBtoLINEAR(abs(VSOut.Normal / max(length(VSOut.Normal), 1e-3))); break; - case 12: OutColor.rgb = SRGBtoLINEAR(abs(perturbedNormal)); break; - case 13: OutColor.rgb = dot(perturbedNormal, view) * float3(1.0, 1.0, 1.0); break; + case 1: OutColor.rgba = BaseColor; break; + case 2: OutColor.rgba = float4(BaseColor.a, BaseColor.a, BaseColor.a, 1.0); break; + case 3: OutColor.rgb = TSNormal.xyz; break; + case 4: OutColor.rgb = Occlusion * float3(1.0, 1.0, 1.0); break; + case 5: OutColor.rgb = Emissive.rgb; break; + case 6: OutColor.rgb = metallic * float3(1.0, 1.0, 1.0); break; + case 7: OutColor.rgb = SrfInfo.PerceptualRoughness * float3(1.0, 1.0, 1.0); break; + case 8: OutColor.rgb = SrfInfo.DiffuseColor; break; + case 9: OutColor.rgb = SrfInfo.Reflectance0; break; + case 10: OutColor.rgb = SrfInfo.Reflectance90; break; + case 11: OutColor.rgb = abs(VSOut.Normal / max(length(VSOut.Normal), 1e-3)); break; + case 12: OutColor.rgb = abs(perturbedNormal); break; + case 13: OutColor.rgb = dot(perturbedNormal, view) * float3(1.0, 1.0, 1.0); break; #if PBR_USE_IBL - case 14: OutColor.rgb = IBLContrib.f3Diffuse; break; - case 15: OutColor.rgb = IBLContrib.f3Specular; break; + case 14: OutColor.rgb = IBLContrib.f3Diffuse; break; + case 15: OutColor.rgb = IBLContrib.f3Specular; break; #endif } } #endif + +#if CONVERT_OUTPUT_TO_SRGB + OutColor.rgb = FastLinearToSRGB(OutColor.rgb); +#endif } diff --git a/Shaders/PBR/public/PBR_Shading.fxh b/Shaders/PBR/public/PBR_Shading.fxh index 693de134..8be15330 100644 --- a/Shaders/PBR/public/PBR_Shading.fxh +++ b/Shaders/PBR/public/PBR_Shading.fxh @@ -4,13 +4,24 @@ #include "PBR_Structures.fxh" #include "PBR_Common.fxh" #include "ShaderUtilities.fxh" +#include "SRGBUtilities.fxh" -#ifndef MANUAL_SRGB_TO_LINEAR -# define MANUAL_SRGB_TO_LINEAR 1 +#ifndef TEX_COLOR_CONVERSION_MODE_NONE +# define TEX_COLOR_CONVERSION_MODE_NONE 0 #endif -#ifndef SRGB_FAST_APPROXIMATION -# define SRGB_FAST_APPROXIMATION 1 +#ifndef TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR +# define TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR 1 +#endif + +#ifndef TEX_COLOR_CONVERSION_MODE +# define TEX_COLOR_CONVERSION_MODE TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR +#endif + +#if TEX_COLOR_CONVERSION_MODE == TEX_COLOR_CONVERSION_MODE_NONE +# define TO_LINEAR(x) (x) +#elif TEX_COLOR_CONVERSION_MODE == TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR +# define TO_LINEAR FastSRGBToLinear #endif #ifndef USE_IBL_ENV_MAP_LOD @@ -48,28 +59,6 @@ float SolveMetallic(float3 diffuse, return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0); } - -float3 SRGBtoLINEAR(float3 srgbIn) -{ -#if MANUAL_SRGB_TO_LINEAR -# if SRGB_FAST_APPROXIMATION - float3 linOut = pow(saturate(srgbIn.xyz), float3(2.2, 2.2, 2.2)); -# else - float3 bLess = step(float3(0.04045, 0.04045, 0.04045), srgbIn.xyz); - float3 linOut = mix( srgbIn.xyz/12.92, pow(saturate((srgbIn.xyz + float3(0.055, 0.055, 0.055)) / 1.055), float3(2.4, 2.4, 2.4)), bLess ); -# endif - return linOut; -#else - return srgbIn; -#endif -} - -float4 SRGBtoLINEAR(float4 srgbIn) -{ - return float4(SRGBtoLINEAR(srgbIn.xyz), srgbIn.w); -} - - float3 ApplyDirectionalLight(float3 lightDir, float3 lightColor, SurfaceReflectanceInfo srfInfo, float3 normal, float3 view) { float3 pointToLight = -lightDir; @@ -162,8 +151,8 @@ IBL_Contribution GetIBLContribution(in SurfaceReflectanceInfo SrfInfo, float3 diffuseLight = diffuseSample.rgb; float3 specularLight = specularSample.rgb; #else - float3 diffuseLight = SRGBtoLINEAR(diffuseSample).rgb; - float3 specularLight = SRGBtoLINEAR(specularSample).rgb; + float3 diffuseLight = TO_LINEAR(diffuseSample.rgb); + float3 specularLight = TO_LINEAR(specularSample.rgb); #endif IBL_Contribution IBLContrib; diff --git a/shaders_inc/PBR_Shading.fxh.h b/shaders_inc/PBR_Shading.fxh.h index 2d6050f3..d42390df 100644 --- a/shaders_inc/PBR_Shading.fxh.h +++ b/shaders_inc/PBR_Shading.fxh.h @@ -4,13 +4,24 @@ "#include \"PBR_Structures.fxh\"\n" "#include \"PBR_Common.fxh\"\n" "#include \"ShaderUtilities.fxh\"\n" +"#include \"SRGBUtilities.fxh\"\n" "\n" -"#ifndef MANUAL_SRGB_TO_LINEAR\n" -"# define MANUAL_SRGB_TO_LINEAR 1\n" +"#ifndef TEX_COLOR_CONVERSION_MODE_NONE\n" +"# define TEX_COLOR_CONVERSION_MODE_NONE 0\n" "#endif\n" "\n" -"#ifndef SRGB_FAST_APPROXIMATION\n" -"# define SRGB_FAST_APPROXIMATION 1\n" +"#ifndef TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR\n" +"# define TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR 1\n" +"#endif\n" +"\n" +"#ifndef TEX_COLOR_CONVERSION_MODE\n" +"# define TEX_COLOR_CONVERSION_MODE TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR\n" +"#endif\n" +"\n" +"#if TEX_COLOR_CONVERSION_MODE == TEX_COLOR_CONVERSION_MODE_NONE\n" +"# define TO_LINEAR(x) (x)\n" +"#elif TEX_COLOR_CONVERSION_MODE == TEX_COLOR_CONVERSION_MODE_SRGB_TO_LINEAR\n" +"# define TO_LINEAR FastSRGBToLinear\n" "#endif\n" "\n" "#ifndef USE_IBL_ENV_MAP_LOD\n" @@ -48,28 +59,6 @@ " return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0);\n" "}\n" "\n" -"\n" -"float3 SRGBtoLINEAR(float3 srgbIn)\n" -"{\n" -"#if MANUAL_SRGB_TO_LINEAR\n" -"# if SRGB_FAST_APPROXIMATION\n" -" float3 linOut = pow(saturate(srgbIn.xyz), float3(2.2, 2.2, 2.2));\n" -"# else\n" -" float3 bLess = step(float3(0.04045, 0.04045, 0.04045), srgbIn.xyz);\n" -" float3 linOut = mix( srgbIn.xyz/12.92, pow(saturate((srgbIn.xyz + float3(0.055, 0.055, 0.055)) / 1.055), float3(2.4, 2.4, 2.4)), bLess );\n" -"# endif\n" -" return linOut;\n" -"#else\n" -" return srgbIn;\n" -"#endif\n" -"}\n" -"\n" -"float4 SRGBtoLINEAR(float4 srgbIn)\n" -"{\n" -" return float4(SRGBtoLINEAR(srgbIn.xyz), srgbIn.w);\n" -"}\n" -"\n" -"\n" "float3 ApplyDirectionalLight(float3 lightDir, float3 lightColor, SurfaceReflectanceInfo srfInfo, float3 normal, float3 view)\n" "{\n" " float3 pointToLight = -lightDir;\n" @@ -162,8 +151,8 @@ " float3 diffuseLight = diffuseSample.rgb;\n" " float3 specularLight = specularSample.rgb;\n" "#else\n" -" float3 diffuseLight = SRGBtoLINEAR(diffuseSample).rgb;\n" -" float3 specularLight = SRGBtoLINEAR(specularSample).rgb;\n" +" float3 diffuseLight = TO_LINEAR(diffuseSample.rgb);\n" +" float3 specularLight = TO_LINEAR(specularSample.rgb);\n" "#endif\n" "\n" " IBL_Contribution IBLContrib;\n" diff --git a/shaders_inc/RenderPBR.psh.h b/shaders_inc/RenderPBR.psh.h index 26937ab6..4b8c96e4 100644 --- a/shaders_inc/RenderPBR.psh.h +++ b/shaders_inc/RenderPBR.psh.h @@ -118,7 +118,7 @@ "{\n" " float4 BaseColor = SampleTexture(g_ColorMap, g_ColorMap_sampler, VSOut.UV0, VSOut.UV1, g_PBRAttribs.Material.BaseColorTextureUVSelector,\n" " g_PBRAttribs.Material.BaseColorUVScaleBias, g_PBRAttribs.Material.BaseColorSlice, float4(1.0, 1.0, 1.0, 1.0));\n" -" BaseColor = SRGBtoLINEAR(BaseColor) * g_PBRAttribs.Material.BaseColorFactor;\n" +" BaseColor = float4(TO_LINEAR(BaseColor.rgb), BaseColor.a) * g_PBRAttribs.Material.BaseColorFactor;\n" " //BaseColor *= getVertexColor();\n" "\n" " float2 NormalMapUV = lerp(VSOut.UV0, VSOut.UV1, g_PBRAttribs.Material.NormalTextureUVSelector);\n" @@ -177,6 +177,7 @@ "#if PBR_USE_EMISSIVE\n" " Emissive = SampleTexture(g_EmissiveMap, g_EmissiveMap_sampler, VSOut.UV0, VSOut.UV1, g_PBRAttribs.Material.EmissiveTextureUVSelector,\n" " g_PBRAttribs.Material.EmissiveUVScaleBias, g_PBRAttribs.Material.EmissiveSlice, float4(0.0, 0.0, 0.0, 0.0)).rgb;\n" +" Emissive = TO_LINEAR(Emissive);\n" "#endif\n" "\n" " float4 PhysicalDesc = float4(0.0, 0.0, 0.0, 0.0);\n" @@ -199,12 +200,13 @@ " float metallic;\n" " if (g_PBRAttribs.Material.Workflow == PBR_WORKFLOW_SPECULAR_GLOSINESS)\n" " {\n" -" PhysicalDesc.rgb = SRGBtoLINEAR(PhysicalDesc.rgb) * g_PBRAttribs.Material.SpecularFactor.rgb;\n" +" PhysicalDesc.rgb = TO_LINEAR(PhysicalDesc.rgb) * g_PBRAttribs.Material.SpecularFactor.rgb;\n" " const float u_GlossinessFactor = 1.0;\n" " PhysicalDesc.a *= u_GlossinessFactor;\n" " }\n" " else if(g_PBRAttribs.Material.Workflow == PBR_WORKFLOW_METALLIC_ROUGHNESS)\n" " {\n" +" // PhysicalDesc should already be in linear space\n" " PhysicalDesc.g = saturate(PhysicalDesc.g * g_PBRAttribs.Material.RoughnessFactor);\n" " PhysicalDesc.b = saturate(PhysicalDesc.b * g_PBRAttribs.Material.MetallicFactor);\n" " }\n" @@ -257,8 +259,6 @@ "#endif\n" "\n" "#if PBR_USE_EMISSIVE\n" -" const float u_EmissiveFactor = 1.0;\n" -" Emissive = SRGBtoLINEAR(Emissive);\n" " color += Emissive.rgb * g_PBRAttribs.Material.EmissiveFactor.rgb * g_PBRAttribs.Renderer.EmissionScale;\n" "#endif\n" "\n" @@ -278,25 +278,28 @@ " {\n" " switch (g_PBRAttribs.Renderer.DebugViewType)\n" " {\n" -" case 1: OutColor.rgba = BaseColor; break;\n" -" case 2: OutColor.rgba = float4(BaseColor.a, BaseColor.a, BaseColor.a, 1.0); break;\n" -" // Apply extra srgb->linear transform to make the maps look better\n" -" case 3: OutColor.rgb = SRGBtoLINEAR(TSNormal.xyz); break;\n" -" case 4: OutColor.rgb = SRGBtoLINEAR(Occlusion * float3(1.0, 1.0, 1.0)); break;\n" -" case 5: OutColor.rgb = SRGBtoLINEAR(Emissive.rgb); break;\n" -" case 6: OutColor.rgb = SRGBtoLINEAR(metallic * float3(1.0, 1.0, 1.0) ); break;\n" -" case 7: OutColor.rgb = SRGBtoLINEAR(SrfInfo.PerceptualRoughness * float3(1.0, 1.0, 1.0)); break;\n" -" case 8: OutColor.rgb = SrfInfo.DiffuseColor; break;\n" -" case 9: OutColor.rgb = SrfInfo.Reflectance0; break;\n" -" case 10: OutColor.rgb = SrfInfo.Reflectance90; break;\n" -" case 11: OutColor.rgb = SRGBtoLINEAR(abs(VSOut.Normal / max(length(VSOut.Normal), 1e-3))); break;\n" -" case 12: OutColor.rgb = SRGBtoLINEAR(abs(perturbedNormal)); break;\n" -" case 13: OutColor.rgb = dot(perturbedNormal, view) * float3(1.0, 1.0, 1.0); break;\n" +" case 1: OutColor.rgba = BaseColor; break;\n" +" case 2: OutColor.rgba = float4(BaseColor.a, BaseColor.a, BaseColor.a, 1.0); break;\n" +" case 3: OutColor.rgb = TSNormal.xyz; break;\n" +" case 4: OutColor.rgb = Occlusion * float3(1.0, 1.0, 1.0); break;\n" +" case 5: OutColor.rgb = Emissive.rgb; break;\n" +" case 6: OutColor.rgb = metallic * float3(1.0, 1.0, 1.0); break;\n" +" case 7: OutColor.rgb = SrfInfo.PerceptualRoughness * float3(1.0, 1.0, 1.0); break;\n" +" case 8: OutColor.rgb = SrfInfo.DiffuseColor; break;\n" +" case 9: OutColor.rgb = SrfInfo.Reflectance0; break;\n" +" case 10: OutColor.rgb = SrfInfo.Reflectance90; break;\n" +" case 11: OutColor.rgb = abs(VSOut.Normal / max(length(VSOut.Normal), 1e-3)); break;\n" +" case 12: OutColor.rgb = abs(perturbedNormal); break;\n" +" case 13: OutColor.rgb = dot(perturbedNormal, view) * float3(1.0, 1.0, 1.0); break;\n" "#if PBR_USE_IBL\n" -" case 14: OutColor.rgb = IBLContrib.f3Diffuse; break;\n" -" case 15: OutColor.rgb = IBLContrib.f3Specular; break;\n" +" case 14: OutColor.rgb = IBLContrib.f3Diffuse; break;\n" +" case 15: OutColor.rgb = IBLContrib.f3Specular; break;\n" "#endif\n" " }\n" " }\n" "#endif\n" +"\n" +"#if CONVERT_OUTPUT_TO_SRGB\n" +" OutColor.rgb = FastLinearToSRGB(OutColor.rgb);\n" +"#endif\n" "}\n" diff --git a/shaders_inc/SRGBUtilities.fxh.h b/shaders_inc/SRGBUtilities.fxh.h new file mode 100644 index 00000000..2afd6fe8 --- /dev/null +++ b/shaders_inc/SRGBUtilities.fxh.h @@ -0,0 +1,50 @@ +"#ifndef _SRGB_UTILITIES_FXH_\n" +"#define _SRGB_UTILITIES_FXH_\n" +"\n" +"float3 SRGBToLinear(float3 sRGB)\n" +"{\n" +" float3 bLess = step(float3(0.04045, 0.04045, 0.04045), sRGB);\n" +" return lerp(sRGB / 12.92,\n" +" pow(saturate((sRGB + float3(0.055, 0.055, 0.055)) / 1.055), float3(2.4, 2.4, 2.4)),\n" +" bLess);\n" +"}\n" +"\n" +"float4 SRGBAToLinear(float4 sRGBA)\n" +"{\n" +" return float4(SRGBToLinear(sRGBA.rgb), sRGBA.a);\n" +"}\n" +"\n" +"float3 FastSRGBToLinear(float3 sRGB)\n" +"{\n" +" return pow(sRGB, float3(2.2, 2.2, 2.2));\n" +"}\n" +"\n" +"float4 FastSRGBAToLinear(float4 sRGBA)\n" +"{\n" +" return float4(FastSRGBToLinear(sRGBA.rgb), sRGBA.a);\n" +"}\n" +"\n" +"float3 LinearToSRGB(float3 RGB)\n" +"{\n" +" float3 bGreater = step(float3(0.0031308, 0.0031308, 0.0031308), RGB);\n" +" return lerp(RGB * 12.92,\n" +" (pow(RGB, float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - float3(0.055, 0.055, 0.055),\n" +" bGreater);\n" +"}\n" +"\n" +"float4 LinearToSRGBA(float4 RGBA)\n" +"{\n" +" return float4(LinearToSRGB(RGBA.rgb), RGBA.a);\n" +"}\n" +"\n" +"float3 FastLinearToSRGB(float3 RGB)\n" +"{\n" +" return pow(RGB, float3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));\n" +"}\n" +"\n" +"float4 FastLinearToSRGBA(float4 RGBA)\n" +"{\n" +" return float4(FastLinearToSRGB(RGBA.rgb), RGBA.a);\n" +"}\n" +"\n" +"#endif // _SRGB_UTILITIES_FXH_\n" diff --git a/shaders_inc/shaders_list.h b/shaders_inc/shaders_list.h index b473ffa7..1813279c 100644 --- a/shaders_inc/shaders_list.h +++ b/shaders_inc/shaders_list.h @@ -26,6 +26,10 @@ static const ShaderIncInfo g_Shaders[] = "PBR_Common.fxh", #include "PBR_Common.fxh.h" }, + { + "SRGBUtilities.fxh", + #include "SRGBUtilities.fxh.h" + }, { "ShaderUtilities.fxh", #include "ShaderUtilities.fxh.h"