ToriaAssets/Sources/Shaders/AtgPBSLighting.cginc
2026-05-19 12:20:15 +02:00

292 lines
9.2 KiB
HLSL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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