Skip to content

Instantly share code, notes, and snippets.

@QuadStorm
Last active August 3, 2018 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save QuadStorm/0ceed8e3a436e0bea4d640ca954702b8 to your computer and use it in GitHub Desktop.
Save QuadStorm/0ceed8e3a436e0bea4d640ca954702b8 to your computer and use it in GitHub Desktop.
An attempt to make PCSS better
#version 120
#extension GL_EXT_texture_array : require
#extension GL_EXT_texture_array : enable
//#extension GL_EXT_gpu_shader4 : require
//#extension GL_EXT_gpu_shader4 : enable
// Port's Poisson Disc (Optimized) Soft Shadow Shader (2015), modified by Stealth Commander/QuadStorm
// Includes an ultra graphics version, a Percentage-Closer Soft Shadows (PCSS) implementation, and other configuration variables
// 7th version
// Configuration: For the adventurous!
// Perfection can be hard to come by. You'll probably have to tweak settings per situation to get things right.
// Shadows
// Ultra Mode; tends to look better with PCSS off, but you can have both on
// Uses 2 shadow sample layers ontop of eachother for an 'ultra' graphics effect
bool ultraMode = false;
// ultraRatio - ratio in size between the normal and ambient samples
float ultraRatio = 5.0f;
// tune the 'ultra' shader effect a bit
// > 0.5f weighs the small sample more, while < 0.5f weighs the large sample more
// values too close to either 0.0f or 1.0f make the effect too subtle and defeat the purpose of ultra mode
float ultraWeightFactor = 0.4f;
// PCSS, aka fighting everything that's wrong with shadow maps
// but could look good if you get the variables balanced right
// fixed sampleDistance far below used when false
// Dynamic soft shadow variance by distance
bool PCSS = true;
// depthLoopNumber - sampling loop amount around each distance point: 1 = 3x3, 2 = 5x5, 3 = 7x7, etc.
int depthLoopNumber = 3;
// how large the light source is -- affects how quickly shadows become soft with distance; change as needed with context
float lightSize = 0.4f; // 0.05 - 0.5 depending on context
// searchDistance - the shadow depth search distance -- higher values don't 'bleed' enough and lower values are less precise with shadow depths; /decrease/ for smaller lightsizes, /increase/ for larger ones
// this shouldn't have to exist...
float searchDistance = 1.0f / 400.0f;
// poisson depth sampling
bool poissonDepth = false;
// lightSize vs searchDistance table (roughly, per scenario)
// 1.0, 1/40; 0.5, 1/80; 0.125, 1/160; etc
// 0.2, 1/100; 0.25, 1/80;
// PCSS radii clamping
// force a minimum and maximum shadow softness
bool pcssClampRadii = false;
float pcssMinRadius = 1.0f / 10000.0f; // 5000 | 0.0002
float pcssMaxRadius = 1.0f / 100.0f; // 250 | 0.004, 50 | 0.02
// Basic Box PCF (instead of default poisson; a la other soft shadow methods)
bool pcfSampler = false;
// amount of loops - 1 = 3x3, 2 = 5x5, 3 = 7x7, ...
int pcfNum = 3;
// use default shadows in particles - h/t Hata's Shader Toggle
bool particleOptimization = false;
// Shadow Opacity Adjustment; blend between minimum shading and full shadows
// Allows for changing how transparent/opaque shadows are -- see https://forum.blockland.us/index.php?topic=289446.0; this toggles the 'fix'
bool shadowOpacity = true;
// occlusionBlend - strength of above effect, where 1.0f is no effect (default opaque), and 0.0f is the same as minimum shaders (no shadows)
float occlusionBlend = 0.925f;
// Shadows fade with distance as well; this can run with PCSS off; turn off for better performance
bool experimentalShadowFalloff = false;
// falloff factor
float experimentalShadowFalloffFactor = 10.0f;
// This is blending. Shadows are rendered to separate layers based on distance.
// This may cause shadows to suddenly change appearance. Use this to change
// how long a distance they will "fade" between the two versions over.
float blendAlpha = 0.85f; // bl default is 0.9f
float blendBeta = 1.0f - blendAlpha;
// These values are very important. If they're too low, you will see weird
// patterns and waves everywhere. If they're too high, shadows will be
// disconnected from their objects. They need to be adjusted carefully.
// These are set specifically for Max quality with max drawing distance.
// You'll need to change them based on your shader quality (and if you changed
// the Poisson disk below.. probably).
const float fudgeFactor1 = 0.2f;
const float fudgeFactor2 = 0.5f;
const float fudgeFactor3 = 1.5f;
const float fudgeFactor4 = 5.0f;
// How soft should the shadows be? (how far out does the edge go)
// Change this or the magic numbers below to improve your "softness" quality
// note that fancy powers of two aren't needed, but they can be good starting points
float sampleDistance = 1.0f / 1000.0f;
// Magic numbers below
/*
int poissonDiskCount = 32;
vec2 poissonDisk[32] = vec2[]
(
vec2(0.6037009, -0.3977135),
vec2(0.1432971, -0.5475889),
vec2(0.4130006, -0.6745455),
vec2(0.9136397, -0.1000729),
vec2(0.5681907, -0.1194669),
vec2(0.7630879, -0.6211567),
vec2(0.1874292, -0.1614596),
vec2(-0.06089688, -0.9141597),
vec2(0.2590805, -0.9208742),
vec2(-0.3907768, -0.594767),
vec2(0.9119951, -0.3819307),
vec2(-0.3664423, -0.9234819),
vec2(-0.09851982, -0.4209589),
vec2(-0.3296949, -0.2300484),
vec2(-0.7646635, -0.5015364),
vec2(-0.8680285, -0.1527984),
vec2(-0.04608675, 0.1312256),
vec2(-0.428542, 0.06557278),
vec2(0.3862999, 0.1360214),
vec2(0.9446273, 0.1907608),
vec2(0.767735, 0.4751784),
vec2(0.00614462, 0.4327521),
vec2(0.4892556, 0.4249187),
vec2(-0.8814729, 0.2260128),
vec2(-0.5271859, 0.3801891),
vec2(-0.6847409, 0.680231),
vec2(-0.4495289, 0.8691995),
vec2(-0.3142174, 0.5816193),
vec2(0.668636, 0.1689468),
vec2(0.03808001, 0.7051221),
vec2(0.3598493, 0.7828714),
vec2(-0.09508449, 0.9845307)
);
*/
// Alternative Poisson Disks
/*
int poissonDiskCount = 81;
vec2 poissonDisk[81] = vec2[]
(
vec2(-0.3699564, -0.8923714),
vec2(-0.2991857, -0.7419077),
vec2(-0.4836373, -0.7128996),
vec2(-0.4001464, -0.5349672),
vec2(-0.1919933, -0.08249668),
vec2(-0.01000632, -0.1949988),
vec2(0.01308492, -0.3854378),
vec2(0.2060275, -0.6136295),
vec2(0.4246204, -0.5385646),
vec2(0.5739859, -0.6241939),
vec2(0.7209898, -0.4848168),
vec2(0.9162411, -0.3304724),
vec2(0.9904354, -0.09592855),
vec2(0.8480595, -0.00145522),
vec2(0.8411906, -0.1628317),
vec2(0.7471918, -0.3052474),
vec2(0.6039378, -0.1701832),
vec2(0.4796014, -0.323362),
vec2(0.2568311, -0.3751998),
vec2(0.183625, -0.2148832),
vec2(0.3433107, -0.1401113),
vec2(0.4316378, 0.03481985),
vec2(0.3968316, 0.1936454),
vec2(0.4381528, 0.3894764),
vec2(0.2114601, 0.4048975),
vec2(0.1994308, 0.2444916),
vec2(0.1721712, 0.01987821),
vec2(0, 0),
vec2(0.00648162, 0.1718858),
vec2(0.0371051, 0.3398669),
vec2(-0.00288106, 0.5080842),
vec2(-0.101272, 0.657119),
vec2(-0.2265163, 0.8383843),
vec2(-0.3772848, 0.9089825),
vec2(-0.5570081, 0.7581005),
vec2(-0.6944108, 0.6688873),
vec2(-0.811931, 0.5597007),
vec2(-0.8990598, 0.397422),
vec2(-0.7313915, 0.3527614),
vec2(-0.5909905, 0.2295826),
vec2(-0.4016944, 0.2946137),
vec2(-0.4303952, 0.1000971),
vec2(-0.2593866, 0.1194347),
vec2(-0.1583612, 0.2668041),
vec2(-0.2674951, 0.5013697),
vec2(-0.4031608, 0.664479),
vec2(-0.5372077, 0.5246259),
vec2(-0.880586, 0.1983642),
vec2(-0.7635881, 0.034782),
vec2(-0.8213844, -0.1374991),
vec2(-0.9844468, -0.07959031),
vec2(-0.9553765, -0.2592497),
vec2(-0.8055727, -0.3689174),
vec2(-0.7207122, -0.5792082),
vec2(-0.5762517, -0.4557166),
vec2(-0.5893056, -0.294492),
vec2(-0.6413326, -0.1379207),
vec2(-0.4876427, -0.06701604),
vec2(-0.3812391, -0.228707),
vec2(-0.2002228, -0.3431383),
vec2(-0.238193, -0.5032565),
vec2(-0.1105472, -0.6067951),
vec2(-0.1185818, -0.829915),
vec2(0.04267518, -0.7710204),
vec2(0.2299606, -0.8834579),
vec2(0.3829597, -0.8357664),
vec2(0.5988549, -0.796147),
vec2(0.6401687, 0.05738575),
vec2(0.6434335, 0.2378507),
vec2(0.7821028, 0.3695812),
vec2(0.9417133, 0.3353129),
vec2(0.843325, 0.1718658),
vec2(0.6487916, 0.5051771),
vec2(0.7990769, 0.5808157),
vec2(0.6465626, 0.7169496),
vec2(0.4615826, 0.6353213),
vec2(0.389738, 0.8312076),
vec2(0.2560864, 0.944613),
vec2(0.0979304, 0.8286165),
vec2(-0.06759234, 0.9140676),
vec2(0.1950012, 0.647736)
);
*/
// /*
int poissonDiskCount = 49;
vec2 poissonDisk[49] =vec2[]
(
vec2(0, 0),
vec2(0.2704636, -0.109632),
vec2(-0.1407196, -0.2135445),
vec2(0.1835398, 0.1544003),
vec2(-0.3016819, 0.02295322),
vec2(-0.1511358, 0.2107215),
vec2(0.5261667, 0.1747418),
vec2(0.106212, -0.4557395),
vec2(0.4724373, -0.4680161),
vec2(0.07686187, -0.1986526),
vec2(0.5025072, -0.1166459),
vec2(0.06726067, 0.5551263),
vec2(0.2961665, 0.4554047),
vec2(0.4371642, -0.6975633),
vec2(0.7450042, -0.6084697),
vec2(0.7879587, -0.3145762),
vec2(0.853178, -0.09371731),
vec2(0.3479224, -0.9342913),
vec2(0.2962557, -0.3351233),
vec2(0.1291568, -0.9127867),
vec2(0.1676721, -0.6902292),
vec2(-0.2335626, -0.5687734),
vec2(-0.1351299, -0.9101442),
vec2(-0.261507, 0.4907885),
vec2(0.2484025, 0.9168846),
vec2(0.4132242, 0.6466962),
vec2(-0.06851456, 0.7667027),
vec2(-0.4992727, -0.2029795),
vec2(-0.7559373, -0.4068739),
vec2(-0.4855339, 0.1969039),
vec2(-0.7640306, -0.1964805),
vec2(-0.5730085, -0.6135933),
vec2(-0.8484348, -0.00299876),
vec2(-0.4140792, 0.8315768),
vec2(-0.485181, 0.5305088),
vec2(0.6689701, 0.5768808),
vec2(0.05106151, 0.3191291),
vec2(0.5435089, 0.3871753),
vec2(0.7201117, 0.07126629),
vec2(-0.627667, -0.00750978),
vec2(-0.7517983, 0.3829239),
vec2(-0.9550468, 0.2630464),
vec2(-0.9520001, -0.2915859),
vec2(-0.3590643, -0.8519062),
vec2(-0.7153674, 0.6039236),
vec2(-0.441388, -0.4258223),
vec2(-0.0022588, 0.9828641),
vec2(0.7638181, 0.3658235),
vec2(0.9487044, 0.1562798)
);
// */
/*
int poissonDiskCount = 49;
vec2 poissonDisk[49] = vec2[]
(
vec2(0.3180534, 0.4481016),
vec2(0.2678761, 0.0108069),
vec2(0.4059432, -0.1698658),
vec2(0.2166998, -0.2913965),
vec2(0.5095147, -0.7720755),
vec2(0.6903954, -0.6289557),
vec2(0.5788592, -0.444398),
vec2(0.3652714, -0.4735996),
vec2(0.06218402, -0.5944019),
vec2(0.2022222, -0.8094499),
vec2(-0.05008334, -0.8284965),
vec2(-0.276035, -0.7895288),
vec2(-0.4997773, -0.8038069),
vec2(-0.654102, -0.6489612),
vec2(-0.8112803, -0.4295334),
vec2(-0.594835, -0.3155343),
vec2(-0.4238591, -0.4459266),
vec2(-0.2346791, -0.5664694),
vec2(-0.0837327, -0.3297902),
vec2(-0.315086, -0.2049854),
vec2(-0.2446316, 0.0475988),
vec2(0, 0),
vec2(-0.05167853, 0.2587596),
vec2(0.1658537, 0.2365123),
vec2(0.08676389, 0.4655274),
vec2(0.00613963, 0.6610284),
vec2(-0.1701808, 0.7868701),
vec2(-0.3171133, 0.9444721),
vec2(-0.531477, 0.7083178),
vec2(-0.7212166, 0.5538531),
vec2(-0.7275055, 0.3375536),
vec2(-0.9388103, 0.2060823),
vec2(-0.9737488, -0.00821011),
vec2(-0.8841391, -0.2061071),
vec2(-0.5946057, 0.0165981),
vec2(-0.4465454, 0.3816047),
vec2(-0.2054298, 0.5647205),
vec2(0.01520541, 0.9229794),
vec2(0.2149482, 0.7891803),
vec2(0.4386395, 0.8156134),
vec2(0.585341, 0.6536921),
vec2(0.599094, 0.4178026),
vec2(0.4628473, 0.2398231),
vec2(0.6354845, 0.08313083),
vec2(0.6402243, -0.1312514),
vec2(0.8978871, -0.3225123),
vec2(0.9632866, -0.1101094),
vec2(0.8624113, 0.1889227),
vec2(0.8072352, 0.5132092)
);
*/
// Fog; enable for somewhat more realistic fog falloff
bool fancyFog = true;
// modify the sin curve power
float fogExponent = 1.0f;
// Superglow - Off-like glow effect
bool superGlow = true;
// Specular Power - control the size of the specular highlight; larger values = smaller specular highlight
float specularPower = 12.0f;
// debug - show only shadows?
bool debug = false;
// End of tweaking variables
// Varying.
varying vec4 vPos;
varying vec3 worldNormal;
varying vec3 worldPos;
// Global directional light uniforms.
uniform vec4 dirLightDir;
uniform vec4 dirLightColor;
uniform vec4 dirLightAmbient;
uniform vec4 dirShadowColor;
// Misc uniforms.
uniform vec3 camPos;
uniform mat4 obj2World;
uniform mat4 world2Cam;
uniform int isParticle;
uniform int doColorMultiply;
uniform int glow;
uniform sampler2DArray stex;
uniform sampler2D tex;
// Surface calculations, including specular power.
varying vec2 texCoord;
vec4 viewDelta;
float specular;
float NdotL;
vec3 reflectVec;
void calculateSurface(vec4 color, inout vec4 albedo)
{
viewDelta.xyz = worldPos - camPos;
viewDelta.w = length(viewDelta.xyz);
viewDelta.xyz = -normalize(viewDelta.xyz);
vec4 texAlbedo = texture2D(tex, texCoord);
albedo.rgb = mix(color.rgb, texAlbedo.rgb, texAlbedo.a);
if(doColorMultiply == 1)
albedo *= gl_Color;
albedo.a = color.a;
NdotL = max(dot(worldNormal, dirLightDir.xyz), 0.0f);
reflectVec = normalize(reflect(-dirLightDir.xyz, worldNormal));
specular = pow(max(dot(reflectVec, viewDelta.xyz), 0.0f), specularPower) * length(texAlbedo.rgb); // change this to change the size of the sun specular reflection
// Uncomment below for a neat rainbow color effect on everything
// albedo.rgb = normalize(viewDelta.xyz);
}
// Fogging.
uniform vec4 fogBaseColor;
uniform vec4 fogConsts;
uniform sampler2D fogTex;
varying vec2 fogCoords;
void applyFog(inout vec4 albedo, in float occlusionFactor)
{
// Calculate fog.
vec4 fogColor = texture2D(fogTex, fogCoords) * fogBaseColor;
// Blend it.
if (fancyFog)
albedo = mix(albedo, fogColor, pow((0.5f + 1.0f / 2.0f * sin(fogColor.a * 3.141592654f - 1.570796327f)), fogExponent));
else
albedo = mix(albedo, fogColor, fogColor.a);
}
// Shadowing
uniform vec4 far_d;
uniform vec2 texSize; // x - size, y - 1/size
uniform vec4 zScale;
uniform int shadowSplitCount;
void calculateShadowCoords(inout vec4 shadow_coordA, inout vec4 shadow_coordB, out float blend)
{
int index = 3;
float fudgeFactorA = 0.0f;
float fudgeFactorB = 0.0f;
fudgeFactorA = fudgeFactor4 / zScale.w;
fudgeFactorB = fudgeFactor4 / zScale.w;
blend = 0.0f;
// find the appropriate depth map to look up in based on the depth of this fragment
if(vPos.y < far_d.x)
{
index = 0;
if(shadowSplitCount > 1)
blend = clamp( (vPos.y - (far_d.x * blendAlpha)) / (far_d.x * blendBeta), 0.0f, 1.0f);
fudgeFactorA = fudgeFactor1 / zScale.x;
fudgeFactorB = fudgeFactor2 / zScale.y;
}
else if(vPos.y < far_d.y)
{
index = 1;
if(shadowSplitCount > 2)
blend = clamp( (vPos.y - (far_d.y * blendAlpha)) / (far_d.x * blendBeta), 0.0f, 1.0f);
fudgeFactorA = fudgeFactor2 / zScale.y;
fudgeFactorB = fudgeFactor3 / zScale.z;
}
else if(vPos.y < far_d.z)
{
index = 2;
if(shadowSplitCount > 3)
blend = clamp( (vPos.y - (far_d.z * blendAlpha)) / (far_d.x * blendBeta), 0.0f, 1.0f);
fudgeFactorA = fudgeFactor3 / zScale.z;
fudgeFactorB = fudgeFactor4 / zScale.w;
}
// transform this fragment's position from view space to scaled light clip space
// such that the xy coordinates are in [0;1]
// note there is no need to divide by w for orthogonal light sources
shadow_coordA = gl_TextureMatrix[index]*vPos;
shadow_coordA.w = shadow_coordA.z - fudgeFactorA; // Figure the input coordinate for PCF sampling if appropriate.
shadow_coordA.z = float(index); // Encode the layer to sample.
//don't have to set second shadow coord if we're not blending
if(blend > 0.0f)
{
shadow_coordB = gl_TextureMatrix[index + 1]*vPos;
shadow_coordB.w = shadow_coordB.z - fudgeFactorB;
shadow_coordB.z = float(index + 1);
}
}
// Point lighting
uniform vec4 pointLightPos0;
uniform vec4 pointLightColor0;
uniform float pointLightRadius0;
uniform vec4 pointLightPos1;
uniform vec4 pointLightColor1;
uniform float pointLightRadius1;
uniform vec4 pointLightPos2;
uniform vec4 pointLightColor2;
uniform float pointLightRadius2;
uniform vec4 pointLightPos3;
uniform vec4 pointLightColor3;
uniform float pointLightRadius3;
uniform vec4 pointLightPos4;
uniform vec4 pointLightColor4;
uniform float pointLightRadius4;
uniform vec4 pointLightPos5;
uniform vec4 pointLightColor5;
uniform float pointLightRadius5;
uniform vec4 pointLightPos6;
uniform vec4 pointLightColor6;
uniform float pointLightRadius6;
uniform vec4 pointLightPos7;
uniform vec4 pointLightColor7;
uniform float pointLightRadius7;
vec4 accumulatePointLights()
{
vec4 pointLightTotal = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec3 lightDelta = vec3(0.0f, 0.0f, 0.0f);
float lightDot = 0.0f;
float ratio = 0.0f;
// Calculate effects of the 8 point lights.
lightDelta = worldPos.xyz - pointLightPos0.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius0);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor0.xyz;
lightDelta = worldPos.xyz - pointLightPos1.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius1);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor1.xyz;
lightDelta = worldPos.xyz - pointLightPos2.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius2);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor2.xyz;
lightDelta = worldPos.xyz - pointLightPos3.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius3);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor3.xyz;
lightDelta = worldPos.xyz - pointLightPos4.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius4);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor4.xyz;
lightDelta = worldPos.xyz - pointLightPos5.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius5);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor5.xyz;
lightDelta = worldPos.xyz - pointLightPos6.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius6);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor6.xyz;
lightDelta = worldPos.xyz - pointLightPos7.xyz;
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f);
ratio = 1.0f - (length(lightDelta) / pointLightRadius7);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * lightDot * pointLightColor7.xyz;
return pointLightTotal;
}
vec4 accumulateParticlePointLights()
{
vec4 pointLightTotal = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec3 lightDelta = vec3(0.0f, 0.0f, 0.0f);
float ratio = 0.0f;
// Calculate effects of the 8 point lights.
lightDelta = worldPos.xyz - pointLightPos0.xyz;
ratio = 1.0f - (length(lightDelta) / pointLightRadius0);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * pointLightColor0.xyz;
lightDelta = worldPos.xyz - pointLightPos1.xyz;
ratio = 1.0f - (length(lightDelta) / pointLightRadius1);
ratio = ratio * ratio * ratio * 0.4f;
ratio = max(ratio, 0.0f);
pointLightTotal.xyz += ratio * pointLightColor1.xyz;
return pointLightTotal;
}
// Combine specular and direct lighting terms.
// note: if we make combinedColor "out" only, it throws a potentially uninitialized value warning, so we've made it inout
void applyLighting(inout vec4 combinedColor, vec4 albedo, float occlusionFactor)
{
// large normal means glowing object
if(glow == 1 || (worldNormal.x + worldNormal.y + worldNormal.z) > 2.0f)
{
combinedColor = superGlow ? vec4(albedo.xyz * 1.5f, albedo.a) : albedo;
return;
}
vec4 dirLightSpecular = occlusionFactor * specular * dirLightColor;
dirLightSpecular *= 0.5f; // arbitrary adjustment
vec4 dirLightDirect = ((NdotL * dirLightColor) * occlusionFactor) + (dirLightAmbient * occlusionFactor) + (dirShadowColor * (1.0f - occlusionFactor));
if(NdotL <= 0.04f)
{
dirLightDirect = dirShadowColor;
dirLightSpecular = vec4(0.0f, 0.0f, 0.0f, 0.0f);
}
else if(NdotL <= 0.1)
{
float val = (NdotL - 0.04f) / (0.1f - 0.04f);
dirLightDirect = (dirLightDirect * val) + (dirShadowColor * (1.0f - val));
dirLightSpecular = dirLightSpecular * val;
}
dirLightDirect += accumulatePointLights();
dirLightSpecular.a = length(dirLightSpecular.rgb);
dirLightDirect.a *= min(occlusionFactor + 0.75f, 1.0f);
combinedColor.rgb = dirLightDirect.rgb * albedo.rgb;
combinedColor.a = albedo.a;
combinedColor += dirLightSpecular;
}
float poissonSample(vec4 shadow_coord, float spread)
{
int hit = 0;
for (int i = 0; i < poissonDiskCount; i++) {
float dist = texture2DArray(stex, vec3(shadow_coord.xy + poissonDisk[i] * spread, shadow_coord.z)).x;
if (dist - shadow_coord.w > 0.0f)
hit++;
}
return float(hit) / poissonDiskCount;
}
float pcfSample(vec4 shadow_coord, float spread)
{
int hit = 0;
for (int x = -pcfNum; x <= pcfNum; x++)
{
for (int y = -pcfNum; y <= pcfNum; y++)
{
float dist = texture2DArray(stex, vec3(shadow_coord.xy + vec2(x, y) / pcfNum * spread, shadow_coord.z)).x;
if (dist - shadow_coord.w > 0.0f)
{
hit++;
}
}
}
return float (hit) / pow(pcfNum * 2 + 1, 2);
}
float shadowSample(vec4 shadow_coord, float spread)
{
if (!pcfSampler)
return poissonSample(shadow_coord, spread);
else
return pcfSample(shadow_coord, spread);
}
float distanceCalcPoisson(vec4 shadow_coord, float searchDistance, float lightSize)
{
float pcfDepth;
for (int i = 0; i < poissonDiskCount; i++)
{
pcfDepth += (texture2DArray(stex, vec3(shadow_coord.xy + poissonDisk[i] * searchDistance, shadow_coord.z)).x - shadow_coord.w) * lightSize / texture2DArray(stex, vec3(shadow_coord.xy + poissonDisk[i] * searchDistance, shadow_coord.z)).x;
}
if (pcssClampRadii)
return clamp(abs(pcfDepth) / poissonDiskCount, pcssMinRadius, pcssMaxRadius);
else
return abs(pcfDepth) / poissonDiskCount;
}
float distanceCalcPCF(vec4 shadow_coord, float searchDistance, float lightSize)
{
float pcfDepth;
float searchDistance2;
for (int x = -depthLoopNumber; x <= depthLoopNumber; x++)
{
for (int y = -depthLoopNumber; y <= depthLoopNumber; y++)
{
searchDistance2 = shadow_coord.w * lightSize * 0.03f;
pcfDepth += texture2DArray(stex, vec3(shadow_coord.xy + vec2(x, y) * searchDistance2 / depthLoopNumber, shadow_coord.z)).x;
}
}
if (pcssClampRadii)
return clamp(abs(pcfDepth) / pow(depthLoopNumber * 2 + 1, 2), pcssMinRadius, pcssMaxRadius);
else
return abs(pcfDepth) / pow(depthLoopNumber * 2 + 1, 2);
}
float penumbraSize(vec4 shadow_coord, float blocker)
{
return (shadow_coord.w - blocker) * lightSize / blocker;
}
float distanceCalc(vec4 shadow_coord, float searchDistance, float lightSize)
{
if (poissonDepth)
return distanceCalcPoisson(shadow_coord, searchDistance, lightSize);
else
return distanceCalcPCF(shadow_coord, searchDistance, lightSize);
}
float advancedShadowCoef()
{
vec4 shadow_coordA = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec4 shadow_coordB = vec4(0.0f, 0.0f, 0.0f, 0.0f);
float blend = 0.0f;
calculateShadowCoords(shadow_coordA, shadow_coordB, blend);
float sampleA;
float sampleADistance;
if (PCSS == true)
{
sampleADistance = penumbraSize(shadow_coordA, distanceCalc(shadow_coordA, searchDistance, lightSize));
if (ultraMode == true)
sampleA = shadowSample(shadow_coordA, sampleADistance) * ultraWeightFactor + shadowSample(shadow_coordA, distanceCalc(shadow_coordA, searchDistance * ultraRatio, lightSize * ultraRatio)) * (1 - ultraWeightFactor);
else
sampleA = shadowSample(shadow_coordA, sampleADistance);
}
if (PCSS == false)
{
if (ultraMode == true)
sampleA = shadowSample(shadow_coordA, sampleDistance) * ultraWeightFactor + shadowSample(shadow_coordA, sampleDistance * ultraRatio) * (1.0f - ultraWeightFactor);
else
sampleA = shadowSample(shadow_coordA, sampleDistance);
}
if (blend > 0.0f)
{
float sampleB;
float sampleBDistance;
if (PCSS == true)
{
sampleBDistance = penumbraSize(shadow_coordB, distanceCalc(shadow_coordB, searchDistance, lightSize));
if (ultraMode)
sampleB = shadowSample(shadow_coordB, sampleBDistance) * ultraWeightFactor + shadowSample(shadow_coordB, distanceCalc(shadow_coordB, searchDistance * ultraRatio, lightSize * ultraRatio)) * (1 - ultraWeightFactor);
else
sampleB = shadowSample(shadow_coordB, sampleBDistance);
}
if (PCSS == false)
{
if (ultraMode == true)
sampleB = shadowSample(shadow_coordB, sampleDistance) * ultraWeightFactor + shadowSample(shadow_coordB, sampleDistance * ultraRatio) * (1.0f - ultraWeightFactor);
else
sampleB = shadowSample(shadow_coordB, sampleDistance);
}
if (!experimentalShadowFalloff)
return clamp((sampleB * blend) + (sampleA * (1.0f - blend)), 0.0f, 1.0f);
else
return clamp(clamp((sampleB * blend) + (sampleA * (1.0f - blend)), 0.0f, 1.0f) + (clamp((distanceCalc(shadow_coordB, searchDistance, lightSize) * experimentalShadowFalloffFactor), 0.0f, 1.0f)), 0.0f, 1.0f);
}
else
{
//return clamp(sampleA + (clamp((vPos.y * 0.1f), 0.0f, 1.0f)), 0.0f, 1.0f);
if (!experimentalShadowFalloff)
return sampleA;
else
return clamp(sampleA + (clamp((distanceCalc(shadow_coordA, searchDistance, lightSize) * experimentalShadowFalloffFactor), 0.0f, 1.0f)), 0.0f, 1.0f);
}
}
// Taken and modified from Hata's Shader Toggle
void basicCalculateShadowCoords(inout vec4 shadow_coordA, float fudgeKeyB)
{
int index = 3;
float fudgeFactorB = fudgeKeyB / zScale.w;
if(vPos.y < far_d.x)
{
index = 0;
fudgeFactorB = fudgeKeyB / zScale.x;
}
else if(vPos.y < far_d.y)
{
index = 1;
fudgeFactorB = fudgeKeyB / zScale.y;
}
else if(vPos.y < far_d.z)
{
index = 2;
fudgeFactorB = fudgeKeyB / zScale.z;
}
shadow_coordA = gl_TextureMatrix[index]*vPos;
shadow_coordA.w = shadow_coordA.z - fudgeFactorB; // Figure the input coordinate for PCF sampling if appropriate.
shadow_coordA.z = float(index); // Encode the layer to sample.
}
float basicShadowCoef(float fudgeKeyB)
{
vec4 shadow_coordA;
basicCalculateShadowCoords(shadow_coordA, fudgeKeyB);
float shadowA = texture2DArray(stex, shadow_coordA.xyz).x; // get the stored depth
float diffA = shadowA - shadow_coordA.w; // get the difference of the stored depth and the distance of this fragment to the light
if(diffA > 0.0f)
diffA = 1.0f;
return diffA;
}
float shadowCoef(bool isLight)
{
float coef = 0.0f;
if (particleOptimization)
{
if(!isLight)
coef = advancedShadowCoef();
else
coef = basicShadowCoef(0.1f);
}
else
coef = advancedShadowCoef();
return coef;
}
// End Hata's Shader Toggle rip
void main()
{
vec4 albedo = vec4(0.0f, 0.0f, 0.0f, 0.0f);
calculateSurface(gl_Color, albedo);
float occlusionFactor = 0.0f;
if(NdotL > -0.01f)
{
if(shadowSplitCount <= 0)
{
occlusionFactor = 1.0f;
}
else if(isParticle == 1)
{
occlusionFactor = shadowCoef(true);
}
else
{
occlusionFactor = shadowCoef(false);
}
}
// Apply lighting and fog.
vec4 fragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);
if(isParticle == 1)
{
vec4 texAlbedo = texture2D(tex, texCoord);
vec4 dirLightDirect = (dirLightColor * occlusionFactor) + (dirLightAmbient * occlusionFactor) + (dirShadowColor * (1.0f - occlusionFactor));
vec4 plt = accumulateParticlePointLights();
vec4 lightTotal = dirLightDirect + plt;
lightTotal.x = clamp(lightTotal.x, 0.0f, 1.2f);
lightTotal.y = clamp(lightTotal.y, 0.0f, 1.2f);
lightTotal.z = clamp(lightTotal.z, 0.0f, 1.2f);
fragColor = texAlbedo * gl_Color * lightTotal;
applyFog(fragColor, occlusionFactor);
fragColor.a = texAlbedo.a * gl_Color.a;
}
else
{
if (shadowOpacity)
applyLighting(fragColor, albedo, 1 - (1 - occlusionFactor) * occlusionBlend);
else
applyLighting(fragColor, albedo, occlusionFactor);
applyFog(fragColor, occlusionFactor);
}
// Uncomment to viz depth in B.
//fragColor.z = vPos.y * 0.01f;
gl_FragColor = fragColor;
// Uncomment to show shadows only
if (debug)
gl_FragColor = vec4(occlusionFactor, occlusionFactor, occlusionFactor, fragColor.a);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment