跳到主要内容
← Lighting Basics

Lighting Basics

BRDF

Cook-Torrance Bidirectional Reflectance Distribution Function

实时渲染 · 网格 GLSL

第 17 课:BRDF

实现:Cook-Torrance Bidirectional Reflectance Distribution Function

实现

uniform vec2 iResolution;
uniform float iTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform mat4 inverseViewMatrix;

varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUv;

const float PI = 3.14159265359;

struct TLight { vec3 position; vec3 color; };

TLight c_Lights[3] = TLight[3](
  TLight(vec3( 0.0, 5.0, 10.0), vec3(1.0, 1.0, 1.0)),
  TLight(vec3( 8.0, 5.0, -8.0), vec3(0.5, 1.0, 0.5)),
  TLight(vec3(-8.0, 5.0, -8.0), vec3(0.5, 0.5, 1.0))
);

float geometryGGX(float NdotV, float k) {
    float nom   = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return nom / denom;
}

float geometrySmith(vec3 N, vec3 V, vec3 L, float k) {
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx1 = geometryGGX(NdotV, k);
    float ggx2 = geometryGGX(NdotL, k);

    return ggx1 * ggx2;
}

float distributionGGX(vec3 N, vec3 H, float a) {
    float a2     = a*a;
    float NdotH  = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;

    float nom    = a2;
    float denom  = (NdotH2 * (a2 - 1.0) + 1.0);
    denom        = 3.14 * denom * denom;

    return nom / denom;
}

vec3 fresnelSchlick(float cosTheta, vec3 F0) {
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

vec3 getViewPos() {
  return (inverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
}

void main() {
  vec3  fragColor = vec3(1.0, 0.6, 0.6);
  vec3  fragNormal = normalize(vNormal);
  float fragMetallic = 0.8;
  float fragRoughness = 0.3;
  vec3  fragPos = vPos;

  // Base Reflectance
  vec3 F0 = vec3(0.04);
  F0 = mix(F0, fragColor, fragMetallic);

  vec3 viewPos = getViewPos();
  vec3 viewDir = normalize(viewPos - fragPos);

  vec3 result = vec3(0.0);
  for (int i = 0; i < 3; i++) {
    vec3 lightColor = c_Lights[i].color;
    vec3 lightPos = c_Lights[i].position;
    vec3 lightDir = normalize(lightPos - fragPos);
    vec3 halfwayDir = normalize(viewDir + lightDir);

    float dist = distance(lightPos, fragPos);
    float attenuation = 1.0 / (dist * 0.01 + 1.0);
    lightColor *= attenuation;

    float NoV = max(dot(fragNormal, viewDir), 0.0);
    float NoL = dot(fragNormal, lightDir);
    if (NoL > 0.0) {
      // GGX_D: the shape of specular
      float GGX_D = distributionGGX(fragNormal, halfwayDir, fragRoughness);

      // GGX_G:
      float roughnessTransformationFunc = pow(fragRoughness+1.0,2.0)/8.0;
      float GGX_G = geometrySmith(fragNormal, viewDir, lightDir, roughnessTransformationFunc);

      // GGX_F
      vec3 ks = fresnelSchlick(max(dot(halfwayDir, viewDir),0.0),F0);

      //Metallic
      //vec3 kd = vec3(1.0) - ks;
      //kd *= 1.0 - fragMetallic;

      // Application
      vec3 s = (GGX_D * GGX_G * ks) / (4.0 * NoV * NoL);
      //vec3 d = (fragColor * kd)/3.14;

      result += (s) * lightColor * NoL;
    }
  }

  gl_FragColor = vec4(result, 1.0);
}

复盘笔记

  • Cook-Torrance Bidirectional Reflectance Distribution Function
  • 应该是只跟反射有关系的