跳到主要内容
← Lighting Basics

Lighting Basics

Lambert Diffuse Reflection

shader-learning 自学第 18 课:Lambert Diffuse Reflection

实时渲染 · 网格 GLSL

第 18 课:Lambert Diffuse Reflection

实现

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(3.0, 3.0, 3.0)),
  TLight(vec3( 8.0, 5.0, -8.0), vec3(1.5, 3.0, 1.5)),
  TLight(vec3(-8.0, 5.0, -8.0), vec3(1.5, 1.5, 3.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.3;
  float fragRoughness = 0.4;
  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 NoL = dot(fragNormal, lightDir);
    if (NoL > 0.0) {
      float NoV = max(dot(fragNormal, viewDir), 0.0);
      float HoV = max(dot(halfwayDir, viewDir), 0.0);

      float k = pow(fragRoughness + 1.0, 2.0) / 8.0;
      float G = geometrySmith(fragNormal, viewDir, lightDir, k);
      vec3  F = fresnelSchlick(HoV, F0);
      float D = distributionGGX(fragNormal, halfwayDir, fragRoughness);

      vec3 kD = vec3(1.0) - F;
      kD *= 1.0 - fragMetallic;

      vec3 Lo = vec3(0.0);
      Lo += kD * fragColor / PI;
      Lo += F * D * G / (4.0 * NoL * NoV);
      Lo *= lightColor * NoL;

      result += Lo;
    }
  }

  gl_FragColor = vec4(result, 1.0);
}