292 lines
9.2 KiB
HLSL
292 lines
9.2 KiB
HLSL
|
|
#ifndef AFS_PBS_LIGHTING_INCLUDED
|
|||
|
|
#define AFS_PBS_LIGHTING_INCLUDED
|
|||
|
|
|
|||
|
|
#include "UnityPBSLighting.cginc"
|
|||
|
|
|
|||
|
|
#include "Includes/AtgStandardBRDF.cginc"
|
|||
|
|
|
|||
|
|
|
|||
|
|
//-------------------------------------------------------------------------------------
|
|||
|
|
// Compatibilty settings
|
|||
|
|
// Uncomment either "#define USEALLOY" or "#define USEUBER" to enable deferred lighting support for the given shader package.
|
|||
|
|
// Leave them commented in case you are using the Lux Foliage deferred lighting shader.
|
|||
|
|
// More infos in the docs.
|
|||
|
|
|
|||
|
|
// #define USEALLOY
|
|||
|
|
// #define USEUBER
|
|||
|
|
|
|||
|
|
//-------------------------------------------------------------------------------------
|
|||
|
|
// Debug shader lighting
|
|||
|
|
|
|||
|
|
struct SurfaceOutputATGUnlit
|
|||
|
|
{
|
|||
|
|
fixed3 Albedo;
|
|||
|
|
fixed3 Normal;
|
|||
|
|
half3 Emission;
|
|||
|
|
half Smoothness;
|
|||
|
|
half Occlusion;
|
|||
|
|
fixed Alpha;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
inline half4 LightingATGUnlit (SurfaceOutputATGUnlit s, half3 viewDir, UnityGI gi)
|
|||
|
|
{
|
|||
|
|
half4 c;
|
|||
|
|
c.rgb = s.Albedo;
|
|||
|
|
c.a = s.Alpha;
|
|||
|
|
return c;
|
|||
|
|
}
|
|||
|
|
inline void LightingATGUnlit_GI (
|
|||
|
|
SurfaceOutputATGUnlit s,
|
|||
|
|
UnityGIInput data,
|
|||
|
|
inout UnityGI gi)
|
|||
|
|
{
|
|||
|
|
UNITY_GI(gi, s, data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//-------------------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
#if defined (VERTEXLIT)
|
|||
|
|
half _AfsVertexLitHorizonFade;
|
|||
|
|
#else
|
|||
|
|
half _HorizonFade;
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
//-------------------------------------------------------------------------------------
|
|||
|
|
// Surface shader output structure to be used with physically
|
|||
|
|
// based shading model.
|
|||
|
|
struct SurfaceOutputATGSpecular
|
|||
|
|
{
|
|||
|
|
fixed3 Albedo; // diffuse color
|
|||
|
|
fixed3 Specular; // specular color
|
|||
|
|
fixed3 Normal; // tangent space normal, if written
|
|||
|
|
half3 Emission;
|
|||
|
|
half Smoothness; // 0=rough, 1=smooth
|
|||
|
|
half Occlusion;
|
|||
|
|
fixed Alpha;
|
|||
|
|
fixed Translucency;
|
|||
|
|
half TranslucencyPower;
|
|||
|
|
fixed Lighting;
|
|||
|
|
|
|||
|
|
#if defined (TANGETFREELIGHTING)
|
|||
|
|
fixed3 WorldNormal;
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
fixed3 VertexNormal;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
//-------------------------------------------------------------------------------------
|
|||
|
|
float3x3 GetCotangentFrame( float3 N, float3 p, float2 uv )
|
|||
|
|
{
|
|||
|
|
// get edge vectors of the pixel triangle
|
|||
|
|
float3 dp1 = ddx( p );
|
|||
|
|
float3 dp2 = ddy( p );
|
|||
|
|
float2 duv1 = ddx( uv );
|
|||
|
|
float2 duv2 = ddy( uv );
|
|||
|
|
|
|||
|
|
// solve the linear system
|
|||
|
|
float3 dp2perp = cross( dp2, N );
|
|||
|
|
float3 dp1perp = cross( N, dp1 );
|
|||
|
|
float3 T = -(dp2perp * duv1.x + dp1perp * duv2.x);
|
|||
|
|
|
|||
|
|
float3 B = -(dp2perp * duv1.y + dp1perp * duv2.y); // * unity_WorldTransformParams.w;
|
|||
|
|
|
|||
|
|
// construct a scale-invariant frame
|
|||
|
|
float invmax = rsqrt( max( dot(T,T), dot(B,B) ) );
|
|||
|
|
return float3x3( T * invmax, B * invmax, N );
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// https://forum.libcinder.org/topic/calculating-normals-after-displacing-vertices-in-shader
|
|||
|
|
float3x3 GetCotangentFrameNew( float3 N, float3 p, float2 uv )
|
|||
|
|
{
|
|||
|
|
// calculate tangent and bitangent
|
|||
|
|
float3 P1 = ddx( p );
|
|||
|
|
float3 P2 = ddy( p );
|
|||
|
|
float2 Q1 = ddx( uv );
|
|||
|
|
float2 Q2 = ddy( uv );
|
|||
|
|
|
|||
|
|
float3 T = normalize( P1 * Q2.y - P2 * Q1.y );
|
|||
|
|
float3 B = normalize( P2 * Q1.x - P1 * Q2.x );
|
|||
|
|
|
|||
|
|
// construct tangent space matrix and perturb normal
|
|||
|
|
return float3x3( T, B, N );
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Horizon Occlusion for Normal Mapped Reflections: http://marmosetco.tumblr.com/post/81245981087
|
|||
|
|
float GetHorizonOcclusion(float3 V, float3 normalWS, float3 vertexNormal, float horizonFade)
|
|||
|
|
{
|
|||
|
|
float3 R = reflect(-V, normalWS);
|
|||
|
|
float specularOcclusion = saturate(1.0 + horizonFade * dot(R, vertexNormal));
|
|||
|
|
// smooth it
|
|||
|
|
return specularOcclusion * specularOcclusion;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//-------------------------------------------------------------------------------------
|
|||
|
|
// This is more or less like the "LightingStandardSpecular" but with translucency added on top ond wrapped around diffuse
|
|||
|
|
|
|||
|
|
inline half4 LightingATGSpecular (SurfaceOutputATGSpecular s, half3 viewDir, UnityGI gi)
|
|||
|
|
{
|
|||
|
|
#if defined (TANGETFREELIGHTING)
|
|||
|
|
s.Normal = normalize(s.WorldNormal);
|
|||
|
|
#else
|
|||
|
|
s.Normal = normalize(s.Normal);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// energy conservation
|
|||
|
|
half oneMinusReflectivity;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// As Grass has very strange spec values...
|
|||
|
|
#if defined (ISGRASS)
|
|||
|
|
//half3 skipIt = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular, /*out*/ oneMinusReflectivity);
|
|||
|
|
oneMinusReflectivity = 1 - unity_ColorSpaceDielectricSpec.r;
|
|||
|
|
#else
|
|||
|
|
s.Albedo = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular.rrr, oneMinusReflectivity);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// 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, outputAlpha);
|
|||
|
|
|
|||
|
|
// energy conserving wrapped around diffuse lighting
|
|||
|
|
// http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
|
|||
|
|
//half wrap1 = 0.4;
|
|||
|
|
//half NdotLDirect = saturate( ( dot(s.Normal, gi.light.dir) + wrap1 ) / ( (1 + wrap1) * (1 + wrap1) ) );
|
|||
|
|
half NdotLDirect = saturate(dot(s.Normal, gi.light.dir));
|
|||
|
|
|
|||
|
|
#if defined(ISTREE)
|
|||
|
|
#if !defined(DIRECTIONAL) && !defined(DIRECTIONAL_COOKIE)
|
|||
|
|
// Fade out point and spot lights
|
|||
|
|
gi.light.color *= s.Lighting;
|
|||
|
|
#endif
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// Horizon Occlusion
|
|||
|
|
#if !defined(ISGRASS)
|
|||
|
|
#if defined (VERTEXLIT)
|
|||
|
|
gi.indirect.specular *= GetHorizonOcclusion( -viewDir, s.Normal, s.VertexNormal, _AfsVertexLitHorizonFade );
|
|||
|
|
#else
|
|||
|
|
gi.indirect.specular *= GetHorizonOcclusion( -viewDir, s.Normal, s.VertexNormal, _HorizonFade );
|
|||
|
|
#endif
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
#if !defined(ISGRASS)
|
|||
|
|
half specularIntensity = 1;
|
|||
|
|
s.TranslucencyPower *= 10;
|
|||
|
|
#else
|
|||
|
|
half specularIntensity = s.TranslucencyPower;
|
|||
|
|
s.TranslucencyPower = 6;
|
|||
|
|
s.Specular = unity_ColorSpaceDielectricSpec.rgb;
|
|||
|
|
gi.indirect.specular *= saturate(specularIntensity + 0.5);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
half4 c = BRDF1_ATG_PBS (s.Albedo, s.Specular, oneMinusReflectivity, s.Smoothness, /*NdotLDirect, */s.Normal, viewDir, gi.light, gi.indirect, specularIntensity);
|
|||
|
|
// For gi lighting we simply use the built in BRDF
|
|||
|
|
c.rgb += UNITY_BRDF_GI (s.Albedo, s.Specular, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi);
|
|||
|
|
|
|||
|
|
// Add Translucency – needs light dir and intensity: so real time only
|
|||
|
|
#if !defined(LIGHTMAP_ON)
|
|||
|
|
// Best for grass as the normal counts less
|
|||
|
|
// // https://colinbarrebrisebois.com/2012/04/09/approximating-translucency-revisited-with-simplified-spherical-gaussian/
|
|||
|
|
half3 transLightDir = gi.light.dir + s.Normal * 0.01;
|
|||
|
|
half transDot = dot( -transLightDir, viewDir ); // sign(minus) comes from eyeVec
|
|||
|
|
transDot = exp2(saturate(transDot) * s.TranslucencyPower - s.TranslucencyPower);
|
|||
|
|
half3 lightScattering = transDot * gi.light.color *
|
|||
|
|
#if !defined(ISGRASS)
|
|||
|
|
(1.0 - NdotLDirect)
|
|||
|
|
#else
|
|||
|
|
1.0
|
|||
|
|
#endif
|
|||
|
|
;
|
|||
|
|
c.rgb += s.Albedo * 4.0 * s.Translucency * lightScattering /* mask trans by spec */ * (1.0 - saturate(c.a));
|
|||
|
|
#endif
|
|||
|
|
c.a = outputAlpha;
|
|||
|
|
return c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
inline half4 LightingATGSpecular_Deferred (SurfaceOutputATGSpecular s, half3 viewDir, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal)
|
|||
|
|
{
|
|||
|
|
// energy conservation
|
|||
|
|
half oneMinusReflectivity;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// As Grass has very strange spec values...
|
|||
|
|
#if defined (ISGRASS)
|
|||
|
|
//half3 skipIt = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular, /*out*/ oneMinusReflectivity);
|
|||
|
|
oneMinusReflectivity = 1 - unity_ColorSpaceDielectricSpec.r;
|
|||
|
|
#else
|
|||
|
|
s.Albedo = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular, /*out*/ oneMinusReflectivity);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
#if defined (TANGETFREELIGHTING)
|
|||
|
|
s.Normal = normalize(s.WorldNormal);
|
|||
|
|
#else
|
|||
|
|
s.Normal = normalize(s.Normal);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// Horizon Occlusion
|
|||
|
|
#if !defined(ISGRASS)
|
|||
|
|
#if defined (VERTEXLIT)
|
|||
|
|
gi.indirect.specular *= GetHorizonOcclusion( -viewDir, s.Normal, s.VertexNormal, _AfsVertexLitHorizonFade );
|
|||
|
|
#else
|
|||
|
|
gi.indirect.specular *= GetHorizonOcclusion( -viewDir, s.Normal, s.VertexNormal, _HorizonFade );
|
|||
|
|
#endif
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// Indirect Lighting - needs proper specular in case deferred reflections are disabled
|
|||
|
|
half3 spec = s.Specular;
|
|||
|
|
#if defined(ISGRASS)
|
|||
|
|
spec = unity_ColorSpaceDielectricSpec.rgb;
|
|||
|
|
gi.indirect.specular *= saturate(s.TranslucencyPower + 0.5);
|
|||
|
|
#else
|
|||
|
|
spec = s.Specular.rrr;
|
|||
|
|
#endif
|
|||
|
|
// For indirect lighting we simply use the built in BRDF
|
|||
|
|
half4 c = UNITY_BRDF_PBS (s.Albedo, spec, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
|
|||
|
|
c.rgb += UNITY_BRDF_GI (s.Albedo, spec, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi);
|
|||
|
|
|
|||
|
|
outDiffuseOcclusion = half4(s.Albedo, s.Occlusion);
|
|||
|
|
|
|||
|
|
half4 emission;
|
|||
|
|
// Alloy Support
|
|||
|
|
#if defined (USEALLOY)
|
|||
|
|
outSpecSmoothness = half4(s.Specular, s.Smoothness);
|
|||
|
|
outNormal = half4(s.Normal * 0.5 + 0.5, 1);
|
|||
|
|
emission = half4(s.Emission + c.rgb, s.Translucency);
|
|||
|
|
// UBER Support
|
|||
|
|
#elif defined (USEUBER)
|
|||
|
|
//outDiffuseOcclusion = half4(half3(1,0,0), s.Occlusion);
|
|||
|
|
outSpecSmoothness = half4(s.Specular, s.Smoothness);
|
|||
|
|
float translucency = floor(saturate(s.Translucency) * 15) * (-128);
|
|||
|
|
outNormal = half4(s.Normal * 0.5 + 0.5, 1);
|
|||
|
|
emission = half4(s.Emission + c.rgb, translucency);
|
|||
|
|
// Lux Support
|
|||
|
|
#else
|
|||
|
|
outSpecSmoothness = half4(s.Specular.r, s.TranslucencyPower, s.Translucency, s.Smoothness);
|
|||
|
|
// Mark as translucent
|
|||
|
|
outNormal = half4(s.Normal * 0.5 + 0.5, 0.66);
|
|||
|
|
emission = half4(s.Emission + c.rgb, 1);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
return emission;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
inline void LightingATGSpecular_GI (
|
|||
|
|
SurfaceOutputATGSpecular s,
|
|||
|
|
UnityGIInput data,
|
|||
|
|
inout UnityGI gi)
|
|||
|
|
{
|
|||
|
|
UNITY_GI(gi, s, data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif // AFS_PBS_LIGHTING_INCLUDED
|