Skip to content

Instantly share code, notes, and snippets.

@QuadStorm
Created February 17, 2019 19:13
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/5a24954357e885ecdaf639850204a2ac to your computer and use it in GitHub Desktop.
Save QuadStorm/5a24954357e885ecdaf639850204a2ac to your computer and use it in GitHub Desktop.
PCSSE pre-configured for (relatively) fast soft shadows; make an accompanying _vert file named PCSSEfastsoft_vert.glsl using a copy of the default rendercsm_vert.glsl
#version 120
#extension GL_EXT_texture_array : require
#extension GL_EXT_texture_array : enable
// Originally Port's Poisson Disc (Optimized) Soft Shadow Shader (2015), modified by Stealth Commander/QuadStorm
// Includes an ultra graphics version, a Percentage-Closer/Perceptually-Correct Soft Shadows (PCSS) implementation, and other configuration variables
// 9th 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
// Ignore any soft shadow settings and use default shader shadowing
bool defaultShadows = 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;
// 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; //0.15f
const float fudgeFactor2 = 0.5f; //0.375f
const float fudgeFactor3 = 1.3f; //1.05f
const float fudgeFactor4 = 5.0f; //4.0f
/*
const float fudgeFactor1 = 0.1f;
const float fudgeFactor2 = 0.25f;
const float fudgeFactor3 = 0.7f;
const float fudgeFactor4 = 2.66f;
*///
// Dynamic Fudge Factor based upon https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping; disable to counter shadow peterpanning instead of acne
bool dynamicFF = true;
// How much more the fudge factor changes with angle
float dynamicFudgeFactor = 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 / 500.0f;
// Cascaded Shadow Map adjustment
// Changes shadow softness to be roughly equal for each shadow cascade
bool csmAdjustmentEnabled = true;
// Ultra Mode; recomended to have PCSS off if you use this but you can have both if you must
// 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;
// Percentage-Closer Soft Shadows
// Variable shadow penumbra by distance (sampleDistance above ignored)
bool PCSS = false;
// How blockers are searched for
// 0 - PCF, 1 - Poisson, 2 - Both
int blockerSearchMode = 0;
// blockerSearchNum - Sampling loop amount around each distance point: 1 = 3x3, 2 = 5x5, 3 = 7x7, etc.
int blockerSearchNum = 3;
// Whether to use the near plane for the PCSS blocker depth search radius
bool searchDistanceNearPlane = false;
// if false, this distance is used
float blockerSearchDistance = 1.0 / 50.0f;
// if true, nearPlane for similar triangles blocker search
float nearPlane = 0.48f;
// whether to adjust the blocker search distances by shadow cascades (similar to csmAdjustmentEnabled)
bool blockerSearchAdjustment = true;
// How large the light source is -- affects how quickly shadows become soft with distance; change as needed with context
float lightSize = 0.125f;
// PCSS radius minimum
bool pcssClampRadius = false;
float pcssClampMinRadius = 1.0f / 5000.0f; // 5000 | 0.0002
// How the shadow is filtered (PCSS or regular fixed soft shadows)
// 0 - PCF, 1 - Poisson, 2 - Both (if you want to for some weird reason have the appearance of both for double the performance impact)
int shadowFilterMode = 1;
// Ratio between PCF and Poisson filtering if Both option is selected; 0.0f = 100% Poisson, 1.0f = 100% PCF
float shadowFilterRatio = 0.4f;
// Basic Box filtering (PCF) loops - 1 = 3x3, 2 = 5x5, 3 = 7x7, ...
int pcfNum = 3;
// Magic numbers below
///*
int poissonDiskCount = 24;
vec2 poissonDisk[24] = vec2[](
vec2(0.01020043f, 0.3103616f),
vec2(-0.4121873f, -0.1701329f),
vec2(0.4333374f, 0.6148015f),
vec2(0.1092096f, -0.2437763f),
vec2(0.6641068f, -0.1210794f),
vec2(-0.1726627f, 0.8724736f),
vec2(-0.8549297f, 0.2836411f),
vec2(0.5146544f, -0.6802685f),
vec2(0.04769185f, -0.879628f),
vec2(-0.9373617f, -0.2187589f),
vec2(-0.69226f, -0.6652822f),
vec2(0.9230682f, 0.3181772f),
// these points might be bad:
vec2(-0.1565961f, 0.8773971f),
vec2(-0.5258075f, 0.3916658f),
vec2(0.515902f, 0.3077986f),
vec2(-0.006838934f, 0.2577735f),
vec2(-0.9315282f, -0.04518054f),
vec2(-0.3417063f, -0.1195169f),
vec2(-0.3221133f, -0.8118886f),
vec2(0.425082f, -0.3786222f),
vec2(0.3917231f, 0.9194779f),
vec2(0.8819267f, -0.1306234f),
vec2(-0.7906089f, -0.5639677f),
vec2(0.2073919f, -0.9611396f)
);
//*/
/*
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)
);
//*/
/*
int poissonDiskCount = 25;
vec2 poissonDisk[25] = vec2[]
(
vec2(0.513658, -0.361747),
vec2(0.7941055, -0.5156633),
vec2(0.4015315, 0.00368995),
vec2(0.2348373, -0.5646414),
vec2(0.08148332, -0.1521704),
vec2(0.9071004, -0.04301345),
vec2(0.5765684, -0.7820904),
vec2(0.02575831, -0.9248317),
vec2(-0.4247141, -0.7601865),
vec2(-0.1650984, -0.5609509),
vec2(-0.00553054, 0.4322597),
vec2(0.374622, 0.536724),
vec2(0.629549, 0.3171313),
vec2(-0.1453903, 0.8028749),
vec2(0.1050673, 0.9782572),
vec2(0.7705216, 0.6211317),
vec2(-0.5209134, -0.2073833),
vec2(-0.2157063, -0.05150497),
vec2(-0.7314271, -0.4448851),
vec2(-0.9658175, -0.08176702),
vec2(-0.6456084, 0.08727718),
vec2(0.4758473, 0.8578165),
vec2(-0.4970213, 0.3748735),
vec2(-0.79823, 0.4584326),
vec2(-0.4652869, 0.7911729)
);
*/
/*
int poissonDiskCount = 121;
vec2 poissonDisk[121] = vec2[]
(
vec2(-0.8145391, 0.2018038),
vec2(-0.7680936, 0.01102507),
vec2(-0.8179, 0.4190474),
vec2(-0.6272386, 0.3042867),
vec2(-0.6388035, 0.09087871),
vec2(-0.973397, 0.09434819),
vec2(-0.9286931, 0.3049383),
vec2(-0.9437586, -0.0878182),
vec2(-0.6478248, 0.5386735),
vec2(-0.6696737, -0.1069194),
vec2(-0.5030807, -0.04799687),
vec2(-0.4554624, 0.1801287),
vec2(-0.4744284, 0.3629912),
vec2(-0.6091245, 0.709008),
vec2(-0.4431208, 0.6060795),
vec2(-0.4783991, 0.872493),
vec2(-0.7650282, 0.6261441),
vec2(-0.648209, -0.2541103),
vec2(-0.4782754, -0.1895011),
vec2(-0.8420978, -0.2915789),
vec2(-0.3320211, 0.4459547),
vec2(-0.2184307, 0.3102135),
vec2(-0.5249589, -0.3567855),
vec2(-0.6339359, -0.4816926),
vec2(-0.7745628, -0.4331442),
vec2(-0.2853205, 0.6266201),
vec2(-0.3126772, 0.2082842),
vec2(-0.2888178, -0.1057123),
vec2(-0.3040508, 0.07155678),
vec2(-0.1689375, 0.00208978),
vec2(-0.1276036, -0.230842),
vec2(-0.2645069, -0.251865),
vec2(-0.05814912, -0.07507057),
vec2(-0.96618, -0.2335756),
vec2(-0.3181189, 0.9354967),
vec2(-0.279675, 0.8050285),
vec2(0.0285327, 0.0285488),
vec2(0.05076085, -0.2321206),
vec2(-0.04266489, 0.1599286),
vec2(-0.1801453, 0.1479051),
vec2(-0.7665108, -0.6125543),
vec2(-0.5986278, -0.633567),
vec2(-0.3869458, -0.5376865),
vec2(-0.1019354, 0.6640193),
vec2(-0.1567075, 0.4577439),
vec2(0.0997559, 0.523626),
vec2(0.08452818, 0.33801),
vec2(-0.0771656, 0.3348197),
vec2(-0.2743955, -0.4123585),
vec2(-0.1417506, -0.3780532),
vec2(0.06017977, -0.3908472),
vec2(0.1209376, 0.1767513),
vec2(0.2930699, 0.1947938),
vec2(0.2726678, 0.4499197),
vec2(0.3479996, 0.3333567),
vec2(-0.3884761, -0.3228932),
vec2(-0.4060122, -0.7620402),
vec2(-0.2692429, -0.6134833),
vec2(-0.2350422, -0.751938),
vec2(0.2291963, -0.5089285),
vec2(-0.1423385, -0.5567046),
vec2(0.2624367, -0.3772998),
vec2(0.1845447, -0.1553576),
vec2(0.03282839, -0.552046),
vec2(-0.03120033, 0.7981148),
vec2(-0.09216484, -0.7041956),
vec2(0.05856795, -0.7267763),
vec2(0.06613369, -0.9221421),
vec2(-0.1888615, -0.9536768),
vec2(-0.07146626, -0.8623131),
vec2(0.1756456, -0.01950932),
vec2(0.193867, -0.8533896),
vec2(0.4005747, -0.10389),
vec2(0.3240081, 0.04697539),
vec2(0.492248, 0.0242701),
vec2(0.5220208, 0.1560711),
vec2(0.411791, -0.8235737),
vec2(0.2914644, -0.9484619),
vec2(0.237363, -0.6849211),
vec2(0.4828349, 0.4181724),
vec2(0.2241743, 0.6966354),
vec2(0.3593884, 0.6664988),
vec2(-0.6096635, -0.7725464),
vec2(-0.3624007, -0.9301076),
vec2(-0.1511986, 0.9812689),
vec2(0.1316039, 0.9200104),
vec2(0.04489716, 0.6663558),
vec2(0.4192846, 0.8968149),
vec2(0.5136389, 0.5955158),
vec2(0.5978712, 0.714323),
vec2(0.2909992, 0.8463242),
vec2(0.667025, 0.2393008),
vec2(0.6945911, 0.5848529),
vec2(0.6720968, 0.4026787),
vec2(0.4061505, -0.3091075),
vec2(-0.00606923, 0.9408461),
vec2(0.6880797, -0.09980167),
vec2(0.6449918, 0.08029267),
vec2(0.5474248, -0.2456431),
vec2(0.5469157, -0.103126),
vec2(0.8124132, 0.2098381),
vec2(0.8384665, 0.5237998),
vec2(0.8843539, 0.3321715),
vec2(0.8657284, 0.06668415),
vec2(0.4219247, -0.5008652),
vec2(0.3702411, -0.6292241),
vec2(0.8320472, -0.09420462),
vec2(0.9697028, 0.1705226),
vec2(0.9808273, -0.08202744),
vec2(0.5489869, -0.4111728),
vec2(0.7044868, -0.3709804),
vec2(-0.04647561, 0.5369669),
vec2(0.7663563, -0.53933),
vec2(0.6115797, -0.5505605),
vec2(0.7589383, -0.24584),
vec2(0.9354028, -0.2223959),
vec2(0.5466368, -0.681439),
vec2(0.1172148, 0.780805),
vec2(0.9163168, -0.3768335),
vec2(0.6836037, -0.6895471),
vec2(0.3884423, 0.5294771)
);
*/
// Use default shadows in particles - h/t Hata's Shader Toggle
bool particleOptimization = true;
// 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;
// Adjust the brightness of the specular effect
float dirLightSpecularMultiplier = 0.5f;
// 0 - Normal, 1 - Shadows, 2 - Position, 3 - Normals, 4 - Albedo, 5 - reflectVec, 6 - viewDelta, 7 - vPos
int displayMode = 0;
// 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;
if (dynamicFF)
{
shadow_coordA.w = shadow_coordA.z - max(dynamicFudgeFactor * fudgeFactorA * (1.0 - dot(worldNormal, dirLightDir.xyz)), fudgeFactorA); // Figure the input coordinate for PCF sampling if appropriate.
}
else
{
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;
if (dynamicFF)
{
shadow_coordB.w = shadow_coordB.z - max(dynamicFudgeFactor * fudgeFactorB * (1.0 - dot(worldNormal, dirLightDir.xyz)), fudgeFactorB);
}
else
{
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 *= dirLightSpecularMultiplier; // 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 csmAdjustment(float index)
{
if (shadowSplitCount == 4)
{
if (index == 1)
return 0.333f;
else if (index == 2)
return 0.1f;
else if (index == 3)
return 0.033f;
}
else if (shadowSplitCount == 3)
{
if (index == 1)
return 0.333f;
else if (index == 2)
return 0.075f;
}
else if (shadowSplitCount == 2)
{
if (index == 1)
return 0.1f;
}
return 1.0f;
}
float getSearchDistance(float dReciever, int index)
{
if (searchDistanceNearPlane)
return lightSize / dReciever * (dReciever - nearPlane);
else
return blockerSearchDistance * (blockerSearchAdjustment ? (bool(index) ? csmAdjustment(index) : 1.0f) : 1.0f);
}
vec2 blockerSearch(vec4 shadow_coord, bool ultra)
{
float searchDistance;
float dBlocker;
float dReciever = shadow_coord.w;
vec2 offset;
float depth;
int hit = 0;
if (blockerSearchMode == 0)
{
searchDistance = getSearchDistance(dReciever, int(shadow_coord.z)) * (ultra ? ultraRatio : 1.0f);
for (int x = -blockerSearchNum; x <= blockerSearchNum; x++)
{
for (int y = -blockerSearchNum; y <= blockerSearchNum; y++)
{
offset = vec2(x, y) / blockerSearchNum * searchDistance;
dBlocker = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dBlocker < dReciever)
{
depth += dBlocker;
hit++;
}
}
}
return vec2(abs(depth) / hit, hit);
}
else if (blockerSearchMode == 1)
{
searchDistance = getSearchDistance(dReciever, int(shadow_coord.z)) * (ultra ? ultraRatio : 1.0f);
for (int i = 0; i < poissonDiskCount; i++)
{
offset = poissonDisk[i] * searchDistance;
dBlocker = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dBlocker < dReciever)
{
depth += dBlocker;
hit++;
}
}
return vec2(abs(depth) / hit, hit);
}
else if (blockerSearchMode == 2)
{
searchDistance = getSearchDistance(dReciever, int(shadow_coord.z)) * (ultra ? ultraRatio : 1.0f);
for (int x = -blockerSearchNum; x <= blockerSearchNum; x++)
{
for (int y = -blockerSearchNum; y <= blockerSearchNum; y++)
{
offset = vec2(x, y) / blockerSearchNum * searchDistance;
dBlocker = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dBlocker < dReciever)
{
depth += dBlocker;
hit++;
}
}
}
float depth2;
int hit2 = 0;
for (int i = 0; i < poissonDiskCount; i++)
{
offset = poissonDisk[i] * searchDistance;
dBlocker = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dBlocker < dReciever)
{
depth2 += dBlocker;
hit2++;
}
}
return vec2((abs(depth) / hit + abs(depth2) / hit2) / 2, hit + hit2);
}
}
float calculatePenumbraSize(int index, float dReciever, float depth, bool ultra)
{
float penumbraSize;
penumbraSize = (dReciever - depth) * lightSize / depth;
penumbraSize *= ultra ? ultraRatio : 1.0f;
if (pcssClampRadius)
{
penumbraSize += pcssClampMinRadius;
}
return penumbraSize;
}
float shadowFilter(vec4 shadow_coord, float penumbraSize)
{
vec2 offset;
float dist;
int index;
if (csmAdjustmentEnabled)
{
index = int(shadow_coord.z);
penumbraSize *= bool(index) ? csmAdjustment(index) : 1.0f;
}
if (shadowFilterMode == 0)
{
int hit = 0;
for (int x = -pcfNum; x <= pcfNum; x++)
{
for (int y = -pcfNum; y <= pcfNum; y++)
{
offset = vec2(x, y) / pcfNum * penumbraSize;
dist = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dist > shadow_coord.w)
{
hit++;
}
}
}
return float (hit) / pow(pcfNum * 2 + 1, 2);
}
else if (shadowFilterMode == 1)
{
int hit = 0;
for (int i = 0; i < poissonDiskCount; i++)
{
offset = poissonDisk[i] * penumbraSize;
dist = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dist > shadow_coord.w)
{
hit++;
}
}
return float(hit) / poissonDiskCount;
}
else if (shadowFilterMode == 2)
{
int hit1 = 0;
int hit2 = 0;
for (int x = -pcfNum; x <= pcfNum; x++)
{
for (int y = -pcfNum; y <= pcfNum; y++)
{
offset = vec2(x, y) / pcfNum * penumbraSize;
dist = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dist > shadow_coord.w)
{
hit1++;
}
}
}
for (int i = 0; i < poissonDiskCount; i++)
{
offset = poissonDisk[i] * penumbraSize;
dist = texture2DArray(stex, vec3(shadow_coord.xy + offset, shadow_coord.z)).x;
if (dist > shadow_coord.w)
{
hit2++;
}
}
return (float(hit1) / pow(pcfNum * 2 + 1, 2)) * shadowFilterRatio + (float(hit2) / poissonDiskCount) * (1.0f - shadowFilterRatio);
}
}
float shadowSamplePCSS(vec4 shadow_coord, bool ultra)
{
float depth;
vec2 blockerSearchResults;
// Step 1: Blocker search
blockerSearchResults = blockerSearch(shadow_coord, ultra) ;
depth = blockerSearchResults.x;
if (blockerSearchResults.y < 1)
return 1.0f;
// Step 2: Penumbra size calculation
float penumbraSize;
penumbraSize = calculatePenumbraSize(int(shadow_coord.z), shadow_coord.w, depth, ultra);
// Step 3: Filtering
return shadowFilter(shadow_coord, penumbraSize);
}
float defaultShading(vec4 shadow_coord)
{
return (texture2DArray(stex, vec3(shadow_coord.xyz)).x > shadow_coord.w) ? 1.0f : 0.0f;
}
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;
if (PCSS == true)
{
if (ultraMode == true)
sampleA = shadowSamplePCSS(shadow_coordA, false) * ultraWeightFactor + shadowSamplePCSS(shadow_coordA, true) * (1.0f - ultraWeightFactor);
else if (!defaultShadows)
sampleA = shadowSamplePCSS(shadow_coordA, false);
else
sampleA = defaultShading(shadow_coordA);
}
if (PCSS == false)
{
if (ultraMode == true)
sampleA = shadowFilter(shadow_coordA, sampleDistance) * ultraWeightFactor + shadowFilter(shadow_coordA, sampleDistance * ultraRatio) * (1.0f - ultraWeightFactor);
else if (!defaultShadows)
sampleA = shadowFilter(shadow_coordA, sampleDistance);
else
sampleA = defaultShading(shadow_coordA);
}
if (blend > 0.0f)
{
float sampleB;
if (PCSS == true)
{
if (ultraMode)
sampleB = shadowSamplePCSS(shadow_coordB, false) * ultraWeightFactor + shadowSamplePCSS(shadow_coordB, true) * (1 - ultraWeightFactor);
else if (!defaultShadows)
sampleB = shadowSamplePCSS(shadow_coordB, false);
else
sampleB = defaultShading(shadow_coordB);
}
if (PCSS == false)
{
if (ultraMode == true)
sampleB = shadowFilter(shadow_coordB, sampleDistance) * ultraWeightFactor + shadowFilter(shadow_coordB, sampleDistance * ultraRatio) * (1.0f - ultraWeightFactor);
else if (!defaultShadows)
sampleB = shadowFilter(shadow_coordB, sampleDistance);
else
sampleB = defaultShading(shadow_coordB);
}
return clamp((sampleB * blend) + (sampleA * (1.0f - blend)), 0.0f, 1.0f);
}
else
{
return sampleA;
}
}
// 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;
if (displayMode == 0)
{
gl_FragColor = fragColor;
}
else if (displayMode == 1)
{
gl_FragColor = vec4(occlusionFactor, occlusionFactor, occlusionFactor, fragColor.a);
}
else if (displayMode == 2)
{
gl_FragColor = vec4(worldPos * 0.02f, fragColor.a);
}
else if (displayMode == 3)
{
gl_FragColor = vec4(worldNormal, fragColor.a);
}
else if (displayMode == 4)
{
gl_FragColor = albedo;
}
else if (displayMode == 5)
{
gl_FragColor = vec4(reflectVec, fragColor.a);;
}
else if (displayMode == 6)
{
gl_FragColor = viewDelta;
}
else if (displayMode == 7)
{
gl_FragColor = vPos;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment