Divergent/mods/Screen Space Shaders/gamedata/shaders/r3/pbr_brdf.h

306 lines
10 KiB
C
Raw Normal View History

2024-03-17 20:18:03 -04:00
/**
* @ Description: Enhanced Shaders and Color Grading 1.10
* @ Author: https://www.moddb.com/members/kennshade
* @ Mod: https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders
*/
//=================================================================================================
//Pseudo PBR shading for STALKER Anomaly
//Roughness is controlled with r2_gloss_min
//=================================================================================================
#include "pbr_settings.h" //load settings files
#define PI 3.14159265359
//=================================================================================================
uniform float4 ssfx_lightsetup_1; // Spec intensity
//Metalness
float calc_metalness(float4 alb_gloss, float material_ID)
{
//material ID experiment
float metallerp = max(0.0, (material_ID*4)-0.5)/4; //approx material + weight? //nowhere near
//metallerp = saturate((metallerp - 0.5) * 2); //metal threshold
//metallerp = saturate(((metallerp * 4) - 2) * 0.5); //metal threshold
//binary metalness
float metalness = saturate(material_ID - 0.75 - 0.001) > 0 ? 1 : 0;
//float metal_thres = METALNESS_THRESHOLD;
//float metal_soft = METALNESS_SOFTNESS;
//float metal_thres = METALNESS_THRESHOLD * (1 - metallerp) * 2;
float metal_thres = pow(METALNESS_THRESHOLD, exp2(metallerp));
float metal_soft = metal_thres * 0.9;
//lerp on gloss
//metalness *= saturate(smoothstep(METALNESS_THRESHOLD-METALNESS_SOFTNESS, METALNESS_THRESHOLD+METALNESS_SOFTNESS, alb_gloss.a));
metalness *= saturate((alb_gloss.a - (metal_thres-metal_soft)) / ((metal_thres+metal_soft) - (metal_thres-metal_soft)));
return metalness;
}
float3 Soft_Light (float3 base, float3 blend)
{
return (blend <= 0.5) ? base - (1-2*blend)*base*(1-base) : base + (2*blend-1)*(sqrt(base)-base);
}
//=================================================================================================
//Material
//
float3 calc_albedo_boost(float3 albedo)
{
float3 blend = lerp(0.5, 1-dot(albedo, LUMINANCE_VECTOR), ALBEDO_BOOST); //boost albedo by inv
return Soft_Light(albedo, blend);
}
float3 calc_albedo(float4 alb_gloss, float material_ID)
{
float metalness = calc_metalness(alb_gloss, material_ID);
float3 albedo = alb_gloss.rgb;
//albedo = SRGBToLinear(albedo);
albedo = calc_albedo_boost(albedo);
//albedo = SRGBToLinear(albedo);
float3 screen_contrib = albedo;
screen_contrib = (1-(1-screen_contrib)*(1-screen_contrib))-lerp(dot(screen_contrib, LUMINANCE_VECTOR), screen_contrib, 0.5);
albedo = SRGBToLinear(albedo);
screen_contrib = SRGBToLinear(screen_contrib);
float3 albedo_metal = screen_contrib; //metal albedo is screen blend contrib, it gets rid of all highlights.
return saturate(lerp(albedo, albedo_metal, metalness)*ALBEDO_AMOUNT);
}
float3 calc_specular(float4 alb_gloss, float material_ID)
{
float metalness = calc_metalness(alb_gloss, material_ID);
float3 specular = float3(SPECULAR_BASE, SPECULAR_BASE, SPECULAR_BASE); //base fresnel to tweak
float3 specular_metal = alb_gloss.rgb; //metal uses diffuse for specular
specular_metal = calc_albedo_boost(specular_metal); //boost albedo
specular_metal = SRGBToLinear(specular_metal);
//tweaks for specular boost
//material_ID = sqrt(material_ID/0.75);
material_ID = saturate(material_ID * 1.425);
alb_gloss.a = sqrt(alb_gloss.a);
/*
//old spec boost
float specular_boost = ((0.5+material_ID) * (0.5+alb_gloss.a))-0.25; //0.0 - 2.0 range
specular_boost = specular_boost - 1; //scale in -1 to +1 range
specular_boost = SPECULAR_RANGE * specular_boost;
specular_boost = max(0, specular_boost + 1); //0 - 2
*/
float specular_boost = (material_ID*2-1) + (alb_gloss.a*2-1); //-2.0 - +2.0 range
specular_boost = exp2(SPECULAR_RANGE * specular_boost);
specular_boost = pow(specular_boost, SPECULAR_POW);
specular *= specular_boost;
return saturate(lerp(specular, specular_metal, metalness));
}
float calc_rough(float4 alb_gloss, float material_ID)
{
float metalness = calc_metalness(alb_gloss, material_ID);
alb_gloss.a = pow(alb_gloss.a, ROUGHNESS_POW - (metalness * METAL_BOOST)); //metal boost
float roughpow = 0.5 / max(0.001, 1 - Ldynamic_color.w);
float rough = pow(lerp(ROUGHNESS_HIGH, ROUGHNESS_LOW, alb_gloss.a), roughpow);
//rough = pow(rough, 1 + (metalness * METAL_BOOST)); //metal boost
return saturate(rough*rough);
}
//=================================================================================================
//Rain and Foliage
//
void calc_rain(inout float3 albedo, inout float3 specular, inout float rough, in float4 alb_gloss, in float material_ID, in float rainmask)
{
//rain based on Remember Me's implementation
//float wetness = saturate(rain_params.x*rainmask);
float wetness = saturate(smoothstep(0.1,0.9,rain_params.x*rainmask));
float porosity = 1-saturate(material_ID*1.425); //metal material at 0, concrete at 1
//porosity = saturate((porosity-0.5)/0.4); //Remember Me rain porosity
float factor = lerp(1,0.2, porosity); //albedo darkening factor
albedo *= lerp(1, factor, wetness);
rough = lerp(0.001, rough, lerp(1, factor, wetness));
specular = lerp(specular, 0.02, wetness);
}
void calc_foliage(inout float3 albedo, inout float3 specular, inout float rough, in float4 alb_gloss, in float mat_id)
{
//specular = (abs(mat_id-MAT_FLORA) <= MAT_FLORA_ELIPSON) ? calc_specular(alb_gloss, 0.0) : specular;
// specular = (abs(mat_id-MAT_FLORA) <= MAT_FLORA_ELIPSON) ? alb_gloss.g * 0.02 : specular;
//specular = (abs(mat_id-MAT_FLORA) <= MAT_FLORA_ELIPSON) ? pow(alb_gloss.g * 0.1414, 2) : specular;
if (abs(mat_id-MAT_FLORA) <= MAT_FLORA_ELIPSON)
{
//float light = 1.0f - saturate(dot(L_hemi_color.rgb, float3(1,1,1)));
specular = alb_gloss.g * 0.05f;//max( light * 0.025f, 0.008f);
}
}
//=================================================================================================
//Functions
//
float F_Shlick(float f0, float f90, float vDotH)
{
return lerp(f0, f90, pow(1-vDotH, 5));
}
float3 F_Shlick(float3 f0, float3 f90, float vDotH)
{
return lerp(f0, f90, pow(1-vDotH, 5));
}
// We have a better approximation of the off specular peak
// but due to the other approximations we found this one performs better .
// N is the normal direction
// R is the mirror vector
// This approximation works fine for G smith correlated and uncorrelated
float3 getSpecularDominantDir(float3 N, float3 R, float roughness)
{
float smoothness = saturate(1 - roughness);
float lerpFactor = smoothness * (sqrt(smoothness) + roughness);
// The result is not normalized as we fetch in a cubemap
return lerp(N, R, lerpFactor);
}
//=================================================================================================
//Shading
//
//include BRDFs
#include "pbr_brdf_blinn.h" //brdf
#include "pbr_brdf_ggx.h" //brdf
float Lit_Burley(float nDotL, float nDotV, float vDotH, float rough)
{
float fd90 = 0.5 + 2 * vDotH * vDotH * rough;
float lightScatter = F_Shlick(1, fd90, nDotL);
float viewScatter = F_Shlick(1, fd90, nDotV);
return (lightScatter * viewScatter) / PI;
}
float Lambert_Source(float nDotL,float rough)
{
float exponent = lerp(1.4, 0.6, rough);
return (pow(nDotL, exponent) * ((exponent + 1.0) * 0.5)) / max(1e-5, PI * nDotL);
}
float Lit_Diffuse(float nDotL, float nDotV, float vDotH, float rough)
{
#ifdef USE_BURLEY_DIFFUSE
return Lit_Burley(nDotL, nDotV, vDotH, rough);
#else
return Lambert_Source(nDotL, rough);
#endif
}
float3 Lit_Specular(float nDotL, float nDotH, float nDotV, float vDotH, float3 f0, float rough)
{
#ifdef USE_GGX_SPECULAR
return Lit_GGX(nDotL, nDotH, nDotV, vDotH, f0, rough); //GGX is much more expensive but looks nicer
#else
return Lit_Blinn(nDotL, nDotH, nDotV, vDotH, f0, rough); //much cheaper pbr blinn
#endif
}
float3 Lit_BRDF(float rough, float3 albedo, float3 f0, float3 V, float3 N, float3 L )
{
// SPECULAR ADJUSTMENTS - SSS Update 18
// Color, intensity and some minor adjustments.
// https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders/
float3 H = normalize(V + L);
float DotNV = dot(N, V);
float nDotL = saturate(dot(N, L));
float nDotH = saturate(dot(N, H));
float nDotV = max(1e-5, DotNV);
float vDotH = saturate(dot(V, H));
float3 diffuse_term = Lit_Diffuse(nDotL, nDotV, vDotH, rough).rrr;
diffuse_term *= albedo;
// Specular
float3 specular_term = Lit_Specular(nDotL, nDotH, nDotV, vDotH, f0, rough);
// Horizon falloff
float horizon = saturate(DotNV * 2.0f);
specular_term *= horizon * horizon;
// Specular color
float3 light = saturate(Ldynamic_color.rgb);
specular_term *= 1.0f - ((light.r + light.g + light.b) / 3.0) * (1.0f - ssfx_lightsetup_1.x);
specular_term *= lerp(1.0f, Ldynamic_color.rgb, ssfx_lightsetup_1.y);
// SSS Update 19 - Smooth Shading ( squared nDotL )
return (diffuse_term + specular_term) * nDotL * nDotL * PI;
}
//=================================================================================================
//Ambient
//
float EnvBurley(float roughness, float NV)
{
//Burley (Hill's curve)
float d0 = 0.97619 - 0.488095 * pow(1.0 - NV, 5.0);
float d1 = 1.55754 + (-2.02221 + (2.56283 - 1.06244 * NV) * NV) * NV;
return lerp(d0, d1, roughness);
}
float Amb_Diffuse(float3 f0, float rough, float nDotV)
{
#ifdef USE_BURLEY_DIFFUSE
return EnvBurley(rough, nDotV);
#else
return 1.0;
#endif
}
float3 Amb_Specular(float3 f0, float rough, float nDotV)
{
#ifdef USE_GGX_SPECULAR
return EnvGGX(f0, rough, nDotV);
#else
return EnvBlops2(f0, rough, nDotV);
#endif
}
float3 Amb_BRDF(float rough, float3 albedo, float3 f0, float3 env_d, float3 env_s, float3 V, float3 N)
{
float DotNV = dot(N, V);
//float nDotV = 1e-5 + abs(dot(N, V)); //DICE
float nDotV = max(1e-5, DotNV);
float3 diffuse_term = Amb_Diffuse(f0, rough, nDotV);
diffuse_term *= env_d * albedo;
float3 specular_term = Amb_Specular(f0, rough, nDotV);
specular_term *= env_s;
// horizon occlusion with falloff, should be computed for direct specular too
//float R = reflect(V, N);
//float horizon = saturate(1.0 + dot(R, N)); //needs vertex normals
float horizon = saturate(DotNV * 2.0f); // 0.95
horizon *= horizon;
specular_term *= horizon; //horizon atten
return diffuse_term + specular_term;
}