154 lines
6.0 KiB
HLSL
154 lines
6.0 KiB
HLSL
#ifndef TOON_FUNCTIONS_INCLUDED
|
|
#define TOON_FUNCTIONS_INCLUDED
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
|
|
// BRDF functions derived from Unity's BRDF.hlsl.
|
|
|
|
half3 ToonGlossyEnvironmentReflection(half3 reflectVector, half perceptualRoughness, half occlusion)
|
|
{
|
|
#if !defined(_ENVIRONMENTREFLECTIONS_OFF)
|
|
half3 irradiance;
|
|
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
|
|
half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
|
|
|
|
return encodedIrradiance.rgb * occlusion;
|
|
#else
|
|
|
|
return _GlossyEnvironmentColor.rgb * occlusion;
|
|
#endif // _ENVIRONMENTREFLECTIONS_OFF
|
|
}
|
|
|
|
half3 ToonGlobalIllumination(BRDFData brdfData,
|
|
half3 bakedGI, half occlusion,
|
|
half3 normalWS, half3 viewDirectionWS)
|
|
{
|
|
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
|
|
half NoV = saturate(dot(normalWS, viewDirectionWS));
|
|
half fresnelTerm = Pow4(1.0 - NoV);
|
|
|
|
half3 indirectDiffuse = bakedGI;
|
|
half3 indirectSpecular = ToonGlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, half(1.0));
|
|
|
|
half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
|
|
|
|
return color * occlusion;
|
|
}
|
|
|
|
void ToonBakedGIData(v2f input, inout InputData inputData)
|
|
{
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.dynamicLightmapUV, input.vertexSH, inputData.normalWS);
|
|
inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
|
|
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
|
|
inputData.bakedGI = SAMPLE_GI(input.vertexSH,
|
|
GetAbsolutePositionWS(inputData.positionWS),
|
|
inputData.normalWS,
|
|
inputData.viewDirectionWS,
|
|
input.positionCS.xy,
|
|
input.probeOcclusion,
|
|
inputData.shadowMask);
|
|
#else
|
|
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS);
|
|
inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
|
|
#endif
|
|
}
|
|
|
|
inline void ToonBRDFDataDirect(half3 albedo, half3 diffuse, half3 specular, half reflectivity, half oneMinusReflectivity, half smoothness, inout half alpha, out BRDFData outBRDFData)
|
|
{
|
|
outBRDFData = (BRDFData) 0;
|
|
outBRDFData.albedo = albedo;
|
|
outBRDFData.diffuse = diffuse;
|
|
outBRDFData.specular = specular;
|
|
outBRDFData.reflectivity = reflectivity;
|
|
|
|
outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
|
|
outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN_SQRT);
|
|
outBRDFData.roughness2 = max(outBRDFData.roughness * outBRDFData.roughness, HALF_MIN);
|
|
outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
|
|
outBRDFData.normalizationTerm = outBRDFData.roughness * half(4.0) + half(2.0);
|
|
outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - half(1.0);
|
|
}
|
|
|
|
// Initialize BRDFData for material, managing both specular and metallic setup using shader keyword _SPECULAR_SETUP.
|
|
inline void ToonBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, inout half alpha, out BRDFData outBRDFData)
|
|
{
|
|
#ifdef _SPECULAR_SETUP
|
|
half reflectivity = ReflectivitySpecular(specular);
|
|
half oneMinusReflectivity = half(1.0) - reflectivity;
|
|
half3 brdfDiffuse = albedo * oneMinusReflectivity;
|
|
half3 brdfSpecular = specular;
|
|
#else
|
|
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
|
|
half reflectivity = half(1.0) - oneMinusReflectivity;
|
|
half3 brdfDiffuse = albedo * oneMinusReflectivity;
|
|
half3 brdfSpecular = lerp(kDielectricSpec.rgb, albedo, metallic);
|
|
#endif
|
|
|
|
ToonBRDFDataDirect(albedo, brdfDiffuse, brdfSpecular, reflectivity, oneMinusReflectivity, smoothness, alpha, outBRDFData);
|
|
}
|
|
|
|
inline half3 CalculateToonLighting(BRDFData brdfData, Light light, half3 normalWS, half3 viewWS, float specularOffset)
|
|
{
|
|
#ifdef _LIGHT_LAYERS
|
|
uint meshRenderingLayers = GetMeshRenderingLayer();
|
|
if (!IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// Diffuse calculations (n dot l).
|
|
half NdotL = dot(normalWS, light.direction);
|
|
half rawDiffuseAmount = smoothstep(_DiffuseThresholds.x, _DiffuseThresholds.y, NdotL);
|
|
|
|
// Light attenuation.
|
|
half lightAtten = saturate(light.distanceAttenuation);
|
|
|
|
#ifdef _RECEIVE_SHADOWS_ON
|
|
lightAtten *= smoothstep(_ShadowThresholds.x, _ShadowThresholds.y, light.shadowAttenuation);
|
|
#endif
|
|
|
|
// Calculate radiance from diffuse values.
|
|
#ifdef _USE_SECOND_THRESHOLD
|
|
half diffuseAmount = rawDiffuseAmount + smoothstep(_DiffuseThresholds.z, _DiffuseThresholds.w, NdotL);
|
|
half3 radiance = lerp(lerp(_ShadowTint, _MiddleTint, saturate(diffuseAmount)), _LightTint, saturate(diffuseAmount - 1.0f));
|
|
#else
|
|
half3 radiance = lerp(_ShadowTint, _LightTint, saturate(rawDiffuseAmount));
|
|
#endif
|
|
|
|
radiance *= light.color * lightAtten;
|
|
|
|
half3 brdf = brdfData.diffuse;
|
|
|
|
// Specular calculations.
|
|
float3 halfDir = SafeNormalize(light.direction + viewWS);
|
|
float NoH = saturate(dot(normalWS, halfDir));
|
|
half LoH = half(saturate(dot(light.direction, halfDir)));
|
|
|
|
float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
|
|
|
|
half LoH2 = LoH * LoH;
|
|
half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
|
|
|
|
#if REAL_IS_HALF
|
|
specularTerm = specularTerm - HALF_MIN;
|
|
specularTerm = clamp(specularTerm, 0.0, 1000.0); // Prevent FP16 overflow on mobiles
|
|
#endif
|
|
|
|
specularTerm = smoothstep(_SpecularThresholds.x, _SpecularThresholds.y, specularTerm + specularOffset);
|
|
specularTerm *= _SpecularBoost;
|
|
|
|
brdf += brdfData.specular * specularTerm;
|
|
|
|
// Rim lighting.
|
|
float rimAmount = (1.0f - saturate(dot(normalWS, viewWS))) * saturate(rawDiffuseAmount + _RimExtension);
|
|
rimAmount = smoothstep(_RimThresholds.x, _RimThresholds.y, rimAmount);
|
|
half3 rimColor = rimAmount * _RimColor;
|
|
|
|
// Combine lighting types.
|
|
return brdf * radiance + rimColor;
|
|
}
|
|
|
|
#endif // TOON_FUNCTIONS_INCLUDED
|