res-avatar-unity/Assets/RalivDynamicPenetrationSystem/Plugins/Xiexes-Unity-Shaders-development/Main/CGIncludes/XSLightingFunctions.cginc

429 lines
17 KiB
HLSL
Raw Permalink Normal View History

2023-07-16 02:51:23 +00:00
//Helper Functions for Reflections
float pow5(float a)
{
return a * a * a * a * a;
}
float3 F_Schlick(float u, float3 f0)
{
return f0 + (1.0 - f0) * pow(1.0 - u, 5.0);
}
float3 F_FresnelLerp (float3 F0, float3 F90, float cosA)
{
float t = pow5(1 - cosA); // ala Schlick interpoliation
return lerp (F0, F90, t);
}
float D_GGX(float NoH, float roughness)
{
float a2 = roughness * roughness;
float f = (NoH * a2 - NoH) * NoH + 1.0;
return a2 / (UNITY_PI * f * f);
}
float D_GGX_Anisotropic(float NoH, const float3 h, const float3 t, const float3 b, float at, float ab)
{
float ToH = dot(t, h);
float BoH = dot(b, h);
float a2 = at * ab;
float3 v = float3(ab * ToH, at * BoH, a2 * NoH);
float v2 = dot(v, v);
float w2 = a2 / v2;
return a2 * w2 * w2 * (1.0 / UNITY_PI);
}
float V_SmithGGXCorrelated(float NoV, float NoL, float a)
{
float a2 = a * a;
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
return 0.5 / (GGXV + GGXL);
}
half3 calcReflView(half3 viewDir, half3 normal)
{
return reflect(-viewDir, normal);
}
half3 calcReflLight(half3 lightDir, half3 normal)
{
return reflect(lightDir, normal);
}
//
//Returns the average direction of all lights and writes to a struct contraining individual directions
float3 getVertexLightsDir(inout VertexLightInformation vLights, float3 worldPos, float4 vertexLightAtten)
{
float3 dir = float3(0,0,0);
float3 toLightX = float3(unity_4LightPosX0.x, unity_4LightPosY0.x, unity_4LightPosZ0.x);
float3 toLightY = float3(unity_4LightPosX0.y, unity_4LightPosY0.y, unity_4LightPosZ0.y);
float3 toLightZ = float3(unity_4LightPosX0.z, unity_4LightPosY0.z, unity_4LightPosZ0.z);
float3 toLightW = float3(unity_4LightPosX0.w, unity_4LightPosY0.w, unity_4LightPosZ0.w);
float3 dirX = toLightX - worldPos;
float3 dirY = toLightY - worldPos;
float3 dirZ = toLightZ - worldPos;
float3 dirW = toLightW - worldPos;
dirX *= length(toLightX) * vertexLightAtten.x;
dirY *= length(toLightY) * vertexLightAtten.y;
dirZ *= length(toLightZ) * vertexLightAtten.z;
dirW *= length(toLightW) * vertexLightAtten.w;
vLights.Direction[0] = dirX;
vLights.Direction[1] = dirY;
vLights.Direction[2] = dirZ;
vLights.Direction[3] = dirW;
dir = (dirX + dirY + dirZ + dirW) / 4;
return dir;
}
// Get the most intense light Dir from probes OR from a light source. Method developed by Xiexe / Merlin
half3 calcLightDir(XSLighting i)
{
half3 lightDir = UnityWorldSpaceLightDir(i.worldPos);
half3 probeLightDir = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz;
lightDir = (lightDir + probeLightDir); //Make light dir the average of the probe direction and the light source direction.
#if !defined(POINT) && !defined(SPOT)// if the average length of the light probes is null, and we don't have a directional light in the scene, fall back to our fallback lightDir
if(length(unity_SHAr.xyz*unity_SHAr.w + unity_SHAg.xyz*unity_SHAg.w + unity_SHAb.xyz*unity_SHAb.w) == 0 && length(lightDir) < 0.1)
{
lightDir = half4(1, 1, 1, 0);
}
#endif
return normalize(lightDir);
}
void calcLightCol(bool lightEnv, inout half3 indirectDiffuse, inout half4 lightColor)
{
//If we're in an environment with a realtime light, then we should use the light color, and indirect color raw.
//...
if(lightEnv)
{
lightColor = _LightColor0;
indirectDiffuse = indirectDiffuse;
}
else
{
lightColor = indirectDiffuse.xyzz * 0.6; // ...Otherwise
indirectDiffuse = indirectDiffuse * 0.4; // Keep overall light to 100% - these should never go over 100%
// ex. If we have indirect 100% as the light color and Indirect 50% as the indirect color,
// we end up with 150% of the light from the scene.
}
}
float3 get4VertexLightsColFalloff(inout VertexLightInformation vLight, float3 worldPos, float3 normal, inout float4 vertexLightAtten)
{
float3 lightColor = 0;
#if defined(VERTEXLIGHT_ON)
float4 toLightX = unity_4LightPosX0 - worldPos.x;
float4 toLightY = unity_4LightPosY0 - worldPos.y;
float4 toLightZ = unity_4LightPosZ0 - worldPos.z;
float4 lengthSq = 0;
lengthSq += toLightX * toLightX;
lengthSq += toLightY * toLightY;
lengthSq += toLightZ * toLightZ;
float4 atten = 1.0 / (1.0 + lengthSq * unity_4LightAtten0);
float4 atten2 = saturate(1 - (lengthSq * unity_4LightAtten0 / 25));
atten = min(atten, atten2 * atten2);
// Cleaner, nicer looking falloff. Also prevents the "Snapping in" effect that Unity's normal integration of vertex lights has.
vertexLightAtten = atten;
lightColor.rgb += unity_LightColor[0] * atten.x;
lightColor.rgb += unity_LightColor[1] * atten.y;
lightColor.rgb += unity_LightColor[2] * atten.z;
lightColor.rgb += unity_LightColor[3] * atten.w;
vLight.ColorFalloff[0] = unity_LightColor[0] * atten.x;
vLight.ColorFalloff[1] = unity_LightColor[1] * atten.y;
vLight.ColorFalloff[2] = unity_LightColor[2] * atten.z;
vLight.ColorFalloff[3] = unity_LightColor[3] * atten.w;
vLight.Attenuation[0] = atten.x;
vLight.Attenuation[1] = atten.y;
vLight.Attenuation[2] = atten.z;
vLight.Attenuation[3] = atten.w;
#endif
return lightColor;
}
half4 calcRamp(XSLighting i, DotProducts d)
{
half remapRamp;
remapRamp = (d.ndl * 0.5 + 0.5) * lerp(1, i.occlusion.r, _OcclusionMode) ;
#if defined(UNITY_PASS_FORWARDBASE)
remapRamp *= i.attenuation;
#endif
half4 ramp = tex2D(_Ramp, half2(remapRamp, i.rampMask.r));
return ramp;
}
half4 calcRampShadowOverride(XSLighting i, float ndl)
{
half remapRamp;
remapRamp = (ndl * 0.5 + 0.5) * lerp(1, i.occlusion.r, _OcclusionMode);
half4 ramp = tex2D(_Ramp, half2(remapRamp, i.rampMask.r));
return ramp;
}
float3 getVertexLightsDiffuse(XSLighting i, VertexLightInformation vLight)
{
float3 vertexLightsDiffuse = 0;
#if defined(VERTEXLIGHT_ON)
for(int light = 0; light < 4; light++) // I know, I know, not using i. Blame my structs.
{
float vLightNdl = dot(vLight.Direction[light], i.normal);
vertexLightsDiffuse += calcRampShadowOverride(i, vLightNdl) * vLight.ColorFalloff[light];
}
#endif
return vertexLightsDiffuse;
}
half4 calcMetallicSmoothness(XSLighting i)
{
half roughness = 1-(_Glossiness * i.metallicGlossMap.a);
roughness *= 1.7 - 0.7 * roughness;
half metallic = lerp(0, i.metallicGlossMap.r * _Metallic, i.reflectivityMask.r);
return half4(metallic, 0, 0, roughness);
}
half4 calcRimLight(XSLighting i, DotProducts d, half4 lightCol, half3 indirectDiffuse, half3 envMap)
{
half rimIntensity = saturate((1-d.svdn)) * pow(d.ndl, _RimThreshold);
rimIntensity = smoothstep(_RimRange - _RimSharpness, _RimRange + _RimSharpness, rimIntensity);
half4 rim = rimIntensity * _RimIntensity * (lightCol + indirectDiffuse.xyzz);
rim *= lerp(1, i.attenuation + indirectDiffuse.xyzz, _RimAttenEffect);
return rim * _RimColor * lerp(1, i.diffuseColor.rgbb, _RimAlbedoTint) * lerp(1, envMap.rgbb, _RimCubemapTint);
}
half4 calcShadowRim(XSLighting i, DotProducts d, half3 indirectDiffuse)
{
half rimIntensity = saturate((1-d.svdn)) * pow(1-d.ndl, _ShadowRimThreshold * 2);
rimIntensity = smoothstep(_ShadowRimRange - _ShadowRimSharpness, _ShadowRimRange + _ShadowRimSharpness, rimIntensity);
half4 shadowRim = lerp(1, (_ShadowRim * lerp(1, i.diffuseColor.rgbb, _ShadowRimAlbedoTint)) + (indirectDiffuse.xyzz * 0.1), rimIntensity);
return shadowRim ;
}
float3 getAnisotropicReflectionVector(float3 viewDir, float3 bitangent, float3 tangent, float3 normal, float roughness, float anisotropy)
{
//_Anisotropy = lerp(-0.2, 0.2, sin(_Time.y / 20)); //This is pretty fun
float3 anisotropicDirection = anisotropy >= 0.0 ? bitangent : tangent;
float3 anisotropicTangent = cross(anisotropicDirection, viewDir);
float3 anisotropicNormal = cross(anisotropicTangent, anisotropicDirection);
float bendFactor = abs(anisotropy) * saturate(5.0 * roughness);
float3 bentNormal = normalize(lerp(normal, anisotropicNormal, bendFactor));
return reflect(-viewDir, bentNormal);
}
half3 calcDirectSpecular(XSLighting i, float ndl, float ndh, float vdn, float ldh, half4 lightCol, half3 halfVector, half anisotropy)
{
half specularIntensity = _SpecularIntensity * i.specularMap.r;
half3 specular = half3(0,0,0);
half smoothness = max(0.01, (_SpecularArea * i.specularMap.b));
smoothness *= 1.7 - 0.7 * smoothness;
float rough = max(smoothness * smoothness, 0.0045);
float Dn = D_GGX(ndh, rough);
float3 F = 1-F_Schlick(ldh, 0);
float V = V_SmithGGXCorrelated(vdn, ndl, rough);
float3 directSpecularNonAniso = max(0, (Dn * V) * F);
anisotropy *= saturate(5.0 * smoothness);
float at = max(rough * (1.0 + anisotropy), 0.001);
float ab = max(rough * (1.0 - anisotropy), 0.001);
float D = D_GGX_Anisotropic(ndh, halfVector, i.tangent, i.bitangent, at, ab);
float3 directSpecularAniso = max(0, (D * V) * F);
specular = lerp(directSpecularNonAniso, directSpecularAniso, saturate(abs(anisotropy * 100)));
specular = lerp(specular, smoothstep(0.5, 0.51, specular), _SpecularSharpness) * 3 * lightCol * specularIntensity; // Multiply by 3 to bring up to brightness of standard
specular *= lerp(1, i.diffuseColor, _SpecularAlbedoTint * i.specularMap.g);
return specular;
}
float3 getVertexLightSpecular(XSLighting i, DotProducts d, VertexLightInformation vLight, float3 normal, float3 viewDir, float anisotropy)
{
float3 vertexLightSpec = 0;
#if defined(VERTEXLIGHT_ON)
for(int light = 0; light < 4; light++)
{
// All of these need to be recalculated for each individual light to treat them how we want to treat them.
float3 vHalfVector = normalize(vLight.Direction[light] + viewDir);
float vNDL = saturate(dot(vLight.Direction[light], normal));
float vLDH = saturate(dot(vLight.Direction[light], vHalfVector));
float vNDH = saturate(dot(normal, vHalfVector));
vertexLightSpec += calcDirectSpecular(i, vNDL, vNDH, d.vdn, vLDH, vLight.ColorFalloff[light].rgbb, vHalfVector, anisotropy) * vNDL;
}
#endif
return vertexLightSpec;
}
half3 calcIndirectSpecular(XSLighting i, DotProducts d, half4 metallicSmoothness, half3 reflDir, half3 indirectLight, half3 viewDir, float3 fresnel, half4 ramp)
{//This function handls Unity style reflections, Matcaps, and a baked in fallback cubemap.
half3 spec = half3(0,0,0);
UNITY_BRANCH
if(_ReflectionMode == 0) // PBR
{
#if defined(UNITY_PASS_FORWARDBASE) //Indirect PBR specular should only happen in the forward base pass. Otherwise each extra light adds another indirect sample, which could mean you're getting too much light.
half3 reflectionUV1 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS);
half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR);
half3 indirectSpecular;
half interpolator = unity_SpecCube0_BoxMin.w;
UNITY_BRANCH
if (interpolator < 0.99999)
{
half3 reflectionUV2 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS);
half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR);
indirectSpecular = lerp(probe1sample, probe0sample, interpolator);
}
else
{
indirectSpecular = probe0sample;
}
if (!any(indirectSpecular))
{
indirectSpecular = texCUBElod(_BakedCubemap, half4(reflDir, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS));
indirectSpecular *= indirectLight;
}
spec = indirectSpecular * fresnel;
#endif
}
else if(_ReflectionMode == 1) //Baked Cubemap
{
half3 indirectSpecular = texCUBElod(_BakedCubemap, half4(reflDir, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS));;
spec = indirectSpecular * fresnel;
if(_ReflectionBlendMode != 1)
{
spec *= (indirectLight + (_LightColor0 * i.attenuation) * 0.5);
}
}
else if (_ReflectionMode == 2) //Matcap
{
half3 upVector = half3(0,1,0);
half2 remapUV = matcapSample(upVector, viewDir, i.normal);
spec = tex2Dlod(_Matcap, half4(remapUV, 0, ((1-metallicSmoothness.w) * UNITY_SPECCUBE_LOD_STEPS))) * _MatcapTint;
if(_ReflectionBlendMode != 1)
{
spec *= (indirectLight + (_LightColor0 * i.attenuation) * 0.5);
}
spec *= lerp(1, i.diffuseColor, _MatcapTintToDiffuse);
}
return spec;
}
half4 calcOutlineColor(XSLighting i, DotProducts d, half3 indirectDiffuse, half4 lightCol)
{
half3 outlineColor = half3(0,0,0);
#if defined(Geometry)
half3 ol = lerp(_OutlineColor, _OutlineColor * i.diffuseColor, _OutlineAlbedoTint);
outlineColor = ol * saturate(i.attenuation * d.ndl) * lightCol.rgb;
outlineColor += indirectDiffuse * ol;
outlineColor = lerp(outlineColor, ol, _OutlineLighting);
#endif
return half4(outlineColor,1);
}
half3 calcIndirectDiffuse(XSLighting i)
{// We don't care about anything other than the color from probes for toon lighting.
half3 indirectDiffuse = ShadeSH9(float4(0,0.5,0,1));//half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
return indirectDiffuse;
}
half4 calcDiffuse(XSLighting i, DotProducts d, half3 indirectDiffuse, half4 lightCol, half4 ramp)
{
half4 diffuse;
half4 indirect = indirectDiffuse.xyzz;
half grayIndirect = dot(indirectDiffuse, float3(1,1,1));
half attenFactor = lerp(i.attenuation, 1, smoothstep(0, 0.2, grayIndirect));
diffuse = ramp * attenFactor * lightCol + indirect;
diffuse = i.albedo * diffuse;
return diffuse;
}
//Subsurface Scattering - Based on a 2011 GDC Conference from by Colin Barre-Bresebois & Marc Bouchard
//Modified by Xiexe
half4 calcSubsurfaceScattering(XSLighting i, DotProducts d, half3 lightDir, half3 viewDir, half3 normal, half4 lightCol, half3 indirectDiffuse)
{
UNITY_BRANCH
if(any(_SSColor.rgb)) // Skip all the SSS stuff if the color is 0.
{
//d.ndl = smoothstep(_SSSRange - _SSSSharpness, _SSSRange + _SSSSharpness, d.ndl);
half attenuation = saturate(i.attenuation * (d.ndl * 0.5 + 0.5));
half3 H = normalize(lightDir + normal * _SSDistortion);
half VdotH = pow(saturate(dot(viewDir, -H)), _SSPower);
half3 I = _SSColor * (VdotH + indirectDiffuse) * attenuation * i.thickness * _SSScale;
half4 SSS = half4(lightCol.rgb * I * i.albedo.rgb, 1);
SSS = max(0, SSS); // Make sure it doesn't go NaN
return SSS;
}
else
{
return 0;
}
}
half4 calcEmission(XSLighting i, half lightAvg)
{
#if defined(UNITY_PASS_FORWARDBASE) // Emission only in Base Pass, and vertex lights
float4 emission = lerp(i.emissionMap, i.emissionMap * i.diffuseColor.xyzz, _EmissionToDiffuse);
float4 scaledEmission = emission * saturate(smoothstep(1-_ScaleWithLightSensitivity, 1+_ScaleWithLightSensitivity, 1-lightAvg));
float4 em = lerp(scaledEmission, emission, _ScaleWithLight);
em.rgb = rgb2hsv(em.rgb);
em.x += fmod(_Hue, 360);
em.y = saturate(em.y * _Saturation);
em.z *= _Value;
em.rgb = hsv2rgb(em.rgb);
return em;
#else
return 0;
#endif
}
void calcReflectionBlending(XSLighting i, inout half4 col, half3 indirectSpecular)
{
if(_ReflectionBlendMode == 0) // Additive
col += indirectSpecular.xyzz * i.reflectivityMask.r;
else if(_ReflectionBlendMode == 1) //Multiplicitive
col = lerp(col, col * indirectSpecular.xyzz, i.reflectivityMask.r);
else if(_ReflectionBlendMode == 2) //Subtractive
col -= indirectSpecular.xyzz * i.reflectivityMask.r;
}
void calcClearcoat(inout half4 col, XSLighting i, DotProducts d, half3 untouchedNormal, half3 indirectDiffuse, half3 lightCol, half3 viewDir, half3 lightDir, half4 ramp)
{
UNITY_BRANCH
if(_ClearCoat != 0)
{
untouchedNormal = normalize(untouchedNormal);
half clearcoatSmoothness = _ClearcoatSmoothness * i.metallicGlossMap.g;
half clearcoatStrength = _ClearcoatStrength * i.metallicGlossMap.b;
half3 reflView = calcReflView(viewDir, untouchedNormal);
half3 reflLight = calcReflLight(lightDir, untouchedNormal);
half rdv = saturate( dot( reflLight, half4(-viewDir, 0) ));
half3 clearcoatIndirect = calcIndirectSpecular(i, d, half4(0, 0, 0, 1-clearcoatSmoothness), reflView, indirectDiffuse, viewDir, 1, ramp);
half3 clearcoatDirect = saturate(pow(rdv, clearcoatSmoothness * 256)) * i.attenuation * lightCol;
half3 clearcoat = (clearcoatIndirect + clearcoatDirect) * clearcoatStrength;
clearcoat = lerp(clearcoat * 0.5, clearcoat, saturate(pow(1-dot(viewDir, untouchedNormal), 0.8)) );
col += clearcoat.xyzz;
}
}