1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
//? #version 150
const int LT_DIRECTIONAL = 0; // A light like a sun
const int LT_POINT = 1; // A point light, like an explosion
const int LT_TUBE = 2; // A tube light, like a fluorescent light
const int LT_CONE = 3; // A cone light, like a flood light
const float SPEC_FACTOR_NO_SPEC_MAP = 0.1;
const float GLOW_MAP_INTENSITY = 1.5;
const float GLOW_MAP_SRGB_MULTIPLIER = 3.0;
const float PI = 3.14159f;
vec3 FresnelSchlick(vec3 halfVec, vec3 view, vec3 specColor)
{
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(view, halfVec), 0.0, 1.0), 5.0);
}
vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, float specPower, float fresnel, float dotNL)
{
return mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnel) * ((specPower + 2.0) / 8.0 ) * pow(clamp(dot(normal, halfVec), 0.0, 1.0), specPower) * dotNL;
}
float GeometrySchlickGGX(float dotAB, float k)
{
return dotAB / (dotAB * (1.0f - k) + k);
}
vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL)
{
float alpha = roughness * roughness;
float alphaSqr = alpha * alpha;
float dotNH = clamp(dot(normal, halfVec), 0.0f, 1.0f);
float dotNV = clamp(dot(normal, view), 0.0f, 1.0f);
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)
// Distribution Term - Trowbridge-Reitz GGX
float denom = dotNH * dotNH * (alphaSqr - 1.0f) + 1.0001f; // Extra .0001 to prevent div 0
float distribution = alphaSqr / (PI * denom * denom);
// Fresnel Term - Fresnel-Schlick
vec3 fresnel = mix(specColor, FresnelSchlick(halfVec, view, specColor), fresnelFactor);
// Geometry Term - Schlick-GGX approximation
float r = roughness + 1.0;
float k = r * r / 8.0f;
// Smith's method:
// Microsurfaces block light rays coming in from the light
// AND block light rays reflecting to the camera.
// Hence, model both separately and multiply.
float g1vNL = GeometrySchlickGGX(dotNL, k);
float g1vNV = GeometrySchlickGGX(dotNV, k);
float geometry = g1vNL * g1vNV;
vec3 specular = distribution * fresnel * geometry / (4*dotNV*dotNL + 0.0001);
// Diffuse term - Lambertian, kD represents energy lost to specular reflection.
vec3 kD = vec3(1.0)-fresnel;
kD *= (vec3(1.0) - specColor);
vec3 diffuse = kD * diffColor/PI;
return (specular + diffuse) * dotNL;
}
vec3 computeLighting(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL)
{
#ifdef FLAG_LIGHT_MODEL_BLINN_PHONG
return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL);
#else
return ComputeGGX(specColor, diffColor, light, normal, halfVec, view, roughness, fresnelFactor, dotNL);
#endif
}
mat3 localCoordinates(vec3 normal, vec3 tangent_in)
{
// Create basis so we can transform `view` direction into local coord system
// We're not particularly attached to any basis as we have an isotropic roughness, and don't need to align axes with x,y terms.
vec3 tangent = normalize (tangent_in - dot (tangent_in, normal) * normal);
vec3 bitangent = cross(tangent, normal);
mat3 basis = mat3(tangent, bitangent, normal);
return basis;
}
|