第 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);
}