From 1763d8f7f08f9b16d2723ce7131841c0d5c76426 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Nov 2014 17:29:19 -0800 Subject: [PATCH] Switch to using cones/spheres (as opposed to screen-aligned quads) with depth testing for light geometry. --- .../shaders/deferred_light_limited.vert | 48 ++----------------- interface/resources/shaders/point_light.frag | 7 ++- interface/resources/shaders/spot_light.frag | 7 ++- .../src/renderer/DeferredLightingEffect.cpp | 27 ++++++++++- 4 files changed, 40 insertions(+), 49 deletions(-) diff --git a/interface/resources/shaders/deferred_light_limited.vert b/interface/resources/shaders/deferred_light_limited.vert index 8a69632f44..849d14bda4 100644 --- a/interface/resources/shaders/deferred_light_limited.vert +++ b/interface/resources/shaders/deferred_light_limited.vert @@ -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); } diff --git a/interface/resources/shaders/point_light.frag b/interface/resources/shaders/point_light.frag index 31de0fe7d2..b9ba638885 100644 --- a/interface/resources/shaders/point_light.frag +++ b/interface/resources/shaders/point_light.frag @@ -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 diff --git a/interface/resources/shaders/spot_light.frag b/interface/resources/shaders/spot_light.frag index 33469be0c7..a496abd7b2 100644 --- a/interface/resources/shaders/spot_light.frag +++ b/interface/resources/shaders/spot_light.frag @@ -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 diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index 7a3f648e37..e1af5e5046 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -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);