Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Shader "BRDF/Shader"
- {
- Properties
- {
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _BumpMap ("Normalmap", 2D) = "bump" {}
- _Roughness ("Roughness", Range (0.0, 1.0)) = 1
- _SubColor ("Subsurface Color", Color) = (1.0, 1.0, 1.0, 1.0)
- //_NoV ("NoV", Range (0.0, 1.0)) = 1
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 200
- CGPROGRAM
- #pragma surface surf PhysicallyBased
- #pragma target 3.0
- sampler2D _MainTex;
- sampler2D _BumpMap;
- float _Roughness;
- fixed4 _SubColor;
- //half _NoV;
- struct Input
- {
- float2 uv_MainTex;
- float2 uv_BumpMap;
- float2 uv_GlossMap;
- //float3 worldNormal;
- };
- //----------------------------------------------------------------------------
- // Common.usf
- //----------------------------------------------------------------------------
- //#define MaterialFloat half
- //#define MaterialFloat3 half3
- #define MaterialFloat float
- #define MaterialFloat3 float3
- // Clamp the base, so it's never <= 0.0f (INF/NaN).
- MaterialFloat ClampedPow(MaterialFloat X,MaterialFloat Y)
- {
- return pow(max(abs(X),0.000001f),Y);
- }
- // Use this function to compute the pow() in the specular computation.
- // This allows to change the implementation depending on platform or it easily can be replaced by some approxmation.
- MaterialFloat PhongShadingPow(MaterialFloat X, MaterialFloat Y)
- {
- // The following clamping is done to prevent NaN being the result of the specular power computation.
- // Clamping has a minor performance cost.
- // In HLSL pow(a, b) is implemented as exp2(log2(a) * b).
- // For a=0 this becomes exp2(-inf * 0) = exp2(NaN) = NaN.
- // As seen in #TTP 160394 "QA Regression: PS3: Some maps have black pixelated artifacting."
- // this can cause severe image artifacts (problem was caused by specular power of 0, lightshafts propagated this to other pixels).
- // The problem appeared on PlayStation 3 but can also happen on similar PC NVidia hardware.
- // In order to avoid platform differences and rarely occuring image atrifacts we clamp the base.
- // Note: Clamping the exponent seemed to fix the issue mentioned TTP but we decided to fix the root and accept the
- // minor performance cost.
- return ClampedPow(X, Y);
- }
- float Square( float x )
- {
- return x*x;
- }
- MaterialFloat LuminanceUE( MaterialFloat3 LinearColor )
- {
- return dot( LinearColor, MaterialFloat3( 0.3, 0.59, 0.11 ) );
- }
- //----------------------------------------------------------------------------
- // BRDF.utf
- //----------------------------------------------------------------------------
- // Physically based shading model
- // parameterized with the below options
- // Microfacet specular = D*G*F / (4*NoL*NoV) = D*Vis*F
- // Vis = G / (4*NoL*NoV)
- // Diffuse model
- // 0: Lambert
- // 1: Burley
- // 2: Oren-Nayar
- #define PHYSICAL_DIFFUSE 0
- // Microfacet distribution function
- // 0: Blinn
- // 1: Beckmann
- // 2: GGX
- #define PHYSICAL_SPEC_D 2
- // Geometric attenuation or shadowing
- // 0: Implicit
- // 1: Neumann
- // 2: Kelemen
- // 3: Schlick
- // 4: Smith (matched to GGX)
- // TODO: со Smith проблема. Нужна функция rcp из HLSL, я не знаю ее аналога (кроме того она доступна только на SM5)
- // поэтому функция выключена
- #define PHYSICAL_SPEC_G 3
- // Fresnel
- // 0: None
- // 1: Schlick
- // 2: Fresnel
- #define PHYSICAL_SPEC_F 1
- #define PI 3.14159265358979323846
- float3 Diffuse_Lambert( float3 DiffuseColor )
- {
- return DiffuseColor / PI;
- }
- // [Burley 2012, "Physically-Based Shading at Disney"]
- float3 Diffuse_Burley( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
- {
- float FD90 = 0.5 + 2 * VoH * VoH * Roughness;
- float FdV = 1 + (FD90 - 1) * exp2( (-5.55473 * NoV - 6.98316) * NoV );
- float FdL = 1 + (FD90 - 1) * exp2( (-5.55473 * NoL - 6.98316) * NoL );
- return DiffuseColor / PI * FdV * FdL;
- }
- // [Gotanda 2012, "Beyond a Simple Physically Based Blinn-Phong Model in Real-Time"]
- float3 Diffuse_OrenNayar( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
- {
- float VoL = 2 * VoH - 1;
- float m = Roughness * Roughness;
- float m2 = m * m;
- float C1 = 1 - 0.5 * m2 / (m2 + 0.33);
- float Cosri = VoL - NoV * NoL;
- float C2 = 0.45 * m2 / (m2 + 0.09) * Cosri * ( Cosri >= 0 ? min( 1, NoL / NoV ) : NoL );
- return DiffuseColor / PI * ( NoL * C1 + C2 );
- }
- // [Blinn 1977, "Models of light reflection for computer synthesized pictures"]
- float D_Blinn( float Roughness, float NoH )
- {
- float m = Roughness * Roughness;
- float m2 = m * m;
- float n = 2 / m2 - 2;
- return (n+2) / (2*PI) * PhongShadingPow( NoH, n ); // 1 mad, 1 exp, 1 mul, 1 log
- }
- // [Beckmann 1963, "The scattering of electromagnetic waves from rough surfaces"]
- float D_Beckmann( float Roughness, float NoH )
- {
- float m = Roughness * Roughness;
- float m2 = m * m;
- float NoH2 = NoH * NoH;
- return exp( (NoH2 - 1) / (m2 * NoH2) ) / ( PI * m2 * NoH2 * NoH2 );
- }
- // GGX / Trowbridge-Reitz
- // [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
- float D_GGX( float Roughness, float NoH )
- {
- float m = Roughness * Roughness;
- float m2 = m * m;
- float d = ( NoH * m2 - NoH ) * NoH + 1; // 2 mad
- return m2 / ( PI*d*d ); // 3 mul, 1 rcp
- }
- // Anisotropic GGX
- // [Burley 2012, "Physically-Based Shading at Disney"]
- float D_GGXaniso( float RoughnessX, float RoughnessY, float NoH, float3 H, float3 X, float3 Y )
- {
- float mx = RoughnessX * RoughnessX;
- float my = RoughnessY * RoughnessY;
- float XoH = dot( X, H );
- float YoH = dot( Y, H );
- float d = XoH*XoH / (mx*mx) + YoH*YoH / (my*my) + NoH*NoH;
- return 1 / ( PI * mx*my * d*d );
- }
- float Vis_Implicit()
- {
- return 0.25;
- }
- // [Neumann et al. 1999, "Compact metallic reflectance models"]
- float Vis_Neumann( float NoV, float NoL )
- {
- return 1 / ( 4 * max( NoL, NoV ) );
- }
- // [Kelemen 2001, "A microfacet based coupled specular-matte brdf model with importance sampling"]
- float Vis_Kelemen( float3 L, float3 V )
- {
- return 1 / ( 2 + 2 * dot(L, V) );
- }
- // Tuned to match behavior of Vis_Smith
- // [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
- float Vis_Schlick( float Roughness, float NoV, float NoL )
- {
- float k = Square( Roughness ) * 0.5;
- float Vis_SchlickV = NoV * (1 - k) + k;
- float Vis_SchlickL = NoL * (1 - k) + k;
- return 0.25 / ( Vis_SchlickV * Vis_SchlickL );
- }
- // Smith term for GGX
- // [Smith 1967, "Geometrical shadowing of a random rough surface"]
- //float Vis_Smith( float Roughness, float NoV, float NoL )
- //{
- // float a = Square( Roughness );
- // float a2 = a*a;
- // float Vis_SmithV = NoV + sqrt( NoV * (NoV - NoV * a2) + a2 );
- // float Vis_SmithL = NoL + sqrt( NoL * (NoL - NoL * a2) + a2 );
- // return rcp( Vis_SmithV * Vis_SmithL );
- //}
- float3 F_None( float3 SpecularColor )
- {
- return SpecularColor;
- }
- // [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
- // [Lagarde 2012, "Spherical Gaussian approximation for Blinn-Phong, Phong and Fresnel"]
- float3 F_Schlick( float3 SpecularColor, float VoH )
- {
- // Anything less than 2% is physically impossible and is instead considered to be shadowing
- return SpecularColor + ( saturate( 50.0 * SpecularColor.g ) - SpecularColor ) * exp2( (-5.55473 * VoH - 6.98316) * VoH );
- //float Fc = exp2( (-5.55473 * VoH - 6.98316) * VoH ); // 1 mad, 1 mul, 1 exp
- //return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
- }
- float3 F_Fresnel( float3 SpecularColor, float VoH )
- {
- float3 SpecularColorSqrt = sqrt( clamp( float3(0, 0, 0), float3(0.99, 0.99, 0.99), SpecularColor ) );
- float3 n = ( 1 + SpecularColorSqrt ) / ( 1 - SpecularColorSqrt );
- float3 g = sqrt( n*n + VoH*VoH - 1 );
- return 0.5 * Square( (g - VoH) / (g + VoH) ) * ( 1 + Square( ((g+VoH)*VoH - 1) / ((g-VoH)*VoH + 1) ) );
- }
- float3 Diffuse( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
- {
- #if PHYSICAL_DIFFUSE == 0
- return Diffuse_Lambert( DiffuseColor );
- #elif PHYSICAL_DIFFUSE == 1
- return Diffuse_Burley( DiffuseColor, Roughness, NoV, NoL, VoH );
- #elif PHYSICAL_DIFFUSE == 2
- return Diffuse_OrenNayar( DiffuseColor, Roughness, NoV, NoL, VoH );
- #endif
- }
- float Distribution( float Roughness, float NoH )
- {
- #if PHYSICAL_SPEC_D == 0
- return D_Blinn( Roughness, NoH );
- #elif PHYSICAL_SPEC_D == 1
- return D_Beckmann( Roughness, NoH );
- #elif PHYSICAL_SPEC_D == 2
- return D_GGX( Roughness, NoH );
- #endif
- }
- // Vis = G / (4*NoL*NoV)
- float GeometricVisibility( float Roughness, float NoV, float NoL, float VoH, float3 L, float3 V )
- {
- #if PHYSICAL_SPEC_G == 0
- return Vis_Implicit();
- #elif PHYSICAL_SPEC_G == 1
- return Vis_Neumann( NoV, NoL );
- #elif PHYSICAL_SPEC_G == 2
- return Vis_Kelemen( L, V );
- #elif PHYSICAL_SPEC_G == 3
- return Vis_Schlick( Roughness, NoV, NoL );
- #elif PHYSICAL_SPEC_G == 4
- return Vis_Smith( Roughness, NoV, NoL );
- #endif
- }
- float3 Fresnel( float3 SpecularColor, float VoH )
- {
- #if PHYSICAL_SPEC_F == 0
- return F_None( SpecularColor );
- #elif PHYSICAL_SPEC_F == 1
- return F_Schlick( SpecularColor, VoH );
- #elif PHYSICAL_SPEC_F == 2
- return F_Fresnel( SpecularColor, VoH );
- #endif
- }
- //----------------------------------------------------------------------------
- // DeferredLightingCommon.usf
- //----------------------------------------------------------------------------
- // greatly reduces shadow mapping artifacts
- float BiasedNDotL(float NDotLWithoutSaturate )
- {
- return saturate(NDotLWithoutSaturate * 1.08f - 0.08f);
- }
- float3 PointLightDiffuse(SurfaceOutput s, float3 VectorToLight, float3 V, half3 N )
- {
- float3 L = VectorToLight;
- float3 H = normalize(V + L);
- float NoL = saturate( dot(N, L) );
- float NoV = saturate( dot(N, V) );
- float VoH = saturate( dot(V, H) );
- return Diffuse( s.Albedo, _Roughness, NoV, NoL, VoH );
- }
- float3 PointLightSpecular(SurfaceOutput s, float3 VectorToLight, float3 V, half3 N)
- {
- float Roughness = _Roughness;
- float Energy = 1;
- //Roughness = max( Roughness, LightData.MinRoughness ); // может кому пригодится
- // TODO: код Spot
- float a = Roughness * Roughness;
- //const float SourceRadius = LightData.SpotAnglesAndSourceRadius.z;
- //const float SourceLength = LightData.SpotAnglesAndSourceRadius.w;
- const float SourceRadius = 1.0;
- const float SourceLength = 1.0;
- float3 R = reflect( -V, N );
- float RLengthL = rsqrt( dot( VectorToLight, VectorToLight ) );
- if( SourceLength > 0 )
- {
- // Energy conservation
- // asin(x) is angle to sphere, atan(x) is angle to disk, saturate(x) is free and in the middle
- float LineAngle = saturate( SourceLength * RLengthL );
- Energy *= a / saturate( a + 0.5 * LineAngle );
- // Closest point on line segment to ray
- //float3 Ld = LightData.LightDirection * SourceLength;
- float3 Ld = VectorToLight * SourceLength;
- float3 L0 = VectorToLight - 0.5 * Ld;
- float3 L1 = VectorToLight + 0.5 * Ld;
- // Shortest distance
- float a = Square( SourceLength );
- float b = dot( R, Ld );
- float t = saturate( dot( L0, b*R - Ld ) / (a - b*b) );
- VectorToLight = L0 + t * Ld;
- }
- if( SourceRadius > 0 )
- {
- // Energy conservation
- // asin(x) is angle to sphere, atan(x) is angle to disk, saturate(x) is free and in the middle
- float SphereAngle = saturate( SourceRadius * RLengthL );
- Energy *= Square( a / saturate( a + 0.5 * SphereAngle ) );
- // Closest point on sphere to ray
- float3 ClosestPointOnRay = dot( VectorToLight, R ) * R;
- float3 CenterToRay = ClosestPointOnRay - VectorToLight;
- float3 ClosestPointOnSphere = VectorToLight + CenterToRay * saturate( SourceRadius * rsqrt( dot( CenterToRay, CenterToRay ) ) );
- VectorToLight = ClosestPointOnSphere;
- }
- // TODO: код Spot
- //float3 L = VectorToLight;
- float3 L = normalize( VectorToLight );
- float3 H = normalize(V + L);
- float NoL = saturate( dot(N, L) );
- float NoV = saturate( dot(N, V) );
- float NoH = saturate( dot(N, H) );
- float VoH = saturate( dot(V, H) );
- // Generalized microfacet specular
- float D = Distribution( Roughness, NoH );
- float Vis = GeometricVisibility( Roughness, NoV, NoL, VoH, L, V );
- float3 F = Fresnel( s.Specular, VoH );
- return (Energy * D * Vis) * F;
- }
- float3 PointLightSubsurface(SurfaceOutput s, float3 L, float3 V, half3 N, float SubsurfaceExtinction )
- {
- float3 H = normalize(V + L);
- // to get an effect when you see through the material
- // hard coded pow constant
- float InScatter = pow(saturate(dot(L, -V)), 12) * lerp(3, .1f, s.Alpha);
- // wrap around lighting, /(PI*2) to be energy consistent (hack do get some view dependnt and light dependent effect)
- float OpacityFactor = s.Alpha ;
- // Opacity of 0 gives no normal dependent lighting, Opacity of 1 gives strong normal contribution
- float NormalContribution = saturate(dot(N, H) * OpacityFactor + 1 - OpacityFactor);
- //float BackScatter = InGBufferData.GBufferAO * NormalContribution / (PI * 2);
- float BackScatter = NormalContribution / (PI * 2);
- // lerp to never exceed 1 (energy conserving)
- //return InGBufferData.SubsurfaceColor * (lerp(BackScatter, 1, InScatter) * SubsurfaceExtinction);
- return _SubColor * (lerp(BackScatter, 1, InScatter) * SubsurfaceExtinction);
- }
- // Calculates lighting for a given position, normal, etc with a fully featured lighting model designed for quality. */
- float4 GetDynamicLighting(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
- {
- // TODO: N - это мировая нормаль, над убедиться что s.Normal это оно же
- // TODO: почистить функции от всяких там нормализаций, то есть надо в них сразу кидать подсчитанное
- float3 N = s.Normal;
- float3 L = normalize(lightDir); // TODO: возможно без нормализации
- float NoL = BiasedNDotL( dot(N, L) );
- float DistanceAttenuation = atten;
- float LightRadiusMask = 1;
- float SpotFalloff = 1;
- half4 OutLighting = 0;
- if (LightRadiusMask > 0 && SpotFalloff > 0)
- {
- float OpaqueShadowTerm = 1;
- float SSSShadowTerm = 1;
- float NonShadowedAttenuation = DistanceAttenuation * LightRadiusMask * SpotFalloff;
- float ShadowedAttenuation = NonShadowedAttenuation * OpaqueShadowTerm;
- // cull behind light (saving shading computations, might not be faster on some hardware)
- ShadowedAttenuation *= saturate(dot(L, N) * 100000);
- // optimization that should help if there are a lot of shadowed pixels
- if (ShadowedAttenuation > 0)
- {
- //const float3 LightColor = LightData.LightColorAndFalloffExponent.rgb;
- const float3 LightColor = s.Albedo;
- float3 DiffuseLighting = PointLightDiffuse( s, L, viewDir, N );
- float3 SpecularLighting = PointLightSpecular( s, L, viewDir, N );
- float3 SubsurfaceLighting = PointLightSubsurface( s, L, viewDir, N, SSSShadowTerm );
- float4 LightColor4 = float4(LightColor, LuminanceUE(LightColor));
- float4 DiffuseLighting4 = float4(DiffuseLighting, 0);
- float4 SpecularLighting4 = float4(SpecularLighting, LuminanceUE(SpecularLighting));
- float4 SubsurfaceLighting4 = float4(SubsurfaceLighting, 0);
- OutLighting += LightColor4 * ( (NoL * ShadowedAttenuation) *
- (DiffuseLighting4 + SpecularLighting4) +
- SubsurfaceLighting4 * NonShadowedAttenuation );
- }
- }
- return OutLighting;
- }
- //----------------------------------------------------------------------------
- // Shader
- //----------------------------------------------------------------------------
- void surf (Input IN, inout SurfaceOutput o)
- {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
- o.Albedo = c.rgb;
- o.Alpha = c.a;
- o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
- o.Specular = c.a;// * _Roughness;
- o.Gloss = c.a;
- }
- fixed4 LightingPhysicallyBased(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
- {
- return GetDynamicLighting(s, lightDir, viewDir, atten);
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
Advertisement
Add Comment
Please, Sign In to add comment