123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- #ifndef LIGHTWEIGHT_SKINLIGHTING_INCLUDED
- #define LIGHTWEIGHT_SKINLIGHTING_INCLUDED
- #if !defined(SHADERGRAPH_PREVIEW) || defined(LIGHTWEIGHT_LIGHTING_INCLUDED)
- // As we do not have access to the vertex lights we will make the shader always sample add lights per pixel
- #if defined(_ADDITIONAL_LIGHTS_VERTEX)
- #undef _ADDITIONAL_LIGHTS_VERTEX
- #define _ADDITIONAL_LIGHTS
- #endif
- #endif
- //TEXTURE2D(_SkinLUT); SAMPLER(sampler_SkinLUT); float4 _SkinLUT_TexelSize;
- #if !defined(SHADERGRAPH_PREVIEW) || defined(LIGHTWEIGHT_LIGHTING_INCLUDED)
- half3 DirectBDRF_Lux(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
- {
- #ifndef _SPECULARHIGHLIGHTS_OFF
- float3 halfDir = SafeNormalize(lightDirectionWS + viewDirectionWS);
- float NoH = saturate(dot(normalWS, halfDir));
- half LoH = saturate(dot(lightDirectionWS, halfDir));
- // GGX Distribution multiplied by combined approximation of Visibility and Fresnel
- // BRDFspec = (D * V * F) / 4.0
- // D = roughness² / ( NoH² * (roughness² - 1) + 1 )²
- // V * F = 1.0 / ( LoH² * (roughness + 0.5) )
- // See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
- // https://community.arm.com/events/1155
- // Final BRDFspec = roughness² / ( NoH² * (roughness² - 1) + 1 )² * (LoH² * (roughness + 0.5) * 4.0)
- // We further optimize a few light invariant terms
- // brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
- float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
- half LoH2 = LoH * LoH;
- half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
- // On platforms where half actually means something, the denominator has a risk of overflow
- // clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
- // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
- #if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)
- specularTerm = specularTerm - HALF_MIN;
- specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
- #endif
- half3 color = specularTerm * brdfData.specular; // + brdfData.diffuse;
- return color;
- #else
- return 0; //brdfData.diffuse;
- #endif
- }
- half3 GlobalIllumination_Lux(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS,
- half specOccluison)
- {
- half fresnelTerm = 0;
- half3 indirectSpecular = 0;
- if(specOccluison > 0) {
- half3 reflectVector = reflect(-viewDirectionWS, normalWS);
- fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
- indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion) * specOccluison;
- }
- half3 indirectDiffuse = bakedGI * occlusion;
- return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
- }
- half3 LightingPhysicallyBasedSkin(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, half NdotL, half NdotLUnclamped, half curvature, half skinMask)
- {
- //half3 radiance = lightColor * NdotL;
- half3 diffuseLighting = brdfData.diffuse * SAMPLE_TEXTURE2D_LOD(_SkinLUT, sampler_SkinLUT, float2( (NdotLUnclamped * 0.5 + 0.5), curvature), 0).rgb;
- diffuseLighting = lerp(brdfData.diffuse * NdotL, diffuseLighting, skinMask);
- return ( DirectBDRF_Lux(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * NdotL + diffuseLighting ) * lightColor * lightAttenuation;
- }
- half3 LightingPhysicallyBasedSkin(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS, half NdotL, half NdotLUnclamped, half curvature, half skinMask)
- {
- return LightingPhysicallyBasedSkin(brdfData, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
- }
- #endif
-
- void Lighting_half(
- // Base inputs
- half3 positionWS,
- half3 viewDirectionWS,
- // Normal inputs
- half3 normalWS,
- half3 tangentWS,
- half3 bitangentWS,
- bool enableNormalMapping,
- bool enableDiffuseNormalMapping,
- bool enableBackScattering,
- bool useVertexNormal,
- // Surface description
- half3 albedo,
- half metallic,
- half3 specular,
- half smoothness,
- half occlusion,
- half3 emission,
- half alpha,
- half4 translucency,
- half AmbientReflection,
- half3 subsurfaceColor,
- half curvature,
- half skinMask,
- half maskbyshadowstrength,
- half backScattering,
- Texture2D normalMap,
- SamplerState sampler_Normal,
- float2 UV,
- float bumpScale,
- float diffuseBias,
- // Lightmapping
- float2 lightMapUV,
- // Final lit color
- out half3 MetaAlbedo,
- out half3 FinalLighting,
- out half3 MetaSpecular
- )
- {
- #if defined(SHADERGRAPH_PREVIEW) || ( !defined(LIGHTWEIGHT_LIGHTING_INCLUDED) && !defined(UNIVERSAL_LIGHTING_INCLUDED) )
- FinalLighting = albedo;
- MetaAlbedo = half3(0,0,0);
- MetaSpecular = half3(0,0,0);
- #else
- half3 diffuseNormalWS;
- if (enableNormalMapping) {
- half3x3 ToW = half3x3(tangentWS.xyz, bitangentWS.xyz, normalWS.xyz);
- half4 sampleNormal = SAMPLE_TEXTURE2D(normalMap, sampler_Normal, UV);
- half3 normalTS = UnpackNormalScale(sampleNormal, bumpScale);
- // Get specular normal
- half3 snormalWS = TransformTangentToWorld(normalTS, ToW);
- snormalWS = NormalizeNormalPerPixel(snormalWS);
- // Get diffuse normal
- if(enableDiffuseNormalMapping) {
- half4 sampleNormalDiffuse = SAMPLE_TEXTURE2D_BIAS(normalMap, sampler_Normal, UV, diffuseBias);
- // Do not manually unpack the normal map as it might use RGB.
- half3 diffuseNormalTS = UnpackNormal(sampleNormalDiffuse);
- // Get diffuseNormalWS
- diffuseNormalWS = TransformTangentToWorld(diffuseNormalTS, ToW);
- diffuseNormalWS = NormalizeNormalPerPixel(diffuseNormalWS);
- }
- else {
- diffuseNormalWS = (useVertexNormal) ? normalWS : snormalWS;
- }
- // Set specular normal
- normalWS = snormalWS;
- }
- else {
- normalWS = NormalizeNormalPerPixel(normalWS);
- diffuseNormalWS = normalWS;
- }
- viewDirectionWS = SafeNormalize(viewDirectionWS);
- // GI Lighting
- half3 bakedGI;
- #ifdef LIGHTMAP_ON
- lightMapUV = lightMapUV * unity_LightmapST.xy + unity_LightmapST.zw;
- bakedGI = SAMPLE_GI(lightMapUV, half3(0,0,0), diffuseNormalWS);
- #else
- bakedGI = SampleSH(diffuseNormalWS);
- #endif
- BRDFData brdfData;
- InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
- float4 clipPos = TransformWorldToHClip(positionWS);
- // Get Shadow Sampling Coords
- #if SHADOWS_SCREEN
- float4 shadowCoord = ComputeScreenPos(clipPos);
- #else
- float4 shadowCoord = TransformWorldToShadowCoord(positionWS);
- #endif
- Light mainLight = GetMainLight(shadowCoord);
- half3 mainLightColor = mainLight.color;
- // SSAO
- #if defined(_SCREEN_SPACE_OCCLUSION)
- float4 ndc = clipPos * 0.5f;
- float2 normalized = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
- normalized /= clipPos.w;
- normalized *= _ScreenParams.xy;
- // We could also use IN.Screenpos(default) --> ( IN.Screenpos.xy * _ScreenParams.xy)
- // HDRP 10.1
- normalized = GetNormalizedScreenSpaceUV(normalized);
- AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(normalized);
- mainLight.color *= aoFactor.directAmbientOcclusion;
- occlusion = min(occlusion, aoFactor.indirectAmbientOcclusion);
- #endif
- FinalLighting = GlobalIllumination_Lux(brdfData, bakedGI, occlusion, normalWS, viewDirectionWS, AmbientReflection);
- // Backscattering
- if (enableBackScattering) {
- FinalLighting += backScattering * SampleSH(-diffuseNormalWS) * albedo * occlusion * translucency.x * subsurfaceColor * skinMask;
- }
- MixRealtimeAndBakedGI(mainLight, normalWS, bakedGI, half4(0, 0, 0, 0));
- half NdotLUnclamped = dot(diffuseNormalWS, mainLight.direction);
- half NdotL = saturate( dot(normalWS, mainLight.direction) );
- FinalLighting += LightingPhysicallyBasedSkin(brdfData, mainLight, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
- // Subsurface Scattering
- half transPower = translucency.y;
- half3 transLightDir = mainLight.direction + normalWS * translucency.w;
- half transDot = dot( transLightDir, -viewDirectionWS );
- transDot = exp2(saturate(transDot) * transPower - transPower);
- FinalLighting += skinMask * subsurfaceColor * transDot * (1.0 - saturate(NdotLUnclamped)) * mainLightColor * lerp(1.0h, mainLight.shadowAttenuation, translucency.z) * translucency.x;
- // URP 10
- half4 shadowMask = half4(1, 1, 1, 1);
- #ifdef _ADDITIONAL_LIGHTS
- uint pixelLightCount = GetAdditionalLightsCount();
- for (uint i = 0u; i < pixelLightCount; ++i)
- {
- //Light light = GetAdditionalLight(i, inputData.positionWS);
- // Get index upfront as we need it for GetAdditionalLightShadowParams();
- int index = GetPerObjectLightIndex(i);
- // Light light = GetAdditionalPerObjectLight(index, positionWS); // here; shadowAttenuation = 1.0;
- // URP 10: We have to use the new GetAdditionalLight function
- Light light = GetAdditionalLight(i, positionWS, shadowMask);
- half3 lightColor = light.color;
- #if defined(_SCREEN_SPACE_OCCLUSION)
- light.color *= aoFactor.directAmbientOcclusion;
- #endif
- half NdotLUnclamped = dot(diffuseNormalWS, light.direction);
- NdotL = saturate( dot(normalWS, light.direction) );
- FinalLighting += LightingPhysicallyBasedSkin(brdfData, light, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
- // Transmission
- half4 shadowParams = GetAdditionalLightShadowParams(index);
- lightColor *= lerp(1, shadowParams.x, maskbyshadowstrength); // shadowParams.x == shadow strength, which is 0 for point lights
-
- transLightDir = light.direction + normalWS * translucency.w;
- transDot = dot( transLightDir, -viewDirectionWS );
- transDot = exp2(saturate(transDot) * transPower - transPower);
- FinalLighting += skinMask * subsurfaceColor * transDot * (1.0 - NdotL) * lightColor * lerp(1.0h, light.shadowAttenuation, translucency.z) * light.distanceAttenuation * translucency.x;
- }
- #endif
- #ifdef _ADDITIONAL_LIGHTS_VERTEX
- // FinalLighting += inputData.vertexLighting * brdfData.diffuse;
- #endif
- FinalLighting += emission;
- // Set Albedo for meta pass
- #if defined(LIGHTWEIGHT_META_PASS_INCLUDED) || defined(UNIVERSAL_META_PASS_INCLUDED)
- FinalLighting = half3(0,0,0);
- MetaAlbedo = albedo;
- MetaSpecular = specular;
- #else
- MetaAlbedo = half3(0,0,0);
- MetaSpecular = half3(0,0,0);
- #endif
- #endif
- }
- // Unity 2019.1. needs a float version
- void Lighting_float(
- // Base inputs
- half3 positionWS,
- half3 viewDirectionWS,
- // Normal inputs
- half3 normalWS,
- half3 tangentWS,
- half3 bitangentWS,
- bool enableNormalMapping,
- bool enableDiffuseNormalMapping,
- bool enableBackScattering,
- bool useVertexNormal,
- // Surface description
- half3 albedo,
- half metallic,
- half3 specular,
- half smoothness,
- half occlusion,
- half3 emission,
- half alpha,
- half4 translucency,
- half AmbientReflection,
- half3 subsurfaceColor,
- half curvature,
- half skinMask,
- half maskbyshadowstrength,
- half backScattering,
- Texture2D normalMap,
- SamplerState sampler_Normal,
- float2 UV,
- float bumpScale,
- float diffuseBias,
- // Lightmapping
- float2 lightMapUV,
- // Final lit color
- out half3 MetaAlbedo,
- out half3 FinalLighting,
- out half3 MetaSpecular
- )
- {
- Lighting_half(
- positionWS, viewDirectionWS, normalWS, tangentWS, bitangentWS, enableNormalMapping, enableDiffuseNormalMapping, enableBackScattering, useVertexNormal,
- albedo, metallic, specular, smoothness, occlusion, emission, alpha,
- translucency, AmbientReflection, subsurfaceColor, curvature, skinMask, maskbyshadowstrength,
- backScattering,
- normalMap, sampler_Normal, UV, bumpScale, diffuseBias,
- lightMapUV,
- MetaAlbedo, FinalLighting, MetaSpecular
- );
- }
- #endif
|