mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-16 15:22:27 +02:00
Someone please performance-test this, but I think the fragment shader code simplifications speak for themselves. Radrark found the "line in polar coordinates" equation I needed and a diagram that explained the variables. That equation was essentially the missing piece to the whole thing.
93 lines
3.4 KiB
GLSL
93 lines
3.4 KiB
GLSL
// Polar-coordinate mapper.
|
|
// While inspired by https://www.gamasutra.com/blogs/RobWare/20180226/313491/Fast_2D_shadows_in_Unity_using_1D_shadow_mapping.php ,
|
|
// has one major difference:
|
|
// The assumption here is that the shadow sampling must be reduced.
|
|
// The original cardinal-direction mapper as written by PJB used 4 separate views.
|
|
// As such, it's still an increase in performance to only render 2 views.
|
|
// And as such, a line can be split across the 2 views.
|
|
|
|
// xy: A, zw: B
|
|
attribute vec4 aPos;
|
|
// x: deflection(0=A/1=B) y: height
|
|
attribute vec2 subVertex;
|
|
|
|
// x: actual angle, y: line angle + 90 degrees, z: Distance at y
|
|
varying vec3 fragControl;
|
|
|
|
// Note: This is *not* the standard projectionMatrix!
|
|
uniform vec2 shadowLightCentre;
|
|
|
|
uniform float shadowOverlapSide;
|
|
|
|
// this constant ought to be moved to z-library
|
|
// also deal with the reference to it in shadow_cast_shared
|
|
const highp float PI = 3.1415926535897932384626433;
|
|
|
|
// expands wall edges a little to prevent holes
|
|
const highp float DEPTH_LEFTRIGHT_EXPAND_BIAS = 0.001;
|
|
// added to zbufferDepth BEFORE divide
|
|
// really just keep at 1.0 (keeps it away from the near clipping plane)
|
|
const highp float DEPTH_ZBUFFER_PREDIV_BIAS = 1.0;
|
|
|
|
void main()
|
|
{
|
|
// aPos is clockwise, but we need anticlockwise so swap it here
|
|
vec2 pA = aPos.zw - shadowLightCentre;
|
|
vec2 pB = aPos.xy - shadowLightCentre;
|
|
float xA = atan(pA.y, -pA.x);
|
|
float xB = atan(pB.y, -pB.x);
|
|
|
|
// expand bias
|
|
float lrSignBias = sign(xB - xA) * DEPTH_LEFTRIGHT_EXPAND_BIAS;
|
|
xA -= lrSignBias;
|
|
xB += lrSignBias;
|
|
|
|
// We need to reliably detect a clip, as opposed to, say, a backdrawn face.
|
|
// So a clip is when the angular area is >= 180 degrees (which is not possible with a quad and always occurs when wrapping)
|
|
if (abs(xA - xB) >= PI)
|
|
{
|
|
// Oh no! It clipped...
|
|
|
|
// If such that xA is on the right side and xB is on the left:
|
|
// Pass 1: Adjust left boundary past left edge
|
|
// Pass 2: Adjust right boundary past right edge
|
|
|
|
// If such that xA is on the left side and xB is on the right!
|
|
// Pass 1: Adjust left boundary past right edge
|
|
// Pass 2: Adjust right boundary past left edge
|
|
|
|
if (shadowOverlapSide < 0.5)
|
|
{
|
|
// ...and we're adjusting the left edge...
|
|
xA += sign(xB - xA) * PI * 2.0;
|
|
}
|
|
else
|
|
{
|
|
// ...and we're adjusting the right edge...
|
|
xB += sign(xA - xB) * PI * 2.0;
|
|
}
|
|
}
|
|
|
|
float targetAngle = mix(xA, xB, subVertex.x);
|
|
|
|
// Calculate the necessary control data for the fragment shader.
|
|
vec2 lineNormal = pB - pA; // hypothetical: <- would have negative X, zero Y
|
|
lineNormal /= length(lineNormal);
|
|
fragControl = vec3(
|
|
// Angle
|
|
targetAngle,
|
|
// Angle Out
|
|
atan(lineNormal.x, lineNormal.y),
|
|
// Distance @ Angle Out
|
|
dot(vec2(lineNormal.y, -lineNormal.x), pA)
|
|
);
|
|
|
|
// Depth divide MUST be implemented here no matter what,
|
|
// because GLES SL 1.00 doesn't have gl_FragDepth.
|
|
// Keep in mind: Ultimately, this doesn't matter, because we use the colour buffer for actual casting,
|
|
// and we don't really need to have correction
|
|
float zbufferDepth = 1.0 - (1.0 / (length(mix(pA, pB, subVertex.x)) + DEPTH_ZBUFFER_PREDIV_BIAS));
|
|
|
|
gl_Position = vec4(targetAngle / PI, mix(1.0, -1.0, subVertex.y), zbufferDepth, 1.0);
|
|
}
|