123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- #ifndef UNIVERSAL_LIGHTING_INCLUDED
- #define UNIVERSAL_LIGHTING_INCLUDED
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/Debugging3D.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GlobalIllumination.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
- #if defined(LIGHTMAP_ON)
- #define DECLARE_LIGHTMAP_OR_SH(lmName, shName, index) float2 lmName : TEXCOORD##index
- #define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw;
- #define OUTPUT_SH(normalWS, OUT)
- #else
- #define DECLARE_LIGHTMAP_OR_SH(lmName, shName, index) half3 shName : TEXCOORD##index
- #define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT)
- #define OUTPUT_SH(normalWS, OUT) OUT.xyz = SampleSHVertex(normalWS)
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // Lighting Functions //
- ///////////////////////////////////////////////////////////////////////////////
- half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
- {
- half NdotL = saturate(dot(normal, lightDir));
- return lightColor * NdotL;
- }
- half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specular, half smoothness)
- {
- float3 halfVec = SafeNormalize(float3(lightDir) + float3(viewDir));
- half NdotH = half(saturate(dot(normal, halfVec)));
- half modifier = pow(NdotH, smoothness);
- half3 specularReflection = specular.rgb * modifier;
- return lightColor * specularReflection;
- }
- half3 LightingPhysicallyBased(BRDFData brdfData, BRDFData brdfDataClearCoat,
- half3 lightColor, half3 lightDirectionWS, half lightAttenuation,
- half3 normalWS, half3 viewDirectionWS,
- half clearCoatMask, bool specularHighlightsOff)
- {
- half NdotL = saturate(dot(normalWS, lightDirectionWS));
- half3 radiance = lightColor * (lightAttenuation * NdotL);
- half3 brdf = brdfData.diffuse;
- #ifndef _SPECULARHIGHLIGHTS_OFF
- [branch] if (!specularHighlightsOff)
- {
- brdf += brdfData.specular * DirectBRDFSpecular(brdfData, normalWS, lightDirectionWS, viewDirectionWS);
- #if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
- // Clear coat evaluates the specular a second timw and has some common terms with the base specular.
- // We rely on the compiler to merge these and compute them only once.
- half brdfCoat = kDielectricSpec.r * DirectBRDFSpecular(brdfDataClearCoat, normalWS, lightDirectionWS, viewDirectionWS);
- // Mix clear coat and base layer using khronos glTF recommended formula
- // https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md
- // Use NoV for direct too instead of LoH as an optimization (NoV is light invariant).
- half NoV = saturate(dot(normalWS, viewDirectionWS));
- // Use slightly simpler fresnelTerm (Pow4 vs Pow5) as a small optimization.
- // It is matching fresnel used in the GI/Env, so should produce a consistent clear coat blend (env vs. direct)
- half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * Pow4(1.0 - NoV);
- brdf = brdf * (1.0 - clearCoatMask * coatFresnel) + brdfCoat * clearCoatMask;
- #endif // _CLEARCOAT
- }
- #endif // _SPECULARHIGHLIGHTS_OFF
- return brdf * radiance;
- }
- half3 LightingPhysicallyBased(BRDFData brdfData, BRDFData brdfDataClearCoat, Light light, half3 normalWS, half3 viewDirectionWS, half clearCoatMask, bool specularHighlightsOff)
- {
- return LightingPhysicallyBased(brdfData, brdfDataClearCoat, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, clearCoatMask, specularHighlightsOff);
- }
- // Backwards compatibility
- half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS)
- {
- #ifdef _SPECULARHIGHLIGHTS_OFF
- bool specularHighlightsOff = true;
- #else
- bool specularHighlightsOff = false;
- #endif
- const BRDFData noClearCoat = (BRDFData)0;
- return LightingPhysicallyBased(brdfData, noClearCoat, light, normalWS, viewDirectionWS, 0.0, specularHighlightsOff);
- }
- half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS)
- {
- Light light;
- light.color = lightColor;
- light.direction = lightDirectionWS;
- light.distanceAttenuation = lightAttenuation;
- light.shadowAttenuation = 1;
- return LightingPhysicallyBased(brdfData, light, normalWS, viewDirectionWS);
- }
- half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS, bool specularHighlightsOff)
- {
- const BRDFData noClearCoat = (BRDFData)0;
- return LightingPhysicallyBased(brdfData, noClearCoat, light, normalWS, viewDirectionWS, 0.0, specularHighlightsOff);
- }
- half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, bool specularHighlightsOff)
- {
- Light light;
- light.color = lightColor;
- light.direction = lightDirectionWS;
- light.distanceAttenuation = lightAttenuation;
- light.shadowAttenuation = 1;
- return LightingPhysicallyBased(brdfData, light, viewDirectionWS, specularHighlightsOff, specularHighlightsOff);
- }
- half3 VertexLighting(float3 positionWS, half3 normalWS)
- {
- half3 vertexLightColor = half3(0.0, 0.0, 0.0);
- #ifdef _ADDITIONAL_LIGHTS_VERTEX
- uint lightsCount = GetAdditionalLightsCount();
- LIGHT_LOOP_BEGIN(lightsCount)
- Light light = GetAdditionalLight(lightIndex, positionWS);
- half3 lightColor = light.color * light.distanceAttenuation;
- vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);
- LIGHT_LOOP_END
- #endif
- return vertexLightColor;
- }
- struct LightingData
- {
- half3 giColor;
- half3 mainLightColor;
- half3 additionalLightsColor;
- half3 vertexLightingColor;
- half3 emissionColor;
- };
- half3 CalculateLightingColor(LightingData lightingData, half3 albedo)
- {
- half3 lightingColor = 0;
- if (IsOnlyAOLightingFeatureEnabled())
- {
- return lightingData.giColor; // Contains white + AO
- }
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_GLOBAL_ILLUMINATION))
- {
- lightingColor += lightingData.giColor;
- }
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_MAIN_LIGHT))
- {
- lightingColor += lightingData.mainLightColor;
- }
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_ADDITIONAL_LIGHTS))
- {
- lightingColor += lightingData.additionalLightsColor;
- }
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_VERTEX_LIGHTING))
- {
- lightingColor += lightingData.vertexLightingColor;
- }
- lightingColor *= albedo;
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_EMISSION))
- {
- lightingColor += lightingData.emissionColor;
- }
- return lightingColor;
- }
- half4 CalculateFinalColor(LightingData lightingData, half alpha)
- {
- half3 finalColor = CalculateLightingColor(lightingData, 1);
- return half4(finalColor, alpha);
- }
- half4 CalculateFinalColor(LightingData lightingData, half3 albedo, half alpha, float fogCoord)
- {
- #if defined(_FOG_FRAGMENT)
- #if (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2))
- float viewZ = -fogCoord;
- float nearToFarZ = max(viewZ - _ProjectionParams.y, 0);
- half fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ);
- #else
- half fogFactor = 0;
- #endif
- #else
- half fogFactor = fogCoord;
- #endif
- half3 lightingColor = CalculateLightingColor(lightingData, albedo);
- half3 finalColor = MixFog(lightingColor, fogFactor);
- return half4(finalColor, alpha);
- }
- LightingData CreateLightingData(InputData inputData, SurfaceData surfaceData)
- {
- LightingData lightingData;
- lightingData.giColor = inputData.bakedGI;
- lightingData.emissionColor = surfaceData.emission;
- lightingData.vertexLightingColor = 0;
- lightingData.mainLightColor = 0;
- lightingData.additionalLightsColor = 0;
- return lightingData;
- }
- half3 CalculateBlinnPhong(Light light, InputData inputData, SurfaceData surfaceData)
- {
- half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
- half3 lightColor = LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
- lightColor *= surfaceData.albedo;
- #if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
- half smoothness = exp2(10 * surfaceData.smoothness + 1);
- lightColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, half4(surfaceData.specular, 1), smoothness);
- #endif
- return lightColor;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Fragment Functions //
- // Used by ShaderGraph and others builtin renderers //
- ///////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- /// PBR lighting...
- ////////////////////////////////////////////////////////////////////////////////
- half4 UniversalFragmentPBR(InputData inputData, SurfaceData surfaceData)
- {
- #if defined(_SPECULARHIGHLIGHTS_OFF)
- bool specularHighlightsOff = true;
- #else
- bool specularHighlightsOff = false;
- #endif
- BRDFData brdfData;
- // NOTE: can modify "surfaceData"...
- InitializeBRDFData(surfaceData, brdfData);
- #if defined(DEBUG_DISPLAY)
- half4 debugColor;
- if (CanDebugOverrideOutputColor(inputData, surfaceData, brdfData, debugColor))
- {
- return debugColor;
- }
- #endif
- // Clear-coat calculation...
- BRDFData brdfDataClearCoat = CreateClearCoatBRDFData(surfaceData, brdfData);
- half4 shadowMask = CalculateShadowMask(inputData);
- AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
- uint meshRenderingLayers = GetMeshRenderingLightLayer();
- Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
- // NOTE: We don't apply AO to the GI here because it's done in the lighting calculation below...
- MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI);
- LightingData lightingData = CreateLightingData(inputData, surfaceData);
- lightingData.giColor = GlobalIllumination(brdfData, brdfDataClearCoat, surfaceData.clearCoatMask,
- inputData.bakedGI, aoFactor.indirectAmbientOcclusion, inputData.positionWS,
- inputData.normalWS, inputData.viewDirectionWS);
- if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
- {
- lightingData.mainLightColor = LightingPhysicallyBased(brdfData, brdfDataClearCoat,
- mainLight,
- inputData.normalWS, inputData.viewDirectionWS,
- surfaceData.clearCoatMask, specularHighlightsOff);
- }
- #if defined(_ADDITIONAL_LIGHTS)
- uint pixelLightCount = GetAdditionalLightsCount();
- #if USE_CLUSTERED_LIGHTING
- for (uint lightIndex = 0; lightIndex < min(_AdditionalLightsDirectionalCount, MAX_VISIBLE_LIGHTS); lightIndex++)
- {
- Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- {
- lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light,
- inputData.normalWS, inputData.viewDirectionWS,
- surfaceData.clearCoatMask, specularHighlightsOff);
- }
- }
- #endif
- LIGHT_LOOP_BEGIN(pixelLightCount)
- Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- {
- lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light,
- inputData.normalWS, inputData.viewDirectionWS,
- surfaceData.clearCoatMask, specularHighlightsOff);
- }
- LIGHT_LOOP_END
- #endif
- #if defined(_ADDITIONAL_LIGHTS_VERTEX)
- lightingData.vertexLightingColor += inputData.vertexLighting * brdfData.diffuse;
- #endif
- return CalculateFinalColor(lightingData, surfaceData.alpha);
- }
- // Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments...
- half4 UniversalFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
- half smoothness, half occlusion, half3 emission, half alpha)
- {
- SurfaceData surfaceData;
- surfaceData.albedo = albedo;
- surfaceData.specular = specular;
- surfaceData.metallic = metallic;
- surfaceData.smoothness = smoothness;
- surfaceData.normalTS = half3(0, 0, 1);
- surfaceData.emission = emission;
- surfaceData.occlusion = occlusion;
- surfaceData.alpha = alpha;
- surfaceData.clearCoatMask = 0;
- surfaceData.clearCoatSmoothness = 1;
- return UniversalFragmentPBR(inputData, surfaceData);
- }
- ////////////////////////////////////////////////////////////////////////////////
- /// Phong lighting...
- ////////////////////////////////////////////////////////////////////////////////
- half4 UniversalFragmentBlinnPhong(InputData inputData, SurfaceData surfaceData)
- {
- #if defined(DEBUG_DISPLAY)
- half4 debugColor;
- if (CanDebugOverrideOutputColor(inputData, surfaceData, debugColor))
- {
- return debugColor;
- }
- #endif
- uint meshRenderingLayers = GetMeshRenderingLightLayer();
- half4 shadowMask = CalculateShadowMask(inputData);
- AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
- Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
- MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, aoFactor);
- inputData.bakedGI *= surfaceData.albedo;
- LightingData lightingData = CreateLightingData(inputData, surfaceData);
- if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
- {
- lightingData.mainLightColor += CalculateBlinnPhong(mainLight, inputData, surfaceData);
- }
- #if defined(_ADDITIONAL_LIGHTS)
- uint pixelLightCount = GetAdditionalLightsCount();
- #if USE_CLUSTERED_LIGHTING
- for (uint lightIndex = 0; lightIndex < min(_AdditionalLightsDirectionalCount, MAX_VISIBLE_LIGHTS); lightIndex++)
- {
- Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- {
- lightingData.additionalLightsColor += CalculateBlinnPhong(light, inputData, surfaceData);
- }
- }
- #endif
- LIGHT_LOOP_BEGIN(pixelLightCount)
- Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- {
- lightingData.additionalLightsColor += CalculateBlinnPhong(light, inputData, surfaceData);
- }
- LIGHT_LOOP_END
- #endif
- #if defined(_ADDITIONAL_LIGHTS_VERTEX)
- lightingData.vertexLightingColor += inputData.vertexLighting;
- #endif
- return CalculateFinalColor(lightingData, surfaceData.alpha);
- }
- // Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments...
- half4 UniversalFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half smoothness, half3 emission, half alpha, half3 normalTS)
- {
- SurfaceData surfaceData;
- surfaceData.albedo = diffuse;
- surfaceData.alpha = alpha;
- surfaceData.emission = emission;
- surfaceData.metallic = 0;
- surfaceData.occlusion = 1;
- surfaceData.smoothness = smoothness;
- surfaceData.specular = specularGloss.rgb;
- surfaceData.clearCoatMask = 0;
- surfaceData.clearCoatSmoothness = 1;
- surfaceData.normalTS = normalTS;
- return UniversalFragmentBlinnPhong(inputData, surfaceData);
- }
- ////////////////////////////////////////////////////////////////////////////////
- /// Unlit
- ////////////////////////////////////////////////////////////////////////////////
- half4 UniversalFragmentBakedLit(InputData inputData, SurfaceData surfaceData)
- {
- #ifdef _ALPHAPREMULTIPLY_ON
- surfaceData.albedo *= surfaceData.alpha;
- #endif
- #if defined(DEBUG_DISPLAY)
- half4 debugColor;
- if (CanDebugOverrideOutputColor(inputData, surfaceData, debugColor))
- {
- return debugColor;
- }
- #endif
- AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
- LightingData lightingData = CreateLightingData(inputData, surfaceData);
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
- {
- lightingData.giColor *= aoFactor.indirectAmbientOcclusion;
- }
- return CalculateFinalColor(lightingData, surfaceData.albedo, surfaceData.alpha, inputData.fogCoord);
- }
- // Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments...
- half4 UniversalFragmentBakedLit(InputData inputData, half3 color, half alpha, half3 normalTS)
- {
- SurfaceData surfaceData;
- surfaceData.albedo = color;
- surfaceData.alpha = alpha;
- surfaceData.emission = half3(0, 0, 0);
- surfaceData.metallic = 0;
- surfaceData.occlusion = 1;
- surfaceData.smoothness = 1;
- surfaceData.specular = half3(0, 0, 0);
- surfaceData.clearCoatMask = 0;
- surfaceData.clearCoatSmoothness = 1;
- surfaceData.normalTS = normalTS;
- return UniversalFragmentBakedLit(inputData, surfaceData);
- }
- #endif
|