summaryrefslogtreecommitdiffstats
path: root/brdf.cginc
blob: ea21b495d38e1a591de84e58b1abcabbf9f200b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#ifndef __BRDF_INC
#define __BRDF_INC

#include "pbr.cginc"
#include "lighting.cginc"
#include "lysenko.cginc"
#include "math.cginc"

// Schlick "An Inexpensive BRDF Model for Physically-based Rendering".
// Equation 24.
// f0: Reflectance at normal incidence. Typically around 0.04.
// f90: Reflectance at grazing incidence. Typically around 1.0.
float F_Schlick(float LoH, float f0, float f90) {
  float term = 1.0f - LoH;
  float term2 = term * term;
  float term5 = term2 * term2 * term;
  return f0 + (f90 - f0) * term5;
}

float4 brdf(Pbr pbr, LightData data) {
  float3 specular = 0;
  float3 diffuse = 0;

  // Direct
  if (true) {
    float F = F_Schlick(data.direct.LoH, 0.04f, 1.0f);
    float D = D_GGX(pbr.roughness, data.direct.NoH, data.direct.H);
    float V = V_SmithGGXCorrelated_Fast(pbr.roughness, data.common.NoV, data.direct.NoL);

    float denom = 4.0f * data.common.NoV * data.direct.NoL;
    float FDV = denom > _BRDF_Specular_Min_Denom ? F * D * V / denom : 0.0f;
    specular += FDV * data.direct.color * data.direct.NoL;

    float Fd = Fd_OrenNayar(pbr.roughness, data.common.NoV, data.direct.NoL, data.direct.LoV);
    float3 remainder = (1.0f - F);
    diffuse  += (Fd / PI) * remainder * pbr.albedo.xyz * data.direct.color;
    remainder *= (1.0f - (Fd / PI) * pbr.albedo);
  }

  // Indirect
  if (true) {
    float F = F_Schlick(data.indirect.LoH, 0.04f, 1.0f);

    specular += F * data.indirect.specular;

    float Fd = 1.0f;  // Lambertian divide is baked into SH
    float3 remainder = (1.0f - F);
    diffuse  += Fd * remainder * pbr.albedo.xyz * data.indirect.diffuse;
    remainder *= (1.0f - Fd * pbr.albedo);
  }

  return float4(diffuse + specular, 1);
}

#endif  // __BRDF_INC