Search Unity

Disney Principled BRDF shader

Discussion in 'Shaders' started by GreatWall, May 10, 2019.

  1. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57

    Attached Files:

  2. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    183
    Direct implementation, but still requires improvements:

    Code (CSharp):
    1. Shader "Disney"
    2. {
    3.     Properties
    4.     {
    5.         metallic ("Metallic", Range (0.0,1.0)) = 0.0
    6.         subsurface ("Subsurface", Range (0.0,1.0)) = 0.0
    7.         _specular ("Specular", Range (0.0,1.0)) = 0.0
    8.         roughness ("Roughness", Range (0.0,1.0)) = 0.5
    9.         specularTint ("SpecularTint", Range (0.0,1.0)) = 0.0
    10.         anisotropic ("Anisotropic", Range (0.0,1.0)) = 0.0
    11.         sheen ("Sheen", Range (0.0,1.0)) = 0.0
    12.         sheenTint ("SheenTint", Range (0.0,1.0)) = 0.5
    13.         clearcoat ("Clearcoat", Range (0.0,1.0)) = 0.0
    14.         clearcoatGloss ("ClearcoatGloss", Range (0.0,1.0)) = 1.0
    15.     }
    16.     SubShader
    17.     {
    18.         Pass
    19.         {
    20.             CGPROGRAM
    21.             #pragma vertex VSMain
    22.             #pragma fragment PSMain
    23.  
    24.             static const float3 baseColor = float3(1,1,1);
    25.             float metallic, subsurface, _specular, roughness, specularTint, anisotropic, sheen,
    26.             sheenTint, clearcoat, clearcoatGloss;
    27.                        
    28.             static const float PI = 3.14159265358979323846;
    29.  
    30.             float sqr(float x) { return x*x; }
    31.  
    32.             float SchlickFresnel(float u)
    33.             {
    34.                 float m = clamp(1-u, 0, 1);
    35.                 float m2 = m*m;
    36.                 return m2*m2*m; // pow(m,5)
    37.             }
    38.  
    39.             float GTR1(float NdotH, float a)
    40.             {
    41.                 if (a >= 1) return 1/PI;
    42.                 float a2 = a*a;
    43.                 float t = 1 + (a2-1)*NdotH*NdotH;
    44.                 return (a2-1) / (PI*log(a2)*t);
    45.             }
    46.  
    47.             float GTR2(float NdotH, float a)
    48.             {
    49.                 float a2 = a*a;
    50.                 float t = 1 + (a2-1)*NdotH*NdotH;
    51.                 return a2 / (PI * t*t);
    52.             }
    53.  
    54.             float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
    55.             {
    56.                 return 1 / (PI * ax*ay * sqr( sqr(HdotX/ax) + sqr(HdotY/ay) + NdotH*NdotH ));
    57.             }
    58.  
    59.             float smithG_GGX(float NdotV, float alphaG)
    60.             {
    61.                 float a = alphaG*alphaG;
    62.                 float b = NdotV*NdotV;
    63.                 return 1 / (NdotV + sqrt(a + b - a*b));
    64.             }
    65.  
    66.             float smithG_GGX_aniso(float NdotV, float VdotX, float VdotY, float ax, float ay)
    67.             {
    68.                 return 1 / (NdotV + sqrt( sqr(VdotX*ax) + sqr(VdotY*ay) + sqr(NdotV) ));
    69.             }
    70.  
    71.             float3 mon2lin(float3 x)
    72.             {
    73.                 return float3(pow(x[0], 2.2), pow(x[1], 2.2), pow(x[2], 2.2));
    74.             }
    75.  
    76.             float3 BRDF( float3 L, float3 V, float3 N, float3 X, float3 Y )
    77.             {
    78.                 float NdotL = max(dot(N,L),0.0);
    79.                 float NdotV = max(dot(N,V),0.0);
    80.  
    81.                 float3 H = normalize(L+V);
    82.                 float NdotH = max(dot(N,H),0.0);
    83.                 float LdotH = max(dot(L,H),0.0);
    84.  
    85.                 float3 Cdlin = mon2lin(baseColor);
    86.                 float Cdlum = .3*Cdlin[0] + .6*Cdlin[1]  + .1*Cdlin[2]; // luminance approx.
    87.  
    88.                 float3 Ctint = Cdlum > 0 ? Cdlin/Cdlum : float3(1,1,1); // normalize lum. to isolate hue+sat
    89.                 float3 Cspec0 = lerp(_specular*.08*lerp(float3(1,1,1), Ctint, specularTint), Cdlin, metallic);
    90.                 float3 Csheen = lerp(float3(1,1,1), Ctint, sheenTint);
    91.  
    92.                 // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
    93.                 // and lerp in diffuse retro-reflection based on roughness
    94.                 float FL = SchlickFresnel(NdotL), FV = SchlickFresnel(NdotV);
    95.                 float Fd90 = 0.5 + 2 * LdotH*LdotH * roughness;
    96.                 float Fd = lerp(1.0, Fd90, FL) * lerp(1.0, Fd90, FV);
    97.  
    98.                 // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
    99.                 // 1.25 scale is used to (roughly) preserve albedo
    100.                 // Fss90 used to "flatten" retroreflection based on roughness
    101.                 float Fss90 = LdotH*LdotH*roughness;
    102.                 float Fss = lerp(1.0, Fss90, FL) * lerp(1.0, Fss90, FV);
    103.                 float ss = 1.25 * (Fss * (1 / (NdotL + NdotV) - .5) + .5);
    104.  
    105.                 // specular
    106.                 float aspect = sqrt(1-anisotropic*.9);
    107.                 float ax = max(.001, sqr(roughness)/aspect);
    108.                 float ay = max(.001, sqr(roughness)*aspect);
    109.                 float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay);
    110.                 float FH = SchlickFresnel(LdotH);
    111.                 float3 Fs = lerp(Cspec0, float3(1,1,1), FH);
    112.                 float Gs  = smithG_GGX_aniso(NdotL, dot(L, X), dot(L, Y), ax, ay);
    113.                 Gs *= smithG_GGX_aniso(NdotV, dot(V, X), dot(V, Y), ax, ay);
    114.  
    115.                 // sheen
    116.                 float3 Fsheen = FH * sheen * Csheen;
    117.  
    118.                 // clearcoat (ior = 1.5 -> F0 = 0.04)
    119.                 float Dr = GTR1(NdotH, lerp(.1,.001,clearcoatGloss));
    120.                 float Fr = lerp(.04, 1.0, FH);
    121.                 float Gr = smithG_GGX(NdotL, .25) * smithG_GGX(NdotV, .25);
    122.  
    123.                 return ((1/PI) * lerp(Fd, ss, subsurface)*Cdlin + Fsheen) * (1-metallic) + Gs*Fs*Ds + .25*clearcoat*Gr*Fr*Dr;
    124.             }
    125.            
    126.             void VSMain (inout float4 vertex:POSITION, inout float2 uv:TEXCOORD0, inout float3 normal:NORMAL, inout float4 tangent:TANGENT, out float3 world:TEXCOORD1)
    127.             {
    128.                 world = mul(unity_ObjectToWorld, vertex).xyz;
    129.                 vertex = UnityObjectToClipPos(vertex);
    130.             }
    131.  
    132.             float4 PSMain (float4 vertex:POSITION, float2 uv:TEXCOORD0, float3 normal:NORMAL, float4 tangent:TANGENT, float3 world:TEXCOORD1) : SV_TARGET
    133.             {
    134.                 float3 LightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - world,_WorldSpaceLightPos0.w));
    135.                 float3 NormalDirection = normalize(mul((float3x3)unity_ObjectToWorld,normal));
    136.                 float3 ViewDirection = normalize( _WorldSpaceCameraPos.xyz - world);
    137.                 float3 WorldTangent = mul((float3x3)unity_ObjectToWorld,tangent.xyz);
    138.                 float3 WorldBinormal = cross(NormalDirection,WorldTangent)*tangent.w;
    139.                 return float4(BRDF( LightDirection, ViewDirection, NormalDirection, WorldTangent, WorldBinormal ), 1.0);
    140.             }
    141.             ENDCG
    142.         }
    143.     }
    144. }
    145.  
     
  3. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
unityunity