2022-11-25 14:58:29 +01:00
|
|
|
#include "light/light.h"
|
|
|
|
#include "scene/scene.h"
|
|
|
|
#include "shader/cooktorranceshader.h"
|
|
|
|
|
2022-11-28 20:55:22 +01:00
|
|
|
CookTorranceShader::CookTorranceShader(Color const &diffCol, Color const &ctCol, float IOR, float roughness,
|
|
|
|
float diffCoeff, float ctCoeff) : diffuseColor(diffCol * diffCoeff),
|
|
|
|
ctColor(ctCol * ctCoeff), F0(IOR),
|
|
|
|
m(roughness) {}
|
2022-11-25 14:58:29 +01:00
|
|
|
|
2022-12-06 13:48:21 +01:00
|
|
|
float CookTorranceShader::D(float NdotH) const {
|
|
|
|
// Beckmann distribution
|
|
|
|
float const r2 = m * m;
|
|
|
|
float const NdotH2 = NdotH * NdotH;
|
|
|
|
return expf((NdotH2 - 1.0f) / (r2 * NdotH2)) / (4.0f * r2 * powf(NdotH, 4.0f));
|
|
|
|
}
|
|
|
|
|
|
|
|
float CookTorranceShader::F(float VdotH) const {
|
|
|
|
// Schlicks approximation
|
|
|
|
return F0 + (1.0f - F0) * powf(1.0f - VdotH, 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
float CookTorranceShader::G(float NdotH, float NdotV, float VdotH, float NdotL) const { return std::min(1.0f, std::min(2.0f * NdotH * NdotV / VdotH, 2.0f * NdotH * NdotL / VdotH)); }
|
|
|
|
|
2022-11-25 14:58:29 +01:00
|
|
|
Color CookTorranceShader::shade(Scene const &scene, Ray const &ray) const {
|
2022-11-28 20:55:22 +01:00
|
|
|
Color fragmentColor;
|
2022-11-25 14:58:29 +01:00
|
|
|
|
2022-12-06 13:48:21 +01:00
|
|
|
if (m >= 0.0f) {
|
|
|
|
// Accumulate the light over all light sources
|
|
|
|
for (const auto &light : scene.lights()) {
|
|
|
|
Light::Illumination illum;
|
|
|
|
illum = light->illuminate(scene, ray);
|
|
|
|
|
|
|
|
float const NdotL = std::max(0.0f, dotProduct(-illum.direction, ray.normal));
|
|
|
|
if (NdotL <= 0.0f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Diffuse term
|
|
|
|
Color const diffuse = this->diffuseColor / float(PI);
|
|
|
|
fragmentColor += diffuse * NdotL * illum.color;
|
|
|
|
|
|
|
|
// Cook-Torrance term
|
|
|
|
// half angle vector
|
|
|
|
Vector3d const H = normalized(-illum.direction - ray.direction);
|
|
|
|
float const NdotH = std::max(0.0f, dotProduct(ray.normal, H));
|
|
|
|
float const NdotV = std::max(0.0f, dotProduct(ray.normal, -ray.direction));
|
|
|
|
float const VdotH = std::max(0.0f, dotProduct(-ray.direction, H));
|
|
|
|
|
|
|
|
if (NdotV * NdotL > EPSILON) {
|
|
|
|
Color const specular = this->ctColor * (F(VdotH) * D(NdotH) * G(NdotH, NdotV, VdotH, NdotL)) / (float(PI) * NdotV * NdotL);
|
|
|
|
|
|
|
|
fragmentColor += specular * NdotL * illum.color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-25 14:58:29 +01:00
|
|
|
|
2022-11-28 20:55:22 +01:00
|
|
|
auto NV = dotProduct(N, V);
|
|
|
|
auto NL = dotProduct(N, L);
|
|
|
|
auto NH = dotProduct(N, H);
|
|
|
|
auto VH = dotProduct(V, H);
|
|
|
|
|
2022-12-02 00:16:18 +01:00
|
|
|
//Cook-Torrance diffuse Term
|
2022-11-28 20:55:22 +01:00
|
|
|
float rhoD = 1.0f / PI;
|
2022-12-02 00:16:18 +01:00
|
|
|
//Cook-Torrance Specular Term
|
|
|
|
//F = Fresnel; D = microfacet Distribution; G = Geometrical factor
|
|
|
|
float rhoS = F(VH) * D(NH) * G(NH, NV, VH, NL) / (4 * NV * NL);
|
|
|
|
//BRDF
|
|
|
|
Color rhoBD = diffuseColor * rhoD + ctColor * rhoS;
|
2022-11-28 20:55:22 +01:00
|
|
|
|
2022-12-02 00:16:18 +01:00
|
|
|
fragmentColor += illum.color * std::abs(NL) * rhoBD;
|
2022-11-28 20:55:22 +01:00
|
|
|
}
|
|
|
|
|
2022-11-28 23:51:33 +01:00
|
|
|
return diffuseColor * fragmentColor;
|
2022-11-28 20:55:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float CookTorranceShader::D(float NdotH) const {
|
2022-12-01 11:43:10 +01:00
|
|
|
float divisor = 4.0f * m * m * std::pow(NdotH, 4.0f);
|
|
|
|
float exponent = (NdotH * NdotH - 1.0f) / (m * m * NdotH * NdotH);
|
|
|
|
return 1 / divisor * std::exp(exponent);
|
2022-11-28 20:55:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float CookTorranceShader::F(float VdotH) const {
|
2022-12-01 11:43:10 +01:00
|
|
|
return F0 + (1.0f - F0) * std::pow(1.0f - VdotH, 5.0f);
|
2022-11-28 20:55:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float CookTorranceShader::G(float NdotH, float NdotV, float VdotH, float NdotL) const {
|
2022-11-28 23:51:33 +01:00
|
|
|
return std::min(1.0f, std::min(2 * NdotH * NdotV / VdotH, 2 * NdotH * NdotL / VdotH));
|
2022-11-28 20:55:22 +01:00
|
|
|
}
|