Use a more tighly fitting quad for pointlights.
This commit is contained in:
parent
30929ef0a7
commit
94ae8fb21e
@ -18,35 +18,104 @@ in vec3 Position;
|
|||||||
in float Energy;
|
in float Energy;
|
||||||
in vec3 Color;
|
in vec3 Color;
|
||||||
|
|
||||||
in vec2 Corner;
|
|
||||||
|
|
||||||
flat out vec3 center;
|
flat out vec3 center;
|
||||||
flat out float energy;
|
flat out float energy;
|
||||||
flat out vec3 col;
|
flat out vec3 col;
|
||||||
|
|
||||||
const float zNear = 1.;
|
const float zNear = 1.;
|
||||||
|
|
||||||
void main(void)
|
// 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) */)
|
||||||
{
|
{
|
||||||
// Beyond that value, light is too attenuated
|
float nz = (lightRadius - nc * lc) / lz;
|
||||||
float r = 30 * Energy;
|
float pz = (lc * lc + lz * lz - lightRadius * lightRadius) /
|
||||||
center = Position;
|
(lz - (nz / nc) * lc);
|
||||||
energy = Energy;
|
|
||||||
vec4 Center = ViewMatrix * vec4(Position, 1.);
|
if (pz > 0.0f) {
|
||||||
vec4 ProjectedCornerPosition = ProjectionMatrix * (Center + r * vec4(Corner, 0., 0.));
|
float c = -nz * cameraScale / nc;
|
||||||
float adjustedDepth = ProjectedCornerPosition.z;
|
if (nc > 0.0f) // Left side boundary
|
||||||
if (Center.z > zNear) // Light is in front of the cam
|
return vec2(c, 1.);
|
||||||
{
|
else // Right side boundary
|
||||||
adjustedDepth = max(Center.z - r, zNear);
|
return vec2(-1., c);
|
||||||
}
|
}
|
||||||
else if (Center.z + r > zNear) // Light is behind the cam but in range
|
return vec2(1., -1);
|
||||||
{
|
|
||||||
adjustedDepth = zNear;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectedCornerPosition /= ProjectedCornerPosition.w;
|
vec2 UpdateClipRegion(float lc, /* Light x/y coordinate (view space) */
|
||||||
ProjectedCornerPosition.zw = (ProjectionMatrix * vec4(0., 0., adjustedDepth, 1.)).zw;
|
float lz, /* Light z coordinate (view space) */
|
||||||
ProjectedCornerPosition.xy *= ProjectedCornerPosition.w;
|
float lightRadius,
|
||||||
col = Color;
|
float cameraScale /* Project scale for coordinate (_11 or _22 for x/y respectively) */)
|
||||||
gl_Position = ProjectedCornerPosition;
|
{
|
||||||
|
float rSq = lightRadius * lightRadius;
|
||||||
|
float lcSqPluslzSq = lc * lc + lz * lz;
|
||||||
|
float d = rSq * lc * lc - lcSqPluslzSq * (rSq - lz * lz);
|
||||||
|
|
||||||
|
if (d > 0) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
return vec2(1., -1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
float radius = 20. * Energy;
|
||||||
|
vec4 Center = ViewMatrix * vec4(Position, 1.);
|
||||||
|
Center /= Center.w;
|
||||||
|
|
||||||
|
vec2 ProjectedCornerPosition;
|
||||||
|
vec4 clip = ComputeClipRegion(Center.xyz, radius);
|
||||||
|
switch (gl_VertexID)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ProjectedCornerPosition = clip.xz;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ProjectedCornerPosition = clip.xw;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ProjectedCornerPosition = clip.yz;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ProjectedCornerPosition = clip.yw;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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.);
|
||||||
|
|
||||||
|
col = Color;
|
||||||
|
center = Position;
|
||||||
|
energy = Energy;
|
||||||
}
|
}
|
||||||
|
@ -1754,7 +1754,6 @@ namespace LightShader
|
|||||||
GLuint PointLightShader::attrib_Position;
|
GLuint PointLightShader::attrib_Position;
|
||||||
GLuint PointLightShader::attrib_Color;
|
GLuint PointLightShader::attrib_Color;
|
||||||
GLuint PointLightShader::attrib_Energy;
|
GLuint PointLightShader::attrib_Energy;
|
||||||
GLuint PointLightShader::attrib_Corner;
|
|
||||||
GLuint PointLightShader::uniform_ntex;
|
GLuint PointLightShader::uniform_ntex;
|
||||||
GLuint PointLightShader::uniform_dtex;
|
GLuint PointLightShader::uniform_dtex;
|
||||||
GLuint PointLightShader::uniform_spec;
|
GLuint PointLightShader::uniform_spec;
|
||||||
@ -1773,7 +1772,6 @@ namespace LightShader
|
|||||||
attrib_Position = glGetAttribLocation(Program, "Position");
|
attrib_Position = glGetAttribLocation(Program, "Position");
|
||||||
attrib_Color = glGetAttribLocation(Program, "Color");
|
attrib_Color = glGetAttribLocation(Program, "Color");
|
||||||
attrib_Energy = glGetAttribLocation(Program, "Energy");
|
attrib_Energy = glGetAttribLocation(Program, "Energy");
|
||||||
attrib_Corner = glGetAttribLocation(Program, "Corner");
|
|
||||||
uniform_ntex = glGetUniformLocation(Program, "ntex");
|
uniform_ntex = glGetUniformLocation(Program, "ntex");
|
||||||
uniform_dtex = glGetUniformLocation(Program, "dtex");
|
uniform_dtex = glGetUniformLocation(Program, "dtex");
|
||||||
uniform_spec = glGetUniformLocation(Program, "spec");
|
uniform_spec = glGetUniformLocation(Program, "spec");
|
||||||
@ -1782,10 +1780,6 @@ namespace LightShader
|
|||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo);
|
|
||||||
glEnableVertexAttribArray(attrib_Corner);
|
|
||||||
glVertexAttribPointer(attrib_Corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
|
||||||
|
|
||||||
glGenBuffers(1, &vbo);
|
glGenBuffers(1, &vbo);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW);
|
||||||
|
@ -434,7 +434,6 @@ namespace LightShader
|
|||||||
public:
|
public:
|
||||||
static GLuint Program;
|
static GLuint Program;
|
||||||
static GLuint attrib_Position, attrib_Energy, attrib_Color;
|
static GLuint attrib_Position, attrib_Energy, attrib_Color;
|
||||||
static GLuint attrib_Corner;
|
|
||||||
static GLuint uniform_ntex, uniform_dtex, uniform_spec, uniform_screen;
|
static GLuint uniform_ntex, uniform_dtex, uniform_spec, uniform_screen;
|
||||||
static GLuint vbo;
|
static GLuint vbo;
|
||||||
static GLuint vao;
|
static GLuint vao;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user