第 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
- 应该是只跟反射有关系的