stk-code_catmod/data/shaders/pointlight.vert

126 lines
3.9 KiB
GLSL
Raw Normal View History

#ifdef UBO_DISABLED
2014-03-10 18:29:37 -04:00
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 InverseViewMatrix;
uniform mat4 InverseProjectionMatrix;
#else
layout (std140) uniform MatrixesData
{
mat4 ViewMatrix;
mat4 ProjectionMatrix;
mat4 InverseViewMatrix;
mat4 InverseProjectionMatrix;
mat4 ShadowViewProjMatrixes[4];
2014-05-16 20:39:55 -04:00
vec2 screen;
};
#endif
2014-03-10 18:29:37 -04:00
in vec3 Position;
in float Energy;
in vec3 Color;
2014-05-12 13:36:45 -04:00
in float Radius;
2014-03-10 18:29:37 -04:00
flat out vec3 center;
flat out float energy;
flat out vec3 col;
2014-05-12 13:36:45 -04:00
flat out float radius;
2014-03-10 18:29:37 -04:00
const float zNear = 1.;
// Code borrowed from https://software.intel.com/en-us/articles/deferred-rendering-for-current-and-future-rendering-pipelines
// Maths explanations are found here http://www.gamasutra.com/view/feature/131351/the_mechanics_of_robust_stencil_.php?page=6
vec2 UpdateClipRegionRoot(float nc, /* Tangent plane x/y normal coordinate (view space) */
float lc, /* Light x/y coordinate (view space) */
float lz, /* Light z coordinate (view space) */
float lightRadius,
float cameraScale /* Project scale for coordinate (_11 or _22 for x/y respectively) */)
{
float nz = (lightRadius - nc * lc) / lz;
float pz = (lc * lc + lz * lz - lightRadius * lightRadius) /
(lz - (nz / nc) * lc);
2014-05-04 13:46:21 -04:00
if (pz > 0.) {
float c = -nz * cameraScale / nc;
2014-05-04 13:46:21 -04:00
if (nc > 0.) // Left side boundary
return vec2(c, 1.);
else // Right side boundary
return vec2(-1., c);
}
2014-05-04 13:46:21 -04:00
return vec2(-1., 1.);
}
vec2 UpdateClipRegion(float lc, /* Light x/y coordinate (view space) */
float lz, /* Light z coordinate (view space) */
float lightRadius,
float cameraScale /* Project scale for coordinate (_11 or _22 for x/y respectively) */)
{
float rSq = lightRadius * lightRadius;
float lcSqPluslzSq = lc * lc + lz * lz;
float d = rSq * lc * lc - lcSqPluslzSq * (rSq - lz * lz);
2014-05-04 13:46:21 -04:00
// The camera is inside lignt bounding sphere, quad fits whole screen
if (d <= 0.)
return vec2(-1., 1.);
2014-05-04 13:46:21 -04:00
float a = lightRadius * lc;
float b = sqrt(d);
float nx0 = (a + b) / lcSqPluslzSq;
float nx1 = (a - b) / lcSqPluslzSq;
vec2 clip0 = UpdateClipRegionRoot(nx0, lc, lz, lightRadius, cameraScale);
vec2 clip1 = UpdateClipRegionRoot(nx1, lc, lz, lightRadius, cameraScale);
return vec2(max(clip0.x, clip1.x), min(clip0.y, clip1.y));
}
// Returns bounding box [min.x, max.x, min.y, max.y] in clip [-1, 1] space.
vec4 ComputeClipRegion(vec3 lightPosView, float lightRadius)
{
if (lightPosView.z + lightRadius >= zNear) {
vec2 clipX = UpdateClipRegion(lightPosView.x, lightPosView.z, lightRadius, ProjectionMatrix[0][0]);
vec2 clipY = UpdateClipRegion(lightPosView.y, lightPosView.z, lightRadius, ProjectionMatrix[1][1]);
return vec4(clipX, clipY);
}
return vec4(0.);
}
2014-03-10 18:29:37 -04:00
void main(void)
{
vec4 Center = ViewMatrix * vec4(Position, 1.);
Center /= Center.w;
vec2 ProjectedCornerPosition;
2014-05-12 13:36:45 -04:00
vec4 clip = ComputeClipRegion(Center.xyz, Radius);
switch (gl_VertexID)
2014-03-10 18:29:37 -04:00
{
case 0:
ProjectedCornerPosition = clip.xz;
break;
case 1:
ProjectedCornerPosition = clip.xw;
break;
case 2:
ProjectedCornerPosition = clip.yz;
break;
case 3:
ProjectedCornerPosition = clip.yw;
break;
2014-03-10 18:29:37 -04:00
}
// Work out nearest depth for quad Z
// Clamp to near plane in case this light intersects the near plane... don't want our quad to be clipped
2014-05-12 13:36:45 -04:00
float quadDepth = max(zNear, Center.z - Radius);
// Project quad depth into clip space
vec4 quadClip = ProjectionMatrix * vec4(0., 0., quadDepth, 1.0f);
gl_Position = vec4(ProjectedCornerPosition, quadClip.z / quadClip.w, 1.);
2014-03-10 18:29:37 -04:00
col = Color;
center = Position;
energy = Energy;
2014-05-12 13:36:45 -04:00
radius = Radius;
2014-03-10 18:29:37 -04:00
}