306 lines
10 KiB
C
306 lines
10 KiB
C
/**
|
|
* @ 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;
|
|
} |