What do you know about this notehttps://zhuanlan.zhihu.com/p/260922654

Time: July to December 2020

Modified: 20201213

Statement: This article is a personal study note. I’ll review it myself and enjoy communicating. If there is infringement, error or different understanding in the article, please leave a message: correct and give advice, and I will correct it in time. My highest respect!

Cognition: micro surface theory, energy conservation theory, etc. (see resources)

There are three notes in PBR series. This is the first of the series: Analysis Based on Disney BRDF algorithm

catalogue

- preface
- Disney BRDF source code and corresponding implementation

preface

PBR: former PBR and current PBR. Front PBR: inconvenient to use, unsatisfactory rendering, non art oriented. Now PBR: algorithm optimization, art oriented, saving time and cost. Find new horizons in subjective (artistic effect) and objective (physical reality). Sacrifice physics to improve artistic effect, or sacrifice artistic effect to improve physical accuracy.

From Disney’s speech and open source, it gives the industry standards: always art oriented (art first); concise core controllable parameters; sharing of material sampling data… And so on (generous sharing, admirable).

As master Peter Drucker said, honor depends on contribution; Look at the contribution to the whole society, the whole human group, and the whole civilization. Disney’s speech and open source have epoch-making significance for physical rendering technology.

The prerequisite knowledge for discussion: color space (see the data manipulation and system notes in common graphics in the previous discussion – color space. The previous notes are the basic knowledge required for the later notes).

https://zhuanlan.zhihu.com/p/203847313zhuanlan.zhihu.com

Disney BRDF source code

https://github.com/wdas/brdf/blob/master/src/brdfs/disney.brdfgithub.com

```
analytic
# Copyright Disney Enterprises, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License
# and the following modification to it: Section 6 Trademarks.
# deleted and replaced with:
#
# 6. Trademarks. This License does not grant permission to use the
# trade names, trademarks, service marks, or product names of the
# Licensor and its affiliates, except as required for reproducing
# the content of the NOTICE file.
#
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# variables go here...
# [type] [name] [min val] [max val] [default val]
::begin parameters
color baseColor .82 .67 .16
//Solid colored
float metallic 0 1 0
//Metallicity (metal (0 = dielectric, 1 = metal, semiconductor between 0-1) do not use semiconductor modulation effect unless special needs
float subsurface 0 1 0
//Subsurface, controlling diffuse shape
float specular 0 1 .5
//Specular reflection intensity, instead of refractive index
float roughness 0 1 .5
//Roughness, controlling diffuse and specular reflections
float specularTint 0 1 0
//Specular reflection color, the concession of physics to art
float anisotropic 0 1 0
//Anisotropy, aspect ratio of highlights
float sheen 0 1 0
//Gloss, for cloth
float sheenTint 0 1 .5
//Sheen color control
float clearcoat 0 1 0
//Varnish, second high gloss
float clearcoatGloss 0 1 1
//Gloss of varnish, 0 = "Satin", 1 = "gloss"
::end parameters
::begin shader
const float PI = 3.14159265358979323846;
//PI
float sqr(float x) { return x*x; }
//Square
float SchlickFresnel(float u)
{// schlickfresnel Fresnel
float m = clamp(1-u, 0, 1);
//Reverse and limit to 0-1
float m2 = m*m;
//Square
return m2*m2*m; // 5th power
}
float GTR1(float NdotH, float a)
{
if (a >= 1) return 1/PI;
//If a is greater than or equal to 1, the reciprocal of PI is returned
float a2 = a*a;
float t = 1 + (a2-1)*NdotH*NdotH;
return (a2-1) / (PI*log(a2)*t);
}
float GTR2(float NdotH, float a)
{
float a2 = a*a;
float t = 1 + (a2-1)*NdotH*NdotH;
return a2 / (PI * t*t);
}
float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
return 1 / (PI * ax*ay * sqr( sqr(HdotX/ax) + sqr(HdotY/ay) + NdotH*NdotH ));
}
float smithG_GGX(float NdotV, float alphaG)
{
float a = alphaG*alphaG;
float b = NdotV*NdotV;
return 1 / (NdotV + sqrt(a + b - a*b));
}
float smithG_GGX_aniso(float NdotV, float VdotX, float VdotY, float ax, float ay)
{
return 1 / (NdotV + sqrt( sqr(VdotX*ax) + sqr(VdotY*ay) + sqr(NdotV) ));
}
vec3 mon2lin(vec3 x)
{
return vec3(pow(x[0], 2.2), pow(x[1], 2.2), pow(x[2], 2.2));
}
vec3 BRDF( vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y )
{
float NdotL = dot(N,L);
float NdotV = dot(N,V);
if (NdotL < 0 || NdotV < 0) return vec3(0);
//Constraints, if less than 0, are meaningless
vec3 H = normalize(L+V);
float NdotH = dot(N,H);
float LdotH = dot(L,H);
vec3 Cdlin = mon2lin(baseColor);
float Cdlum = .3*Cdlin[0] + .6*Cdlin[1] + .1*Cdlin[2]; // luminance approx.
vec3 Ctint = Cdlum > 0 ? Cdlin/Cdlum : vec3(1); // normalize lum. to isolate hue+sat
vec3 Cspec0 = mix(specular*.08*mix(vec3(1), Ctint, specularTint), Cdlin, metallic);
vec3 Csheen = mix(vec3(1), Ctint, sheenTint);
//Diffuse Fresnel - from 1 of normal incidence to 0.5 of grazing
//Diffuse reflectance is mixed according to roughness
float FL = SchlickFresnel(NdotL), FV = SchlickFresnel(NdotV);
float Fd90 = 0.5 + 2 * LdotH*LdotH * roughness;
float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
//Hanrahan Krueger BRDF approximation based on isotropic BSSRDF
//1.25 scale for (approximate) retained albedo
//Fss90 is used to "flatten" roughness based retroreflection
float Fss90 = LdotH*LdotH*roughness;
float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
float ss = 1.25 * (Fss * (1 / (NdotL + NdotV) - .5) + .5);
// specular
float aspect = sqrt(1-anisotropic*.9);
float ax = max(.001, sqr(roughness)/aspect);
float ay = max(.001, sqr(roughness)*aspect);
float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay);
float FH = SchlickFresnel(LdotH);
vec3 Fs = mix(Cspec0, vec3(1), FH);
float Gs;
Gs = smithG_GGX_aniso(NdotL, dot(L, X), dot(L, Y), ax, ay);
Gs *= smithG_GGX_aniso(NdotV, dot(V, X), dot(V, Y), ax, ay);
// sheen
vec3 Fsheen = FH * sheen * Csheen;
// clearcoat (ior = 1.5 -> F0 = 0.04)
float Dr = GTR1(NdotH, mix(.1,.001,clearcoatGloss));
float Fr = mix(.04, 1.0, FH);
float Gr = smithG_GGX(NdotL, .25) * smithG_GGX(NdotV, .25);
return ((1/PI) * mix(Fd, ss, subsurface)*Cdlin + Fsheen)
* (1-metallic)
+ Gs*Fs*Ds + .25*clearcoat*Gr*Fr*Dr;
}
::end shader
```

Implementation of Disney BRDF decomposition

Route and analysis:

First, data resources, before equation calculation, access the correctness of data.

The matching map resources should be correct. Distinguish between gamma space and linear space data resources. PBR workflow has two directions, specific workflow and metallic workflow. In recent years, metallic workflow has been mainly used in games. The main reason is that channel splitting is conducive to iteration (more intuitive parameters and more accurate numerical calculation), which will save more time and cost. This note is also based on metallic flow. Mapping resources in different workflow directions are also different.

Second, Disney function analysis (source code analysis):

Brief description of the equation: Based on the theory of micro surface and energy conservation.

- Diffuse, usually assumed to be expressed as a Lambert diffusion term, is a constant value.
- The fractional form on the right is specular specular:

D is the distribution in the normal direction of the micro surface. Specular highlights, specular shapes;

F is Fresnel reflection coefficient;

G is the geometric change of micro surface, micro geometric term, shadow and mask (mask) of micro surface, and factor.

θ H is the angle between normal N and half vector h, ndoth;

θ D is the “difference” angle between L and H half vector H (or symmetrically V and H), ldoth or vdoth;

θ L is the incidence angle of L vector relative to normal n, ndotl;

θ V is the angle of incidence of the V vector relative to the normal n, ndotv.

The whole function is too complex and huge at first glance. The parameters inside are also complex and confusing. So there is a better way: split it. (the function is diffuse + specular)

Part I: diffuse subsurface scattering: diffuse reflection term (the literature points out that the diffuse reflection term is classified into the subsurface scattering term)

Diffusion model. It is generally assumed that, It is expressed by a constant value of Lambert diffusion (the intensity of diffuse reflection in all directions is the same, so it needs to be divided by π). Therefore, ordinary Lambert is different from BRDF Lambert (the ordinary Lambert lightmode NDL factor is part of the BRDF diffuse reflection equation). Gossip: everything has scattering, and metals are no exception. Only weak calculations are deliberately ignored in the calculation and simulation (energy conservation, only black holes can fully absorb energy without reflecting energy).

Three basic BRDF diffusion models: Lambert, Oren Nayar, Hanrahan Krueger

Disney diffuse

among

Parameters:

Basecolor surface color (diffcolor calculated according to map metallic information, in metallicsetup)

Roughness

cosθl NdotL

cosθv NdotV

cos θ D ldoth or vdoth

cos θ D is written in two different ways, one is unity ldoth, the other is Disney ldoth, and the other is UE Voh.

```
// Unity UnityStandardBRDF. Cginc file
//Note: Disney diffuse must be multiplied by diffuse albedo / PI. This is done outside of this function.
half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
//Two Schlick Fresnel terms
half lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));
half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));
return lightScatter * viewScatter;
}
//BRDF1_Unity_PBS
//Disney diffuse item
half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;
//I took NL here
// UE4 BRDF. In the ush file
// [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) * Pow5( 1 - NoV );
float FdL = 1 + (FD90 - 1) * Pow5( 1 - NoL );
return DiffuseColor * ( (1 / PI) * FdV * FdL );
}
```

Part II: the right part of the formula (surface reflection: specular reflection term)

The unity implementation is somewhat different from the Disney formula: DFG (Disney) – > > DFV (unity), which replaces the G item with the V item, but the overall framework is the same. There are detailed notes in the direct lighting section of the unity URP litshader.

2.1、D( θ h) Specular D observation (distribution in the normal direction of the micro surface) specular reflection highlight, highlight shape.

Introduced and called generalized Trowbridge Reitz, or GTR.

Parameters:

C scaling constant

α The roughness parameter (commonly known as perceptual roughness map) is between 0-1

θ H is ndh

γ Index value

In BRDF, GTR 2 (main mirror lobe) is first used for the anisotropic and or isotropic metal or non-metal of the base material (commonly known as the lower highlight); GTR 1 (secondary mirror lobe) is second used for the upper transparent coating material (clearcoat varnish material, commonly known as the upper highlight), which is isotropic and non-metallic. (two layer highlight concept, such as car paint: metal layer + varnish layer, and the thickness of varnish is included in the calculation. The varnish is on the top and the metal is on the bottom, and both layers have different highlight effects. Development trend: more complex multi-layer highlight calculation)

```
// UnityBuiltin UnityStandardBRDF. Cginc file
inline float GGXTerm (float NdotH, float roughness)
{// corresponding to Disney GTR2 lower layer
float a2 = roughness * roughness;
float d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad
return UNITY_ INV_ PI * a2 / (d * d + 1e-7f); // This feature is not suitable for running on mobile,
//Therefore, epsilon is less than half
}
// UE4 BRDF. Anisotropic GGX in ush file
// [Burley 2012, "Physically-Based Shading at Disney"]
float D_GGXaniso( float ax, float ay, float NoH, float3 H, float3 X, float3 Y )
{
float XoH = dot( X, H );
float YoH = dot( Y, H );
float d = XoH*XoH / (ax*ax) + YoH*YoH / (ay*ay) + NoH*NoH;
return 1 / ( PI * ax*ay * d*d );
}
```

Disney GTR (gtr1 is γ＝ 1. GTR2 is γ＝ 2）

```
float GTR1(float NdotH, float a)
{
if (a >= 1) return 1/PI;
//If a is greater than or equal to 1, the reciprocal of PI is returned
float a2 = a*a;
float t = 1 + (a2-1)*NdotH*NdotH;
return (a2-1) / (PI*log(a2)*t);
}
float GTR2(float NdotH, float a)
{
float a2 = a*a;
float t = 1 + (a2-1)*NdotH*NdotH;
return a2 / (PI * t*t);
}
//Different versions
float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
return 1 / (PI * ax*ay * sqr( sqr(HdotX/ax) + sqr(HdotY/ay) + NdotH*NdotH ));
}
```

Set the size of the circle as the judgment value to determine the accuracy of rendering.

2.2、F( θ d) Mirror f observation (Fresnel reflection)

Parameters:

F0 specular reflectance, obtained by LERP (constant value, albedo, metallic). The constant value is directly related to the data color space. The color space is different and the value is different.

cos θ There are two different ways to write D, one is HDL (unity ldoth, Disney ldoth) and the other is HDV (UE Voh).

Gossip: everything has a Fresnel reflex.

```
//Dot (V, H) is used in the formula. By default, unity passes in dot (L, H)
//Because a large number of calculations of BRDF use the dot product of L and h, and H is the half angle vector of L and V, the included angle of LH and VH is the same.
//You don't need one more variable.
// UnityBuiltin UnityStandardBRDF. Cginc file
Inline half pow5 (half x) // performance optimization
{
return x*x * x*x * x;
}
Inline half3 fresnelterm (half3 F0, half COSA) // corresponding to Disney f
{
half t = Pow5 (1 - cosA); // Ala Schlick interpolation
//Dot (V, H) is used in the formula. By default, unity passes in dot (L, H)
//Because a large number of calculations of BRDF use the dot product of L and h, and H is the half angle vector of L and V, the included angle of LH and VH is the same.不需要多来一个变量。
return F0 + (1-F0) * t;
}
// UE4 BRDF. In the ush file
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
float3 F_Schlick( float3 SpecularColor, float VoH )
{
float Fc = Pow5( 1 - VoH ); // 1 sub, 3 mul
//return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
// Anything less than 2% is physically impossible and is instead considered to be shadowing
return saturate( 50.0 * SpecularColor.g ) * Fc + (1 - Fc) * SpecularColor;
}
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) ) );
}
```

2.3、G( θ l, θ v) Mirror g microscopic surface geometric change, microscopic geometric term, shadow of microscopic surface and mask (mask) (unity V term is equivalent) is the most complex term

Three rough distribution models: Kurt’s empirical model (data fitting), Walter’s Smith g derivative, and Schlick’s simpler derivative roughness as a free parameter

```
// UnityBuiltin UnityStandardBRDF. Cginc file
//Low effect version V item, but better performance
//Note: the visibility term is the complete form of Torrance sparrow model, including geometric terms: v = g / (N.L * N.V)
//This makes it easier to swap geometry items and has more optimization space (except perhaps in the case of the cooktorrance geom item)
//General Smith Schlick visibility terminology
inline half SmithVisibilityTerm (half NdotL, half NdotV, half k)
{
half gL = NdotL * (1-k) + k;
half gV = NdotV * (1-k) + k;
return 1.0 / (gL * gV + 1e-5f); // This feature is not suitable for running on mobile,
//Therefore, epsilon is less than a value that can be expressed as half
}
//Smith Schlick is Beckman's work
inline half SmithBeckmannVisibilityTerm (half NdotL, half NdotV, half roughness)
{
half c = 0.797884560802865h; // c = sqrt(2 / Pi)
half k = roughness * c;
return SmithVisibilityTerm (NdotL, NdotV, k) * 0.25f; // * 0.25 is 1 / 4 of the visibility item
}
//High effect version V item
// Ref: http://jcgt.org/published/0003/02/03/paper.pdf 2014 literature
//Calculation of visibility items, including geometric functions and trim coefficients
inline float SmithJointGGXVisibilityTerm (float NdotL, float NdotV, float roughness)
{
#If 0 // it is closed by default. Note: This is frostbite's GGX Smith joint scheme (accurate, but it requires two prescriptions, which is uneconomical)
//Original recipe:
// lambda_v = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
// lambda_l = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;
// G = 1 / (1 + lambda_v + lambda_l);
//Reorder the code to make it more optimized
half a = roughness;
half a2 = a * a;
half lambdaV = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
half lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
//Simplified visibility terms: (2.0f * ndotl * ndotv) / ((4.0f * ndotl * ndotv) * (lambda_v + lambda_l + 1e-5f));
return 0.5f / (lambdaV + lambdaL + 1e-5f); // This feature is not suitable for running on mobile,
//Therefore, epsilon is less than a value that can be expressed as half
#else
//Take this part
//Approximate value (simplified sqrt, mathematically incorrect, but close enough)
//This part is the GGX Smith joint approximation scheme of repawn entertainment
float a = roughness;
float lambdaV = NdotL * (NdotV * (1 - a) + a);
float lambdaL = NdotV * (NdotL * (1 - a) + a);
#if defined(SHADER_API_SWITCH)
return 0.5f / (lambdaV + lambdaL + 1e-4f); // Solution to hlslcc rounding error
#else
return 0.5f / (lambdaV + lambdaL + 1e-5f);
#endif
#endif
}
// UE
//Smith GGX item g, same sex version
float smithG_GGX(float NdotV, float alphaG)
{
float a = alphaG * alphaG;
float b = NdotV * NdotV;
return 1 / (NdotV + sqrt(a + b - a * b));
}
//Smith GGX item g, version of each item
// Derived G function for GGX
float smithG_GGX_aniso(float dotVN, float dotVX, float dotVY, float ax, float ay)
{
return 1.0 / (dotVN + sqrt(pow(dotVX * ax, 2.0) + pow(dotVY * ay, 2.0) + pow(dotVN, 2.0)));
}
//GGX varnish geometry
// G GGX function for clearcoat
float G_GGX(float dotVN, float alphag)
{
float a = alphag * alphag;
float b = dotVN * dotVN;
return 1.0 / (dotVN + sqrt(a + b - a * b));
}
```

2.31、1/4cos θ lcos θ V derivative of micro geometric term, a correction factor used to correct the difference in the number of micro surfaces to macro surfaces (as a whole)

Most physically feasible models that are not specifically described in the form of micro surface can still be described by micro surface model, because they also have distribution function, Fresnel factor and some other factors that can be considered as geometric shadow factor. The only real difference is whether explicit correction factors are included between the micro surface model and other models:

The explicit correction factor is derived from the micro surface model. For models that do not include this factor, use trim: Hidden shadows can be multiplied by 4 cos by dividing the model by D and F θ lcos θ V to determine the factor.

Unity V term (equivalent to G term): BRDF function fitting optimization term

See the description in the fragment directbdrf function in pbr-brdf-disney-unity-3.

2.4. Cloth; 2.5. Rainbow (rainbow can give art a colorful Black: P, skip, have time to further study)

Required References:

Substance PBR instruction manual

https://link.zhihu.com/?target=https%3A//academy.substance3d.com/courses/pbrguide

Eight monkey PBR instruction manual

https://marmoset.co/posts/basic-theory-of-physically-based-rendering/marmoset.co

Siggraph 2012 original article: 2012 physically based shading at Disney

https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdfmedia.disneyanimation.com

My sorted Chinese version:

https://link.zhihu.com/?target=https%3A//github.com/MasterWangdaoyong/Shader-Graph/tree/main/Show/PBR-BRDF-Disney-Unity

Siggraph 2017 original article: 2017 reflection models (BRDF)

https://cgg.mff.cuni.cz/~pepca/lectures/pdf/pg2-05-brdf.en.pdfcgg.mff.cuni.cz

Yan Lingqi (Yan Shen):

https://link.zhihu.com/?target=http%3A//games-cn.org/

I hope there are also friends learning 101102201202 to discuss communication:)

Personal learning notes address:

https://github.com/MasterWangdaoyong/Shader-Graph/tree/main/Unity_SourceCodegithub.com

MasterWangdaoyong/Shader-Graph

https://github.com/MasterWangdaoyong/Shader-Graph/tree/main/Unity_SourceCodegithub.com

Hairy Nebula:https://zhuanlan.zhihu.com/p/60977923

Yuxuan:https://zhuanlan.zhihu.com/p/137039291

Xiong Xinke: source code analysis Chapter 10 Chapter 11

Feng Lele: introduction essentials Chapter 18