steps3D - Диффузная модель освещения Burley

Диффузная модель освещения Burley

В 2012 Brent Burley из Walt Disney Animation Studios опубликовал оказавшую заметное влияние работу, описывающую BRDF, которая применяется в Disney. В этой работе была описана диффузная модель, заметно отличающаяся от классической модели Ламберта.

В этой модели использовалась неровность поверхности - оказалось, что когда направление почти касается поверхности, то отражательная способность материала сильно зависит от неровности. И эта зависимость довольно хорошо описывается коэффициентом Френеля.

Для новой модели была введена следующая функция (фактически это приближение Шлика для коэффициента Френеля)

\[F_D(\omega)=1 + (F_{D90}-1)(1-(n,\omega))^5\]

Коэффициент \(F_{D90}\) задается следующей формулой: \[F_{D90}=\frac{1}{2} + 2 \cdot roughness \cdot (h,\omega_{out})^2\]

И, тогда, итоговая BRDF задается следующей формулой:

\[f_{baseDiffuse}=\frac{baseColor}{\pi}F_D(\omega_{in})F_D(\omega_{out})\]

Через \(\omega_i\) и \(\omega_o\) обозначены углы между нормалью \(n\) и векторами на источник света \(l\) и на камеру \(v\).

Ниже приводится изображение, полученное при помощи данной модели

Рис.

Рис. Диффузное освещение Lambert (слева) по сравнению с Burley (справа)

Шейдер для этой модели очень прост, ниже приводится только фрагментный шейдер.

#version 330 core

in  vec3 n;
in  vec3 l;
in  vec3 v;
in  vec3 h;

out vec4 color;

const vec4  clr  = vec4 ( 0.7, 0.3, 0.1, 1.0 ) * 2;
const float ka   = 0.2;
const float kd   = 0.8;

uniform float roughness = 0.9;

float   sqr ( in float x )
{
    return x*x;
}

    // fast computation of pow (x, 5)
float   pow5 ( in float x )
{
    float x2 = x * x;
    
    return x2 * x2 * x;
}

float   fd ( in float fd90, in vec3 n, in vec3 omega )
{
    return 1 + (fd90 - 1) * pow5 ( 1 - abs ( dot ( n, omega ) ) );
}

void main(void)
{
    vec3  n2   = normalize ( n );
    vec3  l2   = normalize ( l );
    vec3  h2   = normalize ( h );
    vec3  v2   = normalize ( v );
    float hv   = dot       ( h2, v2 );
    float FD90 = 0.5 + 2.0 * roughness * sqr ( hv );
    
    color = clr / 3.1415926 * fd ( FD90, n2, l2 ) * fd ( FD90, n2, v2 ) * abs ( dot ( n2, l2 ) );
}

Кроме того, было предложено дополнение, моделирующее подповерхностное рассеивание без дополнительный проходов рендеринга на основе модели Lommel-Seeliger:

\[ f_{subsurface} = \frac{1.25 \cdot baseColor}{\pi} \left( F_{SS}(\omega_{in}) F_{SS}(\omega_{out}) \left (\frac{1}{|(n,\omega_{in})| + |(n,\omega_{out})|} - 0.5 \right) + 0.5 \right) |(n,\omega_{out})| \]

Здесь

\[ F_{SS90} = roughness \cdot (h, \omega_{out})^2 \]

\[F_{SS}(\omega) = (1 + (F_{SS90} - 1)(1 - |(n,\omega)|)^5\]

Итоговая диффузная BRDF задается следующей формулой:

\[f_{dissuse} = (1-subsurface) \cdot f_{baseDiffuse} + subsurface \cdot f_{subsurface}\]

Рис. Освещение с учетом подповерхностного рассеивания

Соответствующий фрагментый шейдер.

#version 330 core

in  vec3 n;
in  vec3 l;
in  vec3 v;
in  vec3 h;

out vec4 color;

const vec4  clr  = vec4 ( 0.7, 0.3, 0.1, 1.0 ) * 2;
const float ka   = 0.2;
const float kd   = 0.8;

uniform float roughness  = 0.9;
uniform float subsurface = 0.3;

float   sqr ( in float x )
{
    return x*x;
}

    // fast computation of pow (x, 5)
float   pow5 ( in float x )
{
    float x2 = x * x;
    
    return x2 * x2 * x;
}

float   fd ( in float fd90, in vec3 n, in vec3 omega )
{
    return 1 + (fd90 - 1) * pow5 ( 1 - abs ( dot ( n, omega ) ) );
}

void main(void)
{
    vec3  n2    = normalize ( n );
    vec3  l2    = normalize ( l );
    vec3  h2    = normalize ( h );
    vec3  v2    = normalize ( v );
    float hv    = dot       ( h2, v2 );
    
    float FD90  = 0.5 + 2.0 * roughness * sqr ( hv );
    float FSS90 = roughness * sqr ( hv );
    
    float   fBaseDiffuse = 1.0 / 3.1415926 * fd ( FD90, n2, l2 ) * fd ( FD90, n2, v2 ) * abs ( dot ( n2, l2 ) );
    float   fSubsurface  = 1.0 / 3.1415926 * ( fd ( FSS90, n2, l2 ) * fd ( FSS90, n2, v2 ) * (1.0 / ( abs ( dot ( n2, l2 ) ) + abs ( dot ( n2, v2 ) ) ) - 0.5 ) + 0.5 );
    float   f            = (1 - subsurface) * fBaseDiffuse + subsurface * fSubsurface;
    
    color = clr * f;
}