Blaze/Blaze/Assets/Shaders/PBR.slang

108 lines
3.3 KiB
Plaintext

public static const float PI = 3.14159265f;
float TrowbridgeReitzGGX(float3 normal, float3 halfway, float roughness)
{
float alpha = roughness * roughness;
float alpha2 = alpha * alpha;
float nDotH = max(dot(normal, halfway), 0.0f);
float nDotH2 = nDotH * nDotH;
float numerator = alpha2;
float denominator = nDotH2 * (alpha2 - 1.0f) + 1.0f;
denominator = PI * denominator * denominator;
return numerator / denominator;
}
float GeometrySchlickGGX(float nDotV, float roughness)
{
float r = roughness + 1.0f;
float k = (r * r) / 8.0f;
float numerator = nDotV;
float denominator = nDotV * (1.0f - k) + k;
return numerator / denominator;
}
float GeometrySmith(float nDotV, float nDotL, float roughness)
{
float ggx1 = GeometrySchlickGGX(nDotV, roughness);
float ggx2 = GeometrySchlickGGX(nDotL, roughness);
return ggx1 * ggx2;
}
// https://en.wikipedia.org/wiki/Schlick%27s_approximation
float3 FresnelSchlick(float cosine, float3 f_0)
{
return f_0 + (1.0f - f_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
}
// Sebastian Lagarde
float3 FresnelSchlickRoughness(float cosine, float3 f_0, float roughness)
{
return f_0 + (max((1.0f - roughness).xxx, f_0) - f_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
}
float3 GetPBRContrib(
float3 albedo,
float3 radiance,
float3 viewDir,
float3 normal,
float3 lightDir,
float2 metalRough,
float3 f_0)
{
float3 halfway = normalize(viewDir + lightDir);
float cosineFactor = max(dot(halfway, viewDir), 0.0f);
float nDotV = max(dot(normal, viewDir), 0.0f);
float nDotL = max(dot(normal, lightDir), 0.0f);
float normalDistribution = TrowbridgeReitzGGX(normal, halfway, metalRough.y);
float geometry = GeometrySmith(nDotV, nDotL, metalRough.y);
float3 fresnel = FresnelSchlickRoughness(cosineFactor, f_0, metalRough.y);
float3 numerator = (normalDistribution * geometry) * fresnel;
float denominator = 4.0f * nDotV * nDotL;
float3 specular = numerator / (denominator + 0.00001f);
float3 kSpecular = fresnel;
float3 kDiffuse = 1.0f - kSpecular;
kDiffuse *= 1.0f - metalRough.x;
return nDotL * radiance * (kDiffuse * albedo / PI + specular);
}
public struct PointLight {
public float3 position;
public float range;
public float3 color;
float attenuation;
public float3 getInfluence(float3 albedo, float2 metalRough, float3 viewDir, float3 worldPosition, float3 normal, float3 f_0) {
float3 lightDir = float3(position) - worldPosition;
float lightDistance = length(lightDir);
if (lightDistance > range)
return 0.0f.xxx;
lightDir /= lightDistance; // Normalization
// Color Unpack
//float R = (Light.Color & 0xFF000000) >> 24;
//float G = (Light.Color & 0x00FF0000) >> 16;
//float B = (Light.Color & 0x0000FF00) >> 8;
//float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
let attenuation_ = attenuation / (lightDistance * lightDistance);
let radiance = color * attenuation_;
return GetPBRContrib(albedo, radiance, viewDir, normal, lightDir, metalRough, f_0);
}
};