Switch to using cones/spheres (as opposed to screen-aligned quads) with depth

testing for light geometry.
This commit is contained in:
Andrzej Kapolka 2014-11-04 17:29:19 -08:00
parent 576ac23e71
commit 1763d8f7f0
4 changed files with 40 additions and 49 deletions

View file

@ -11,50 +11,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// the radius (hard cutoff) of the light effect
uniform float radius;
void main(void) {
// find the right "right" direction
vec3 firstRightCandidate = cross(gl_LightSource[1].spotDirection, vec3(0.0, 1.0, 0.0));
vec3 secondRightCandidate = cross(gl_LightSource[1].spotDirection, vec3(1.0, 0.0, 0.0));
vec3 right = mix(firstRightCandidate, secondRightCandidate, step(length(firstRightCandidate), length(secondRightCandidate)));
right = normalize(right);
// and the "up"
vec3 up = cross(right, gl_LightSource[1].spotDirection);
// and the "back," which depends on whether this is a spot light
vec3 back = -gl_LightSource[1].spotDirection * step(gl_LightSource[1].spotCosCutoff, 0.0);
// find the eight corners of the bounds
vec4 c0 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up - right + back), 1.0);
vec4 c1 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up + right + back), 1.0);
vec4 c2 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up - right + back), 1.0);
vec4 c3 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up + right + back), 1.0);
vec4 c4 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up - right + gl_LightSource[1].spotDirection), 1.0);
vec4 c5 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up + right + gl_LightSource[1].spotDirection), 1.0);
vec4 c6 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up - right + gl_LightSource[1].spotDirection), 1.0);
vec4 c7 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up + right + gl_LightSource[1].spotDirection), 1.0);
// find their projected extents
vec2 extents = max(
max(max(gl_Vertex.xy * (c0.xy / max(c0.w, 0.001)), gl_Vertex.xy * (c1.xy / max(c1.w, 0.001))),
max(gl_Vertex.xy * (c2.xy / max(c2.w, 0.001)), gl_Vertex.xy * (c3.xy / max(c3.w, 0.001)))),
max(max(gl_Vertex.xy * (c4.xy / max(c4.w, 0.001)), gl_Vertex.xy * (c5.xy / max(c5.w, 0.001))),
max(gl_Vertex.xy * (c6.xy / max(c6.w, 0.001)), gl_Vertex.xy * (c7.xy / max(c7.w, 0.001)))));
// make sure they don't extend beyond the screen
extents = min(extents, vec2(1.0, 1.0));
gl_Position = vec4(gl_Vertex.xy * extents, 0.0, 1.0);
gl_TexCoord[0] = vec4(dot(gl_Position, gl_ObjectPlaneS[3]), dot(gl_Position, gl_ObjectPlaneT[3]), 0.0, 1.0);
gl_Position = ftransform();
vec4 projected = gl_Position / gl_Position.w;
gl_TexCoord[0] = vec4(dot(projected, gl_ObjectPlaneS[3]), dot(projected, gl_ObjectPlaneT[3]), 0.0, 1.0);
}

View file

@ -39,8 +39,13 @@ uniform vec2 depthTexCoordScale;
uniform float radius;
void main(void) {
// get the depth and exit early if it doesn't pass the test
float depth = texture2D(depthMap, gl_TexCoord[0].st).r;
if (depth < gl_FragCoord.z) {
discard;
}
// compute the view space position using the depth
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
float z = near / (depth * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
// get the normal from the map

View file

@ -39,8 +39,13 @@ uniform vec2 depthTexCoordScale;
uniform float radius;
void main(void) {
// get the depth and exit early if it doesn't pass the test
float depth = texture2D(depthMap, gl_TexCoord[0].st).r;
if (depth < gl_FragCoord.z) {
discard;
}
// compute the view space position using the depth
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
float z = near / (depth * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
// get the normal from the map

View file

@ -222,11 +222,16 @@ void DeferredLightingEffect::render() {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_CULL_FACE);
glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f);
glm::vec4 tCoefficients(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f);
glTexGenfv(GL_S, GL_OBJECT_PLANE, (const GLfloat*)&sCoefficients);
glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients);
// enlarge the scales slightly to account for tesselation
const float SCALE_EXPANSION = 0.1f;
if (!_pointLights.isEmpty()) {
_pointLight.bind();
_pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal);
@ -244,7 +249,12 @@ void DeferredLightingEffect::render() {
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, light.linearAttenuation);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, light.quadraticAttenuation);
renderFullscreenQuad();
glPushMatrix();
glTranslatef(light.position.x, light.position.y, light.position.z);
Application::getInstance()->getGeometryCache()->renderSphere(light.radius * (1.0f + SCALE_EXPANSION), 32, 32);
glPopMatrix();
}
_pointLights.clear();
@ -271,7 +281,18 @@ void DeferredLightingEffect::render() {
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, light.exponent);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, glm::degrees(light.cutoff));
renderFullscreenQuad();
glPushMatrix();
glTranslatef(light.position.x, light.position.y, light.position.z);
glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light.direction);
glm::vec3 axis = glm::axis(spotRotation);
glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z);
glTranslatef(0.0f, 0.0f, -light.radius * (1.0f + SCALE_EXPANSION * 0.5f));
float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION);
Application::getInstance()->getGeometryCache()->renderCone(expandedRadius * glm::tan(light.cutoff),
expandedRadius, 32, 8);
glPopMatrix();
}
_spotLights.clear();
@ -291,6 +312,8 @@ void DeferredLightingEffect::render() {
freeFBO->release();
glDisable(GL_CULL_FACE);
// now transfer the lit region to the primary fbo
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
glColorMask(true, true, true, false);