From 446c2193ff19bc496c5c132b53f66c6968899960 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 19 Sep 2014 12:18:00 -0700 Subject: [PATCH] Limit what we render for deferred point/spot lights based on the light's radius. --- .../shaders/deferred_light_limited.vert | 60 +++++++++++++++++++ .../src/renderer/DeferredLightingEffect.cpp | 24 +++++--- .../src/renderer/DeferredLightingEffect.h | 2 +- 3 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 interface/resources/shaders/deferred_light_limited.vert diff --git a/interface/resources/shaders/deferred_light_limited.vert b/interface/resources/shaders/deferred_light_limited.vert new file mode 100644 index 0000000000..8a69632f44 --- /dev/null +++ b/interface/resources/shaders/deferred_light_limited.vert @@ -0,0 +1,60 @@ +#version 120 + +// +// deferred_light_limited.vert +// vertex shader +// +// Created by Andrzej Kapolka on 9/19/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// 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); +} diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index 198cb50f13..585fa9b31c 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -27,13 +27,13 @@ void DeferredLightingEffect::init() { _glowIntensityLocation = _simpleProgram.uniformLocation("glowIntensity"); _simpleProgram.release(); - loadLightProgram("shaders/directional_light.frag", _directionalLight, _directionalLightLocations); - loadLightProgram("shaders/directional_light_shadow_map.frag", _directionalLightShadowMap, + loadLightProgram("shaders/directional_light.frag", false, _directionalLight, _directionalLightLocations); + loadLightProgram("shaders/directional_light_shadow_map.frag", false, _directionalLightShadowMap, _directionalLightShadowMapLocations); - loadLightProgram("shaders/directional_light_cascaded_shadow_map.frag", _directionalLightCascadedShadowMap, + loadLightProgram("shaders/directional_light_cascaded_shadow_map.frag", false, _directionalLightCascadedShadowMap, _directionalLightCascadedShadowMapLocations); - loadLightProgram("shaders/point_light.frag", _pointLight, _pointLightLocations); - loadLightProgram("shaders/spot_light.frag", _spotLight, _spotLightLocations); + loadLightProgram("shaders/point_light.frag", true, _pointLight, _pointLightLocations); + loadLightProgram("shaders/spot_light.frag", true, _spotLight, _spotLightLocations); } void DeferredLightingEffect::bindSimpleProgram() { @@ -216,6 +216,11 @@ void DeferredLightingEffect::render() { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); + 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); + if (!_pointLights.isEmpty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); @@ -233,7 +238,7 @@ void DeferredLightingEffect::render() { glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, light.linearAttenuation); glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, light.quadraticAttenuation); - renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); + renderFullscreenQuad(); } _pointLights.clear(); @@ -260,7 +265,7 @@ void DeferredLightingEffect::render() { glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, light.exponent); glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, glm::degrees(light.cutoff)); - renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); + renderFullscreenQuad(); } _spotLights.clear(); @@ -319,8 +324,9 @@ void DeferredLightingEffect::render() { _postLightingRenderables.clear(); } -void DeferredLightingEffect::loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations) { - program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/deferred_light.vert"); +void DeferredLightingEffect::loadLightProgram(const char* name, bool limited, ProgramObject& program, LightLocations& locations) { + program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + (limited ? "shaders/deferred_light_limited.vert" : "shaders/deferred_light.vert")); program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + name); program.link(); diff --git a/interface/src/renderer/DeferredLightingEffect.h b/interface/src/renderer/DeferredLightingEffect.h index 6eb8947689..33fe6b474d 100644 --- a/interface/src/renderer/DeferredLightingEffect.h +++ b/interface/src/renderer/DeferredLightingEffect.h @@ -78,7 +78,7 @@ private: int radius; }; - static void loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations); + static void loadLightProgram(const char* name, bool limited, ProgramObject& program, LightLocations& locations); ProgramObject _simpleProgram; int _glowIntensityLocation;