Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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:
    327
    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