#ifndef UNITY_PBS_LIGHTING_INCLUDED #define UNITY_PBS_LIGHTING_INCLUDED #include "UnityShaderVariables.cginc" #include "UnityStandardConfig.cginc" #include "UnityLightingCommon.cginc" #include "UnityGlobalIllumination.cginc" //------------------------------------------------------------------------------------- // Default BRDF to use: #if !defined (UNITY_BRDF_PBS) // allow to explicitly override BRDF in custom shader #if (SHADER_TARGET < 30) || defined(SHADER_API_PSP2) // Fallback to low fidelity one for pre-SM3.0 #define UNITY_BRDF_PBS BRDF3_Unity_PBS #elif defined(SHADER_API_MOBILE) // Somewhat simplified for mobile #define UNITY_BRDF_PBS BRDF2_Unity_PBS #else // Full quality for SM3+ PC / consoles #define UNITY_BRDF_PBS BRDF1_Unity_PBS #endif #endif //------------------------------------------------------------------------------------- // BRDF for lights extracted from *indirect* directional lightmaps (baked and realtime). // Baked directional lightmap with *direct* light uses UNITY_BRDF_PBS. // For better quality change to BRDF1_Unity_PBS. // No directional lightmaps in SM2.0. #if !defined(UNITY_BRDF_PBS_LIGHTMAP_INDIRECT) #define UNITY_BRDF_PBS_LIGHTMAP_INDIRECT BRDF2_Unity_PBS #endif #if !defined (UNITY_BRDF_GI) #define UNITY_BRDF_GI BRDF_Unity_Indirect #endif //------------------------------------------------------------------------------------- inline half3 BRDF_Unity_Indirect (half3 baseColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness, half3 normal, half3 viewDir, half occlusion, UnityGI gi) { half3 c = 0; #if defined(DIRLIGHTMAP_SEPARATE) gi.indirect.diffuse = 0; gi.indirect.specular = 0; #ifdef LIGHTMAP_ON c += UNITY_BRDF_PBS_LIGHTMAP_INDIRECT (baseColor, specColor, oneMinusReflectivity, oneMinusRoughness, normal, viewDir, gi.light2, gi.indirect).rgb * occlusion; #endif #ifdef DYNAMICLIGHTMAP_ON c += UNITY_BRDF_PBS_LIGHTMAP_INDIRECT (baseColor, specColor, oneMinusReflectivity, oneMinusRoughness, normal, viewDir, gi.light3, gi.indirect).rgb * occlusion; #endif #endif return c; } //------------------------------------------------------------------------------------- // Surface shader output structure to be used with physically // based shading model. //------------------------------------------------------------------------------------- // Metallic workflow // Define output struct unless it's already defined #ifndef SurfaceOutputStandard struct SurfaceOutputStandard { half3 Albedo; // base (diffuse or specular) color half3 Normal; // tangent space normal, if written half3 Emission; half Metallic; // 0=non-metal, 1=metal half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) half Alpha; // alpha for transparencies }; #endif inline half4 LightingStandard (SurfaceOutputStandard s, half3 viewDir, UnityGI gi) { s.Normal = normalize(s.Normal); half oneMinusReflectivity; half3 specColor; s.Albedo = DiffuseAndSpecularFromMetallic (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity); // shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha) // this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha half outputAlpha; s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha); half4 c = UNITY_BRDF_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect); c.rgb += UNITY_BRDF_GI (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi); c.a = outputAlpha; return c; } inline half4 LightingStandard_Deferred (SurfaceOutputStandard s, half3 viewDir, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal) { half oneMinusReflectivity; half3 specColor; s.Albedo = DiffuseAndSpecularFromMetallic (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity); half4 c = UNITY_BRDF_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect); c.rgb += UNITY_BRDF_GI (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi); outDiffuseOcclusion = half4(s.Albedo, s.Occlusion); outSpecSmoothness = half4(specColor, s.Smoothness); outNormal = half4(s.Normal * 0.5 + 0.5, 1); half4 emission = half4(s.Emission + c.rgb, 1); return emission; } inline void LightingStandard_GI ( SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi) { gi = UnityGlobalIllumination (data, s.Occlusion, s.Smoothness, s.Normal); } //------------------------------------------------------------------------------------- // Specular workflow // Define output struct unless it's already defined #ifndef SurfaceOutputStandardSpecular struct SurfaceOutputStandardSpecular { half3 Albedo; // diffuse color half3 Specular; // specular color half3 Normal; // tangent space normal, if written half3 Emission; half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) half Alpha; // alpha for transparencies }; #endif inline half4 LightingStandardSpecular (SurfaceOutputStandardSpecular s, half3 viewDir, UnityGI gi) { s.Normal = normalize(s.Normal); // energy conservation half oneMinusReflectivity; s.Albedo = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular, /*out*/ oneMinusReflectivity); // shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha) // this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha half outputAlpha; s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha); half4 c = UNITY_BRDF_PBS (s.Albedo, s.Specular, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect); c.rgb += UNITY_BRDF_GI (s.Albedo, s.Specular, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi); c.a = outputAlpha; return c; } inline half4 LightingStandardSpecular_Deferred (SurfaceOutputStandardSpecular s, half3 viewDir, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal) { // energy conservation half oneMinusReflectivity; s.Albedo = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular, /*out*/ oneMinusReflectivity); half4 c = UNITY_BRDF_PBS (s.Albedo, s.Specular, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect); c.rgb += UNITY_BRDF_GI (s.Albedo, s.Specular, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi); outDiffuseOcclusion = half4(s.Albedo, s.Occlusion); outSpecSmoothness = half4(s.Specular, s.Smoothness); outNormal = half4(s.Normal * 0.5 + 0.5, 1); half4 emission = half4(s.Emission + c.rgb, 1); return emission; } inline void LightingStandardSpecular_GI ( SurfaceOutputStandardSpecular s, UnityGIInput data, inout UnityGI gi) { gi = UnityGlobalIllumination (data, s.Occlusion, s.Smoothness, s.Normal); } #endif // UNITY_PBS_LIGHTING_INCLUDED