History

Instanced rendering, first pass

Brad Davis committed 11 years ago

Commit 8a703d01 parent ec8639417 files · +1140 −899Browse files

Showing the changes to libraries/render-utils/src/DeferredLightingEffect.cpp (1 of 17 files). Show all

Unified · Split

libraries/render-utils/src/DeferredLightingEffect.cpp+844−808
@@ -1,809 +1,845 @@
1−//
2−// DeferredLightingEffect.cpp
3−// interface/src/renderer
4−//
5−// Created by Andrzej Kapolka on 9/11/14.
6−// Copyright 2014 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#include "DeferredLightingEffect.h"
13−
14−#include <GLMHelpers.h>
15−#include <PathUtils.h>
16−#include <ViewFrustum.h>
17−
18−#include <gpu/Batch.h>
19−#include <gpu/Context.h>
20−#include <gpu/StandardShaderLib.h>
21−
22−#include "AbstractViewStateInterface.h"
23−#include "GeometryCache.h"
24−#include "TextureCache.h"
25−#include "FramebufferCache.h"
26−
27−
28−#include "simple_vert.h"
29−#include "simple_textured_frag.h"
30−#include "simple_textured_emisive_frag.h"
31−
32−#include "deferred_light_vert.h"
33−#include "deferred_light_limited_vert.h"
34−#include "deferred_light_spot_vert.h"
35−
36−#include "directional_light_frag.h"
37−#include "directional_light_shadow_map_frag.h"
38−#include "directional_light_cascaded_shadow_map_frag.h"
39−
40−#include "directional_ambient_light_frag.h"
41−#include "directional_ambient_light_shadow_map_frag.h"
42−#include "directional_ambient_light_cascaded_shadow_map_frag.h"
43−
44−#include "directional_skybox_light_frag.h"
45−#include "directional_skybox_light_shadow_map_frag.h"
46−#include "directional_skybox_light_cascaded_shadow_map_frag.h"
47−
48−#include "point_light_frag.h"
49−#include "spot_light_frag.h"
50−
51−static const std::string glowIntensityShaderHandle = "glowIntensity";
52−
53−struct LightLocations {
54− int shadowDistances;
55− int shadowScale;
56− int radius;
57− int ambientSphere;
58− int lightBufferUnit;
59− int atmosphereBufferUnit;
60− int texcoordMat;
61− int coneParam;
62− int deferredTransformBuffer;
63−};
64−
65−static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
66−
67−
68−gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) {
69− auto it = _simplePrograms.find(config);
70− if (it != _simplePrograms.end()) {
71− return it.value();
72− }
73−
74− auto state = std::make_shared<gpu::State>();
75− if (config.isCulled()) {
76− state->setCullMode(gpu::State::CULL_BACK);
77− } else {
78− state->setCullMode(gpu::State::CULL_NONE);
79− }
80− state->setDepthTest(true, true, gpu::LESS_EQUAL);
81− if (config.hasDepthBias()) {
82− state->setDepthBias(1.0f);
83− state->setDepthBiasSlopeScale(1.0f);
84− }
85− state->setBlendFunction(false,
86− gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
87− gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
88−
89− gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
90− gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
91− _simplePrograms.insert(config, pipeline);
92− return pipeline;
93−}
94−
95−void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
96− auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
97− auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag)));
98− auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)));
99−
100− _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
101− _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
102−
103− gpu::Shader::BindingSet slotBindings;
104− slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
105− gpu::Shader::makeProgram(*_simpleShader, slotBindings);
106− gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
107−
108− _viewState = viewState;
109− _directionalLightLocations = std::make_shared<LightLocations>();
110− _directionalLightShadowMapLocations = std::make_shared<LightLocations>();
111− _directionalLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
112− _directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
113− _directionalAmbientSphereLightShadowMapLocations = std::make_shared<LightLocations>();
114− _directionalAmbientSphereLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
115− _directionalSkyboxLightLocations = std::make_shared<LightLocations>();
116− _directionalSkyboxLightShadowMapLocations = std::make_shared<LightLocations>();
117− _directionalSkyboxLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
118− _pointLightLocations = std::make_shared<LightLocations>();
119− _spotLightLocations = std::make_shared<LightLocations>();
120−
121− loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
122− loadLightProgram(deferred_light_vert, directional_light_shadow_map_frag, false, _directionalLightShadowMap,
123− _directionalLightShadowMapLocations);
124− loadLightProgram(deferred_light_vert, directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap,
125− _directionalLightCascadedShadowMapLocations);
126−
127− loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
128− loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap,
129− _directionalAmbientSphereLightShadowMapLocations);
130− loadLightProgram(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap,
131− _directionalAmbientSphereLightCascadedShadowMapLocations);
132−
133− loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
134− loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_map_frag, false, _directionalSkyboxLightShadowMap,
135− _directionalSkyboxLightShadowMapLocations);
136− loadLightProgram(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag, false, _directionalSkyboxLightCascadedShadowMap,
137− _directionalSkyboxLightCascadedShadowMapLocations);
138−
139−
140− loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations);
141− loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
142−
143− {
144− //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
145− //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
146− auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
147− gpu::Shader::makeProgram(*blitProgram);
148− auto blitState = std::make_shared<gpu::State>();
149− blitState->setBlendFunction(true,
150− gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
151− gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
152− blitState->setColorWriteMask(true, true, true, false);
153− _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
154− }
155−
156− // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light
157− _globalLights.push_back(0);
158− _allocatedLights.push_back(std::make_shared<model::Light>());
159−
160− model::LightPointer lp = _allocatedLights[0];
161−
162− lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f));
163− lp->setColor(glm::vec3(1.0f));
164− lp->setIntensity(1.0f);
165− lp->setType(model::Light::SUN);
166− lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
167−}
168−
169−
170−
171−void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled,
172− bool emmisive, bool depthBias) {
173− SimpleProgramKey config{textured, culled, emmisive, depthBias};
174− batch.setPipeline(getPipeline(config));
175−
176− gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
177− int glowIntensity = program->getUniforms().findLocation("glowIntensity");
178− batch._glUniform1f(glowIntensity, 1.0f);
179−
180− if (!config.isTextured()) {
181− // If it is not textured, bind white texture and keep using textured pipeline
182− batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
183− }
184−
185− batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
186−}
187−
188−void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
189− bindSimpleProgram(batch);
190− DependencyManager::get<GeometryCache>()->renderSphere(batch, radius, slices, stacks, color);
191−}
192−
193−void DeferredLightingEffect::renderWireSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
194− bindSimpleProgram(batch);
195− DependencyManager::get<GeometryCache>()->renderSphere(batch, radius, slices, stacks, color, false);
196−}
197−
198−void DeferredLightingEffect::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) {
199− bindSimpleProgram(batch);
200− DependencyManager::get<GeometryCache>()->renderSolidCube(batch, size, color);
201−}
202−
203−void DeferredLightingEffect::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) {
204− bindSimpleProgram(batch);
205− DependencyManager::get<GeometryCache>()->renderWireCube(batch, size, color);
206−}
207−
208−void DeferredLightingEffect::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner,
209− const glm::vec4& color) {
210− bindSimpleProgram(batch);
211− DependencyManager::get<GeometryCache>()->renderQuad(batch, minCorner, maxCorner, color);
212−}
213−
214−void DeferredLightingEffect::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2,
215− const glm::vec4& color1, const glm::vec4& color2) {
216− bindSimpleProgram(batch);
217− DependencyManager::get<GeometryCache>()->renderLine(batch, p1, p2, color1, color2);
218−}
219−
220−void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color,
221− float intensity) {
222− addSpotLight(position, radius, color, intensity);
223−}
224−
225−void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,
226− float intensity, const glm::quat& orientation, float exponent, float cutoff) {
227−
228− unsigned int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size();
229− if (lightID >= _allocatedLights.size()) {
230− _allocatedLights.push_back(std::make_shared<model::Light>());
231− }
232− model::LightPointer lp = _allocatedLights[lightID];
233−
234− lp->setPosition(position);
235− lp->setMaximumRadius(radius);
236− lp->setColor(color);
237− lp->setIntensity(intensity);
238− //lp->setShowContour(quadraticAttenuation);
239−
240− if (exponent == 0.0f && cutoff == PI) {
241− lp->setType(model::Light::POINT);
242− _pointLights.push_back(lightID);
243−
244− } else {
245− lp->setOrientation(orientation);
246− lp->setSpotAngle(cutoff);
247− lp->setSpotExponent(exponent);
248− lp->setType(model::Light::SPOT);
249− _spotLights.push_back(lightID);
250− }
251−}
252−
253−void DeferredLightingEffect::prepare(RenderArgs* args) {
254− gpu::Batch batch;
255− batch.enableStereo(false);
256−
257− batch.setStateScissorRect(args->_viewport);
258−
259− auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
260−
261− batch.setFramebuffer(primaryFbo);
262− // clear the normal and specular buffers
263− batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
264− const float MAX_SPECULAR_EXPONENT = 128.0f;
265− batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true);
266−
267− args->_context->render(batch);
268−}
269−
270−gpu::FramebufferPointer _copyFBO;
271−
272−void DeferredLightingEffect::render(RenderArgs* args) {
273− gpu::Batch batch;
274−
275− // Allocate the parameters buffer used by all the deferred shaders
276− if (!_deferredTransformBuffer[0]._buffer) {
277− DeferredTransform parameters;
278− _deferredTransformBuffer[0] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) &parameters));
279− _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) &parameters));
280− }
281−
282− // Framebuffer copy operations cannot function as multipass stereo operations.
283− batch.enableStereo(false);
284−
285− // perform deferred lighting, rendering to free fbo
286− auto framebufferCache = DependencyManager::get<FramebufferCache>();
287−
288− QSize framebufferSize = framebufferCache->getFrameBufferSize();
289−
290− // binding the first framebuffer
291− _copyFBO = framebufferCache->getFramebuffer();
292− batch.setFramebuffer(_copyFBO);
293−
294− // Clearing it
295− batch.setViewportTransform(args->_viewport);
296− batch.setStateScissorRect(args->_viewport);
297− batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
298−
299− // BInd the G-Buffer surfaces
300− batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());
301− batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture());
302− batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture());
303− batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture());
304−
305− // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport)
306− auto monoViewport = args->_viewport;
307− float sMin = args->_viewport.x / (float)framebufferSize.width();
308− float sWidth = args->_viewport.z / (float)framebufferSize.width();
309− float tMin = args->_viewport.y / (float)framebufferSize.height();
310− float tHeight = args->_viewport.w / (float)framebufferSize.height();
311−
312− // The view frustum is the mono frustum base
313− auto viewFrustum = args->_viewFrustum;
314−
315− // Eval the mono projection
316− mat4 monoProjMat;
317− viewFrustum->evalProjectionMatrix(monoProjMat);
318−
319− // The mono view transform
320− Transform monoViewTransform;
321− viewFrustum->evalViewTransform(monoViewTransform);
322−
323− // THe mono view matrix coming from the mono view transform
324− glm::mat4 monoViewMat;
325− monoViewTransform.getMatrix(monoViewMat);
326−
327− // Running in stero ?
328− bool isStereo = args->_context->isStereo();
329− int numPasses = 1;
330−
331− mat4 projMats[2];
332− Transform viewTransforms[2];
333− ivec4 viewports[2];
334− vec4 clipQuad[2];
335− vec2 screenBottomLeftCorners[2];
336− vec2 screenTopRightCorners[2];
337− vec4 fetchTexcoordRects[2];
338−
339− DeferredTransform deferredTransforms[2];
340− auto geometryCache = DependencyManager::get<GeometryCache>();
341−
342− if (isStereo) {
343− numPasses = 2;
344−
345− mat4 eyeViews[2];
346− args->_context->getStereoProjections(projMats);
347− args->_context->getStereoViews(eyeViews);
348−
349− float halfWidth = 0.5 * sWidth;
350−
351− for (int i = 0; i < numPasses; i++) {
352− // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half
353− int sideWidth = monoViewport.z >> 1;
354− viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w);
355−
356− deferredTransforms[i].projection = projMats[i];
357−
1+//
2+// DeferredLightingEffect.cpp
3+// interface/src/renderer
4+//
5+// Created by Andrzej Kapolka on 9/11/14.
6+// Copyright 2014 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+#include "DeferredLightingEffect.h"
13+
14+#include <GLMHelpers.h>
15+#include <PathUtils.h>
16+#include <ViewFrustum.h>
17+
18+#include <gpu/Batch.h>
19+#include <gpu/Context.h>
20+#include <gpu/StandardShaderLib.h>
21+
22+#include "AbstractViewStateInterface.h"
23+#include "GeometryCache.h"
24+#include "TextureCache.h"
25+#include "FramebufferCache.h"
26+
27+
28+#include "simple_vert.h"
29+#include "simple_textured_frag.h"
30+#include "simple_textured_emisive_frag.h"
31+
32+#include "deferred_light_vert.h"
33+#include "deferred_light_limited_vert.h"
34+#include "deferred_light_spot_vert.h"
35+
36+#include "directional_light_frag.h"
37+#include "directional_light_shadow_map_frag.h"
38+#include "directional_light_cascaded_shadow_map_frag.h"
39+
40+#include "directional_ambient_light_frag.h"
41+#include "directional_ambient_light_shadow_map_frag.h"
42+#include "directional_ambient_light_cascaded_shadow_map_frag.h"
43+
44+#include "directional_skybox_light_frag.h"
45+#include "directional_skybox_light_shadow_map_frag.h"
46+#include "directional_skybox_light_cascaded_shadow_map_frag.h"
47+
48+#include "point_light_frag.h"
49+#include "spot_light_frag.h"
50+
51+static const std::string glowIntensityShaderHandle = "glowIntensity";
52+
53+struct LightLocations {
54+ int shadowDistances;
55+ int shadowScale;
56+ int radius;
57+ int ambientSphere;
58+ int lightBufferUnit;
59+ int atmosphereBufferUnit;
60+ int texcoordMat;
61+ int coneParam;
62+ int deferredTransformBuffer;
63+};
64+
65+static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
66+
67+
68+gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) {
69+ auto it = _simplePrograms.find(config);
70+ if (it != _simplePrograms.end()) {
71+ return it.value();
72+ }
73+
74+ auto state = std::make_shared<gpu::State>();
75+ if (config.isCulled()) {
76+ state->setCullMode(gpu::State::CULL_BACK);
77+ } else {
78+ state->setCullMode(gpu::State::CULL_NONE);
79+ }
80+ state->setDepthTest(true, true, gpu::LESS_EQUAL);
81+ if (config.hasDepthBias()) {
82+ state->setDepthBias(1.0f);
83+ state->setDepthBiasSlopeScale(1.0f);
84+ }
85+ state->setBlendFunction(false,
86+ gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
87+ gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
88+
89+ gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
90+ gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
91+ _simplePrograms.insert(config, pipeline);
92+ return pipeline;
93+}
94+
95+void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
96+ auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
97+ auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag)));
98+ auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)));
99+
100+ _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
101+ _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
102+
103+ gpu::Shader::BindingSet slotBindings;
104+ slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
105+ gpu::Shader::makeProgram(*_simpleShader, slotBindings);
106+ gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
107+
108+ _viewState = viewState;
109+ _directionalLightLocations = std::make_shared<LightLocations>();
110+ _directionalLightShadowMapLocations = std::make_shared<LightLocations>();
111+ _directionalLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
112+ _directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
113+ _directionalAmbientSphereLightShadowMapLocations = std::make_shared<LightLocations>();
114+ _directionalAmbientSphereLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
115+ _directionalSkyboxLightLocations = std::make_shared<LightLocations>();
116+ _directionalSkyboxLightShadowMapLocations = std::make_shared<LightLocations>();
117+ _directionalSkyboxLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
118+ _pointLightLocations = std::make_shared<LightLocations>();
119+ _spotLightLocations = std::make_shared<LightLocations>();
120+
121+ loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
122+ loadLightProgram(deferred_light_vert, directional_light_shadow_map_frag, false, _directionalLightShadowMap,
123+ _directionalLightShadowMapLocations);
124+ loadLightProgram(deferred_light_vert, directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap,
125+ _directionalLightCascadedShadowMapLocations);
126+
127+ loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
128+ loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap,
129+ _directionalAmbientSphereLightShadowMapLocations);
130+ loadLightProgram(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap,
131+ _directionalAmbientSphereLightCascadedShadowMapLocations);
132+
133+ loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
134+ loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_map_frag, false, _directionalSkyboxLightShadowMap,
135+ _directionalSkyboxLightShadowMapLocations);
136+ loadLightProgram(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag, false, _directionalSkyboxLightCascadedShadowMap,
137+ _directionalSkyboxLightCascadedShadowMapLocations);
138+
139+
140+ loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations);
141+ loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
142+
143+ {
144+ //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
145+ //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
146+ auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
147+ gpu::Shader::makeProgram(*blitProgram);
148+ auto blitState = std::make_shared<gpu::State>();
149+ blitState->setBlendFunction(true,
150+ gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
151+ gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
152+ blitState->setColorWriteMask(true, true, true, false);
153+ _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
154+ }
155+
156+ // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light
157+ _globalLights.push_back(0);
158+ _allocatedLights.push_back(std::make_shared<model::Light>());
159+
160+ model::LightPointer lp = _allocatedLights[0];
161+
162+ lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f));
163+ lp->setColor(glm::vec3(1.0f));
164+ lp->setIntensity(1.0f);
165+ lp->setType(model::Light::SUN);
166+ lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
167+}
168+
169+
170+
171+gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled,
172+ bool emmisive, bool depthBias) {
173+ SimpleProgramKey config{textured, culled, emmisive, depthBias};
174+ gpu::PipelinePointer pipeline = getPipeline(config);
175+ batch.setPipeline(pipeline);
176+
177+ gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
178+ int glowIntensity = program->getUniforms().findLocation("glowIntensity");
179+ batch._glUniform1f(glowIntensity, 1.0f);
180+
181+ if (!config.isTextured()) {
182+ // If it is not textured, bind white texture and keep using textured pipeline
183+ batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
184+ }
185+
186+ batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
187+ return pipeline;
188+}
189+
190+
191+void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
192+ bindSimpleProgram(batch);
193+ DependencyManager::get<GeometryCache>()->renderSphere(batch, radius, slices, stacks, color);
194+}
195+
196+void DeferredLightingEffect::renderWireSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
197+ bindSimpleProgram(batch);
198+ DependencyManager::get<GeometryCache>()->renderSphere(batch, radius, slices, stacks, color, false);
199+}
200+
201+uint32_t toCompactColor(const glm::vec4& color) {
202+ uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) |
203+ ((int(color.y * 255.0f) & 0xFF) << 8) |
204+ ((int(color.z * 255.0f) & 0xFF) << 16) |
205+ ((int(color.w * 255.0f) & 0xFF) << 24);
206+ return compactColor;
207+}
208+
209+void DeferredLightingEffect::renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color) {
210+ static const std::string INSTANCE_NAME = __FUNCTION__;
211+ static const size_t TRANSFORM_BUFFER = 0;
212+ static const size_t COLOR_BUFFER = 1;
213+ {
214+ gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(INSTANCE_NAME, TRANSFORM_BUFFER);
215+ glm::mat4 xfmMat4;
216+ instanceTransformBuffer->append(xfm.getMatrix(xfmMat4));
217+
218+ gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(INSTANCE_NAME, COLOR_BUFFER);
219+ auto compactColor = toCompactColor(color);
220+ instanceColorBuffer->append(compactColor);
221+ }
222+
223+ batch.setupNamedCalls(INSTANCE_NAME, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
224+ auto pipeline = bindSimpleProgram(batch);
225+ auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced");
226+
227+ batch._glUniform1i(location, 1);
228+ DependencyManager::get<GeometryCache>()->renderSolidCubeInstances(batch, data._count,
229+ data._buffers[TRANSFORM_BUFFER], data._buffers[COLOR_BUFFER]);
230+ batch._glUniform1i(location, 0);
231+ });
232+}
233+
234+void DeferredLightingEffect::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) {
235+ bindSimpleProgram(batch);
236+ DependencyManager::get<GeometryCache>()->renderSolidCube(batch, size, color);
237+}
238+
239+void DeferredLightingEffect::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) {
240+ bindSimpleProgram(batch);
241+ DependencyManager::get<GeometryCache>()->renderWireCube(batch, size, color);
242+}
243+
244+void DeferredLightingEffect::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner,
245+ const glm::vec4& color) {
246+ bindSimpleProgram(batch);
247+ DependencyManager::get<GeometryCache>()->renderQuad(batch, minCorner, maxCorner, color);
248+}
249+
250+void DeferredLightingEffect::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2,
251+ const glm::vec4& color1, const glm::vec4& color2) {
252+ bindSimpleProgram(batch);
253+ DependencyManager::get<GeometryCache>()->renderLine(batch, p1, p2, color1, color2);
254+}
255+
256+void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color,
257+ float intensity) {
258+ addSpotLight(position, radius, color, intensity);
259+}
260+
261+void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,
262+ float intensity, const glm::quat& orientation, float exponent, float cutoff) {
263+
264+ unsigned int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size();
265+ if (lightID >= _allocatedLights.size()) {
266+ _allocatedLights.push_back(std::make_shared<model::Light>());
267+ }
268+ model::LightPointer lp = _allocatedLights[lightID];
269+
270+ lp->setPosition(position);
271+ lp->setMaximumRadius(radius);
272+ lp->setColor(color);
273+ lp->setIntensity(intensity);
274+ //lp->setShowContour(quadraticAttenuation);
275+
276+ if (exponent == 0.0f && cutoff == PI) {
277+ lp->setType(model::Light::POINT);
278+ _pointLights.push_back(lightID);
279+
280+ } else {
281+ lp->setOrientation(orientation);
282+ lp->setSpotAngle(cutoff);
283+ lp->setSpotExponent(exponent);
284+ lp->setType(model::Light::SPOT);
285+ _spotLights.push_back(lightID);
286+ }
287+}
288+
289+void DeferredLightingEffect::prepare(RenderArgs* args) {
290+ gpu::Batch batch;
291+ batch.enableStereo(false);
292+
293+ batch.setStateScissorRect(args->_viewport);
294+
295+ auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
296+
297+ batch.setFramebuffer(primaryFbo);
298+ // clear the normal and specular buffers
299+ batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
300+ const float MAX_SPECULAR_EXPONENT = 128.0f;
301+ batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true);
302+
303+ args->_context->render(batch);
304+}
305+
306+gpu::FramebufferPointer _copyFBO;
307+
308+void DeferredLightingEffect::render(RenderArgs* args) {
309+ gpu::Batch batch;
310+
311+ // Allocate the parameters buffer used by all the deferred shaders
312+ if (!_deferredTransformBuffer[0]._buffer) {
313+ DeferredTransform parameters;
314+ _deferredTransformBuffer[0] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) &parameters));
315+ _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) &parameters));
316+ }
317+
318+ // Framebuffer copy operations cannot function as multipass stereo operations.
319+ batch.enableStereo(false);
320+
321+ // perform deferred lighting, rendering to free fbo
322+ auto framebufferCache = DependencyManager::get<FramebufferCache>();
323+
324+ QSize framebufferSize = framebufferCache->getFrameBufferSize();
325+
326+ // binding the first framebuffer
327+ _copyFBO = framebufferCache->getFramebuffer();
328+ batch.setFramebuffer(_copyFBO);
329+
330+ // Clearing it
331+ batch.setViewportTransform(args->_viewport);
332+ batch.setStateScissorRect(args->_viewport);
333+ batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
334+
335+ // BInd the G-Buffer surfaces
336+ batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());
337+ batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture());
338+ batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture());
339+ batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture());
340+
341+ // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport)
342+ auto monoViewport = args->_viewport;
343+ float sMin = args->_viewport.x / (float)framebufferSize.width();
344+ float sWidth = args->_viewport.z / (float)framebufferSize.width();
345+ float tMin = args->_viewport.y / (float)framebufferSize.height();
346+ float tHeight = args->_viewport.w / (float)framebufferSize.height();
347+
348+ // The view frustum is the mono frustum base
349+ auto viewFrustum = args->_viewFrustum;
350+
351+ // Eval the mono projection
352+ mat4 monoProjMat;
353+ viewFrustum->evalProjectionMatrix(monoProjMat);
354+
355+ // The mono view transform
356+ Transform monoViewTransform;
357+ viewFrustum->evalViewTransform(monoViewTransform);
358+
359+ // THe mono view matrix coming from the mono view transform
360+ glm::mat4 monoViewMat;
361+ monoViewTransform.getMatrix(monoViewMat);
362+
363+ // Running in stero ?
364+ bool isStereo = args->_context->isStereo();
365+ int numPasses = 1;
366+
367+ mat4 projMats[2];
368+ Transform viewTransforms[2];
369+ ivec4 viewports[2];
370+ vec4 clipQuad[2];
371+ vec2 screenBottomLeftCorners[2];
372+ vec2 screenTopRightCorners[2];
373+ vec4 fetchTexcoordRects[2];
374+
375+ DeferredTransform deferredTransforms[2];
376+ auto geometryCache = DependencyManager::get<GeometryCache>();
377+
378+ if (isStereo) {
379+ numPasses = 2;
380+
381+ mat4 eyeViews[2];
382+ args->_context->getStereoProjections(projMats);
383+ args->_context->getStereoViews(eyeViews);
384+
385+ float halfWidth = 0.5 * sWidth;
386+
387+ for (int i = 0; i < numPasses; i++) {
388+ // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half
389+ int sideWidth = monoViewport.z >> 1;
390+ viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w);
391+
392+ deferredTransforms[i].projection = projMats[i];
393+
358394 auto sideViewMat = eyeViews[i] * monoViewMat;
359− viewTransforms[i].evalFromRawMatrix(sideViewMat);
360− deferredTransforms[i].viewInverse = sideViewMat;
361−
362− deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f);
363−
364− clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
365− screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f);
366− screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f);
367−
368− fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
369− }
370− } else {
371−
372− viewports[0] = monoViewport;
373− projMats[0] = monoProjMat;
374−
375− deferredTransforms[0].projection = monoProjMat;
376−
377− deferredTransforms[0].viewInverse = monoViewMat;
378− viewTransforms[0] = monoViewTransform;
379−
380− deferredTransforms[0].stereoSide = 0.0f;
381−
382− clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
383− screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f);
384− screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f);
385−
386− fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
387− }
388−
389− auto eyePoint = viewFrustum->getPosition();
390− float nearRadius = glm::distance(eyePoint, viewFrustum->getNearTopLeft());
391−
392−
393− for (int side = 0; side < numPasses; side++) {
394− // Render in this side's viewport
395− batch.setViewportTransform(viewports[side]);
396− batch.setStateScissorRect(viewports[side]);
397−
398− // Sync and Bind the correct DeferredTransform ubo
399− _deferredTransformBuffer[side]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[side]);
400− batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, _deferredTransformBuffer[side]);
401−
402− glm::vec2 topLeft(-1.0f, -1.0f);
403− glm::vec2 bottomRight(1.0f, 1.0f);
404− glm::vec2 texCoordTopLeft(clipQuad[side].x, clipQuad[side].y);
405− glm::vec2 texCoordBottomRight(clipQuad[side].x + clipQuad[side].z, clipQuad[side].y + clipQuad[side].w);
406−
407− // First Global directional light and ambient pass
408− {
409− bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap());
410−
411− auto& program = _directionalLight;
412− LightLocationsPtr locations = _directionalLightLocations;
413−
414− // TODO: At some point bring back the shadows...
415− // Setup the global directional pass pipeline
416− {
417− if (useSkyboxCubemap) {
418− program = _directionalSkyboxLight;
419− locations = _directionalSkyboxLightLocations;
420− } else if (_ambientLightMode > -1) {
421− program = _directionalAmbientSphereLight;
422− locations = _directionalAmbientSphereLightLocations;
423− }
424− batch.setPipeline(program);
425− }
426−
427− { // Setup the global lighting
428− auto globalLight = _allocatedLights[_globalLights.front()];
429−
430− if (locations->ambientSphere >= 0) {
431− gpu::SphericalHarmonics sh = globalLight->getAmbientSphere();
432− if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) {
433− sh = (*_skybox->getCubemap()->getIrradiance());
434− }
435− for (int i =0; i <gpu::SphericalHarmonics::NUM_COEFFICIENTS; i++) {
436− batch._glUniform4fv(locations->ambientSphere + i, 1, (const float*) (&sh) + i * 4);
437− }
438− }
439−
440− if (useSkyboxCubemap) {
441− batch.setResourceTexture(5, _skybox->getCubemap());
442− }
443−
444− if (locations->lightBufferUnit >= 0) {
445− batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer());
446− }
447−
448− if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) {
449− batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer());
450− }
451− }
452−
453− {
454− batch.setModelTransform(Transform());
455− batch.setProjectionTransform(glm::mat4());
456− batch.setViewTransform(Transform());
457−
458− glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
459− geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
460− }
461−
462− if (useSkyboxCubemap) {
463− batch.setResourceTexture(5, nullptr);
464− }
465− }
466−
467− auto texcoordMat = glm::mat4();
468− /* texcoordMat[0] = glm::vec4(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f);
469− texcoordMat[1] = glm::vec4(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f);
470− */ texcoordMat[0] = glm::vec4(fetchTexcoordRects[side].z / 2.0f, 0.0f, 0.0f, fetchTexcoordRects[side].x + fetchTexcoordRects[side].z / 2.0f);
471− texcoordMat[1] = glm::vec4(0.0f, fetchTexcoordRects[side].w / 2.0f, 0.0f, fetchTexcoordRects[side].y + fetchTexcoordRects[side].w / 2.0f);
472− texcoordMat[2] = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f);
473− texcoordMat[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
474−
475− // enlarge the scales slightly to account for tesselation
476− const float SCALE_EXPANSION = 0.05f;
477−
478−
479− batch.setProjectionTransform(projMats[side]);
480− batch.setViewTransform(viewTransforms[side]);
481−
482− // Splat Point lights
483− if (!_pointLights.empty()) {
484− batch.setPipeline(_pointLight);
485−
486− batch._glUniformMatrix4fv(_pointLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat));
487−
488− for (auto lightID : _pointLights) {
489− auto& light = _allocatedLights[lightID];
490− // IN DEBUG: light->setShowContour(true);
491− if (_pointLightLocations->lightBufferUnit >= 0) {
492− batch.setUniformBuffer(_pointLightLocations->lightBufferUnit, light->getSchemaBuffer());
493− }
494−
495− float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
496− // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
497− // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
498− if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) {
499− Transform model;
500− model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f));
501− batch.setModelTransform(model);
502− batch.setViewTransform(Transform());
503− batch.setProjectionTransform(glm::mat4());
504−
505− glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
506− DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
507−
508− batch.setProjectionTransform(projMats[side]);
509− batch.setViewTransform(viewTransforms[side]);
510− } else {
511− Transform model;
512− model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z));
513− batch.setModelTransform(model);
514− geometryCache->renderSphere(batch, expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
515− }
516− }
517− }
518−
519− // Splat spot lights
520− if (!_spotLights.empty()) {
521− batch.setPipeline(_spotLight);
522−
523− batch._glUniformMatrix4fv(_spotLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat));
524−
525− for (auto lightID : _spotLights) {
526− auto light = _allocatedLights[lightID];
527− // IN DEBUG: light->setShowContour(true);
528−
529− batch.setUniformBuffer(_spotLightLocations->lightBufferUnit, light->getSchemaBuffer());
530−
531− auto eyeLightPos = eyePoint - light->getPosition();
532− auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection());
533−
534− const float TANGENT_LENGTH_SCALE = 0.666f;
535− glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f);
536−
537− float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
538− // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
539− // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
540− if ((eyeHalfPlaneDistance > -nearRadius) &&
541− (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) {
542− coneParam.w = 0.0f;
543− batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
544−
545− Transform model;
546− model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f));
547− batch.setModelTransform(model);
548− batch.setViewTransform(Transform());
549− batch.setProjectionTransform(glm::mat4());
550−
551− glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
552− DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
553−
554− batch.setProjectionTransform( projMats[side]);
555− batch.setViewTransform(viewTransforms[side]);
556− } else {
557− coneParam.w = 1.0f;
558− batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
559−
560− Transform model;
561− model.setTranslation(light->getPosition());
562− model.postRotate(light->getOrientation());
563− model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius));
564−
565− batch.setModelTransform(model);
566− auto mesh = getSpotLightMesh();
567−
568− batch.setIndexBuffer(mesh->getIndexBuffer());
569− batch.setInputBuffer(0, mesh->getVertexBuffer());
570− batch.setInputFormat(mesh->getVertexFormat());
571−
572− auto& part = mesh->getPartBuffer().get<model::Mesh::Part>();
573−
574− batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex);
575− }
576− }
577− }
578− }
579−
580− // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target
581− batch.setResourceTexture(0, nullptr);
582− batch.setResourceTexture(1, nullptr);
583− batch.setResourceTexture(2, nullptr);
584− batch.setResourceTexture(3, nullptr);
585− batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, nullptr);
586−
587− args->_context->render(batch);
588−
589− // End of the Lighting pass
590− if (!_pointLights.empty()) {
591− _pointLights.clear();
592− }
593− if (!_spotLights.empty()) {
594− _spotLights.clear();
595− }
596−}
597−
598−
599−void DeferredLightingEffect::copyBack(RenderArgs* args) {
600− gpu::Batch batch;
601− batch.enableStereo(false);
602− auto framebufferCache = DependencyManager::get<FramebufferCache>();
603− QSize framebufferSize = framebufferCache->getFrameBufferSize();
604−
605− // TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror.
606− // auto destFbo = framebufferCache->getPrimaryFramebuffer();
607− auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor();
608−// gpu::Vec4i vp = args->_viewport;
609−// batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp);
610− batch.setFramebuffer(destFbo);
611− batch.setViewportTransform(args->_viewport);
612− batch.setProjectionTransform(glm::mat4());
613− batch.setViewTransform(Transform());
614− {
615− float sMin = args->_viewport.x / (float)framebufferSize.width();
616− float sWidth = args->_viewport.z / (float)framebufferSize.width();
617− float tMin = args->_viewport.y / (float)framebufferSize.height();
618− float tHeight = args->_viewport.w / (float)framebufferSize.height();
619− Transform model;
620− batch.setPipeline(_blitLightBuffer);
621− model.setTranslation(glm::vec3(sMin, tMin, 0.0));
622− model.setScale(glm::vec3(sWidth, tHeight, 1.0));
623− batch.setModelTransform(model);
624− }
625−
626− batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0));
627− batch.draw(gpu::TRIANGLE_STRIP, 4);
628−
629− args->_context->render(batch);
630− framebufferCache->releaseFramebuffer(_copyFBO);
631−}
632−
633−void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) {
634− auto globalLight = _allocatedLights[_globalLights.front()];
635− args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer());
636−}
637−
638−static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) {
639− auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource)));
640− auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource)));
641−
642− gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
643−
644− gpu::Shader::BindingSet slotBindings;
645− slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0));
646− slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
647− slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
648− slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3));
649− slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4));
650− slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5));
651− const int LIGHT_GPU_SLOT = 3;
652− slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));
653− const int ATMOSPHERE_GPU_SLOT = 4;
654− slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT));
655−
656− slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DeferredLightingEffect::DEFERRED_TRANSFORM_BUFFER_SLOT));
657−
658− gpu::Shader::makeProgram(*program, slotBindings);
659−
660− locations->shadowDistances = program->getUniforms().findLocation("shadowDistances");
661− locations->shadowScale = program->getUniforms().findLocation("shadowScale");
662−
663− locations->radius = program->getUniforms().findLocation("radius");
664− locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00");
665−
666− locations->texcoordMat = program->getUniforms().findLocation("texcoordMat");
667− locations->coneParam = program->getUniforms().findLocation("coneParam");
668−
669− locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
670− locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit");
671− locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer");
672−
673− auto state = std::make_shared<gpu::State>();
674− if (lightVolume) {
675− state->setCullMode(gpu::State::CULL_BACK);
676−
677− // No need for z test since the depth buffer is not bound state->setDepthTest(true, false, gpu::LESS_EQUAL);
678− // TODO: We should bind the true depth buffer both as RT and texture for the depth test
679− // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases
680− state->setDepthClampEnable(true);
681−
682− // additive blending
683− state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
684− } else {
685− state->setCullMode(gpu::State::CULL_BACK);
686− }
687− pipeline.reset(gpu::Pipeline::create(program, state));
688−
689−}
690−
691−void DeferredLightingEffect::setAmbientLightMode(int preset) {
692− if ((preset >= 0) && (preset < gpu::SphericalHarmonics::NUM_PRESET)) {
693− _ambientLightMode = preset;
694− auto light = _allocatedLights.front();
695− light->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(preset % gpu::SphericalHarmonics::NUM_PRESET));
696− } else {
697− // force to preset 0
698− setAmbientLightMode(0);
699− }
700−}
701−
702−void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) {
703− auto light = _allocatedLights.front();
704− light->setDirection(direction);
705− light->setColor(diffuse);
706− light->setIntensity(intensity);
707− light->setAmbientIntensity(ambientIntensity);
708−}
709−
710−void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) {
711− _skybox = skybox;
712−}
713−
714−model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
715− if (!_spotLightMesh) {
716− _spotLightMesh = std::make_shared<model::Mesh>();
717−
718− int slices = 32;
719− int rings = 3;
720− int vertices = 2 + rings * slices;
721− int originVertex = vertices - 2;
722− int capVertex = vertices - 1;
723− int verticesSize = vertices * 3 * sizeof(float);
724− int indices = 3 * slices * (1 + 1 + 2 * (rings -1));
725− int ringFloatOffset = slices * 3;
726−
727−
728− float* vertexData = new float[verticesSize];
729− float* vertexRing0 = vertexData;
730− float* vertexRing1 = vertexRing0 + ringFloatOffset;
731− float* vertexRing2 = vertexRing1 + ringFloatOffset;
732−
733− for (int i = 0; i < slices; i++) {
734− float theta = TWO_PI * i / slices;
735− auto cosin = glm::vec2(cosf(theta), sinf(theta));
736−
737− *(vertexRing0++) = cosin.x;
738− *(vertexRing0++) = cosin.y;
739− *(vertexRing0++) = 0.0f;
740−
741− *(vertexRing1++) = cosin.x;
742− *(vertexRing1++) = cosin.y;
743− *(vertexRing1++) = 0.33f;
744−
745− *(vertexRing2++) = cosin.x;
746− *(vertexRing2++) = cosin.y;
747− *(vertexRing2++) = 0.66f;
748− }
749−
750− *(vertexRing2++) = 0.0f;
751− *(vertexRing2++) = 0.0f;
752− *(vertexRing2++) = -1.0f;
753−
754− *(vertexRing2++) = 0.0f;
755− *(vertexRing2++) = 0.0f;
756− *(vertexRing2++) = 1.0f;
757−
758− _spotLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ));
759− delete[] vertexData;
760−
761− gpu::uint16* indexData = new gpu::uint16[indices];
762− gpu::uint16* index = indexData;
763− for (int i = 0; i < slices; i++) {
764− *(index++) = originVertex;
765−
766− int s0 = i;
767− int s1 = ((i + 1) % slices);
768− *(index++) = s0;
769− *(index++) = s1;
770−
771− int s2 = s0 + slices;
772− int s3 = s1 + slices;
773− *(index++) = s1;
774− *(index++) = s0;
775− *(index++) = s2;
776−
777− *(index++) = s1;
778− *(index++) = s2;
779− *(index++) = s3;
780−
781− int s4 = s2 + slices;
782− int s5 = s3 + slices;
783− *(index++) = s3;
784− *(index++) = s2;
785− *(index++) = s4;
786−
787− *(index++) = s3;
788− *(index++) = s4;
789− *(index++) = s5;
790−
791−
792− *(index++) = s5;
793− *(index++) = s4;
794− *(index++) = capVertex;
795− }
796−
797− _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16));
798− delete[] indexData;
799−
800− model::Mesh::Part part(0, indices, 0, model::Mesh::TRIANGLES);
801− //DEBUG: model::Mesh::Part part(0, indices, 0, model::Mesh::LINE_STRIP);
802−
803− _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL));
804−
805− _spotLightMesh->makeBufferStream();
806− }
807− return _spotLightMesh;
808−}
809−
395+ viewTransforms[i].evalFromRawMatrix(sideViewMat);
396+ deferredTransforms[i].viewInverse = sideViewMat;
397+
398+ deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f);
399+
400+ clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
401+ screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f);
402+ screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f);
403+
404+ fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
405+ }
406+ } else {
407+
408+ viewports[0] = monoViewport;
409+ projMats[0] = monoProjMat;
410+
411+ deferredTransforms[0].projection = monoProjMat;
412+
413+ deferredTransforms[0].viewInverse = monoViewMat;
414+ viewTransforms[0] = monoViewTransform;
415+
416+ deferredTransforms[0].stereoSide = 0.0f;
417+
418+ clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
419+ screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f);
420+ screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f);
421+
422+ fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
423+ }
424+
425+ auto eyePoint = viewFrustum->getPosition();
426+ float nearRadius = glm::distance(eyePoint, viewFrustum->getNearTopLeft());
427+
428+
429+ for (int side = 0; side < numPasses; side++) {
430+ // Render in this side's viewport
431+ batch.setViewportTransform(viewports[side]);
432+ batch.setStateScissorRect(viewports[side]);
433+
434+ // Sync and Bind the correct DeferredTransform ubo
435+ _deferredTransformBuffer[side]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[side]);
436+ batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, _deferredTransformBuffer[side]);
437+
438+ glm::vec2 topLeft(-1.0f, -1.0f);
439+ glm::vec2 bottomRight(1.0f, 1.0f);
440+ glm::vec2 texCoordTopLeft(clipQuad[side].x, clipQuad[side].y);
441+ glm::vec2 texCoordBottomRight(clipQuad[side].x + clipQuad[side].z, clipQuad[side].y + clipQuad[side].w);
442+
443+ // First Global directional light and ambient pass
444+ {
445+ bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap());
446+
447+ auto& program = _directionalLight;
448+ LightLocationsPtr locations = _directionalLightLocations;
449+
450+ // TODO: At some point bring back the shadows...
451+ // Setup the global directional pass pipeline
452+ {
453+ if (useSkyboxCubemap) {
454+ program = _directionalSkyboxLight;
455+ locations = _directionalSkyboxLightLocations;
456+ } else if (_ambientLightMode > -1) {
457+ program = _directionalAmbientSphereLight;
458+ locations = _directionalAmbientSphereLightLocations;
459+ }
460+ batch.setPipeline(program);
461+ }
462+
463+ { // Setup the global lighting
464+ auto globalLight = _allocatedLights[_globalLights.front()];
465+
466+ if (locations->ambientSphere >= 0) {
467+ gpu::SphericalHarmonics sh = globalLight->getAmbientSphere();
468+ if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) {
469+ sh = (*_skybox->getCubemap()->getIrradiance());
470+ }
471+ for (int i =0; i <gpu::SphericalHarmonics::NUM_COEFFICIENTS; i++) {
472+ batch._glUniform4fv(locations->ambientSphere + i, 1, (const float*) (&sh) + i * 4);
473+ }
474+ }
475+
476+ if (useSkyboxCubemap) {
477+ batch.setResourceTexture(5, _skybox->getCubemap());
478+ }
479+
480+ if (locations->lightBufferUnit >= 0) {
481+ batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer());
482+ }
483+
484+ if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) {
485+ batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer());
486+ }
487+ }
488+
489+ {
490+ batch.setModelTransform(Transform());
491+ batch.setProjectionTransform(glm::mat4());
492+ batch.setViewTransform(Transform());
493+
494+ glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
495+ geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
496+ }
497+
498+ if (useSkyboxCubemap) {
499+ batch.setResourceTexture(5, nullptr);
500+ }
501+ }
502+
503+ auto texcoordMat = glm::mat4();
504+ /* texcoordMat[0] = glm::vec4(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f);
505+ texcoordMat[1] = glm::vec4(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f);
506+ */ texcoordMat[0] = glm::vec4(fetchTexcoordRects[side].z / 2.0f, 0.0f, 0.0f, fetchTexcoordRects[side].x + fetchTexcoordRects[side].z / 2.0f);
507+ texcoordMat[1] = glm::vec4(0.0f, fetchTexcoordRects[side].w / 2.0f, 0.0f, fetchTexcoordRects[side].y + fetchTexcoordRects[side].w / 2.0f);
508+ texcoordMat[2] = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f);
509+ texcoordMat[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
510+
511+ // enlarge the scales slightly to account for tesselation
512+ const float SCALE_EXPANSION = 0.05f;
513+
514+
515+ batch.setProjectionTransform(projMats[side]);
516+ batch.setViewTransform(viewTransforms[side]);
517+
518+ // Splat Point lights
519+ if (!_pointLights.empty()) {
520+ batch.setPipeline(_pointLight);
521+
522+ batch._glUniformMatrix4fv(_pointLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat));
523+
524+ for (auto lightID : _pointLights) {
525+ auto& light = _allocatedLights[lightID];
526+ // IN DEBUG: light->setShowContour(true);
527+ if (_pointLightLocations->lightBufferUnit >= 0) {
528+ batch.setUniformBuffer(_pointLightLocations->lightBufferUnit, light->getSchemaBuffer());
529+ }
530+
531+ float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
532+ // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
533+ // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
534+ if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) {
535+ Transform model;
536+ model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f));
537+ batch.setModelTransform(model);
538+ batch.setViewTransform(Transform());
539+ batch.setProjectionTransform(glm::mat4());
540+
541+ glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
542+ DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
543+
544+ batch.setProjectionTransform(projMats[side]);
545+ batch.setViewTransform(viewTransforms[side]);
546+ } else {
547+ Transform model;
548+ model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z));
549+ batch.setModelTransform(model);
550+ geometryCache->renderSphere(batch, expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
551+ }
552+ }
553+ }
554+
555+ // Splat spot lights
556+ if (!_spotLights.empty()) {
557+ batch.setPipeline(_spotLight);
558+
559+ batch._glUniformMatrix4fv(_spotLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat));
560+
561+ for (auto lightID : _spotLights) {
562+ auto light = _allocatedLights[lightID];
563+ // IN DEBUG: light->setShowContour(true);
564+
565+ batch.setUniformBuffer(_spotLightLocations->lightBufferUnit, light->getSchemaBuffer());
566+
567+ auto eyeLightPos = eyePoint - light->getPosition();
568+ auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection());
569+
570+ const float TANGENT_LENGTH_SCALE = 0.666f;
571+ glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f);
572+
573+ float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
574+ // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
575+ // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
576+ if ((eyeHalfPlaneDistance > -nearRadius) &&
577+ (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) {
578+ coneParam.w = 0.0f;
579+ batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
580+
581+ Transform model;
582+ model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f));
583+ batch.setModelTransform(model);
584+ batch.setViewTransform(Transform());
585+ batch.setProjectionTransform(glm::mat4());
586+
587+ glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
588+ DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
589+
590+ batch.setProjectionTransform( projMats[side]);
591+ batch.setViewTransform(viewTransforms[side]);
592+ } else {
593+ coneParam.w = 1.0f;
594+ batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
595+
596+ Transform model;
597+ model.setTranslation(light->getPosition());
598+ model.postRotate(light->getOrientation());
599+ model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius));
600+
601+ batch.setModelTransform(model);
602+ auto mesh = getSpotLightMesh();
603+
604+ batch.setIndexBuffer(mesh->getIndexBuffer());
605+ batch.setInputBuffer(0, mesh->getVertexBuffer());
606+ batch.setInputFormat(mesh->getVertexFormat());
607+
608+ auto& part = mesh->getPartBuffer().get<model::Mesh::Part>();
609+
610+ batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex);
611+ }
612+ }
613+ }
614+ }
615+
616+ // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target
617+ batch.setResourceTexture(0, nullptr);
618+ batch.setResourceTexture(1, nullptr);
619+ batch.setResourceTexture(2, nullptr);
620+ batch.setResourceTexture(3, nullptr);
621+ batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, nullptr);
622+
623+ args->_context->render(batch);
624+
625+ // End of the Lighting pass
626+ if (!_pointLights.empty()) {
627+ _pointLights.clear();
628+ }
629+ if (!_spotLights.empty()) {
630+ _spotLights.clear();
631+ }
632+}
633+
634+
635+void DeferredLightingEffect::copyBack(RenderArgs* args) {
636+ gpu::Batch batch;
637+ batch.enableStereo(false);
638+ auto framebufferCache = DependencyManager::get<FramebufferCache>();
639+ QSize framebufferSize = framebufferCache->getFrameBufferSize();
640+
641+ // TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror.
642+ // auto destFbo = framebufferCache->getPrimaryFramebuffer();
643+ auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor();
644+// gpu::Vec4i vp = args->_viewport;
645+// batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp);
646+ batch.setFramebuffer(destFbo);
647+ batch.setViewportTransform(args->_viewport);
648+ batch.setProjectionTransform(glm::mat4());
649+ batch.setViewTransform(Transform());
650+ {
651+ float sMin = args->_viewport.x / (float)framebufferSize.width();
652+ float sWidth = args->_viewport.z / (float)framebufferSize.width();
653+ float tMin = args->_viewport.y / (float)framebufferSize.height();
654+ float tHeight = args->_viewport.w / (float)framebufferSize.height();
655+ Transform model;
656+ batch.setPipeline(_blitLightBuffer);
657+ model.setTranslation(glm::vec3(sMin, tMin, 0.0));
658+ model.setScale(glm::vec3(sWidth, tHeight, 1.0));
659+ batch.setModelTransform(model);
660+ }
661+
662+ batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0));
663+ batch.draw(gpu::TRIANGLE_STRIP, 4);
664+
665+ args->_context->render(batch);
666+ framebufferCache->releaseFramebuffer(_copyFBO);
667+}
668+
669+void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) {
670+ auto globalLight = _allocatedLights[_globalLights.front()];
671+ args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer());
672+}
673+
674+static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) {
675+ auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource)));
676+ auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource)));
677+
678+ gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
679+
680+ gpu::Shader::BindingSet slotBindings;
681+ slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0));
682+ slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
683+ slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
684+ slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3));
685+ slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4));
686+ slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5));
687+ const int LIGHT_GPU_SLOT = 3;
688+ slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));
689+ const int ATMOSPHERE_GPU_SLOT = 4;
690+ slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT));
691+
692+ slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DeferredLightingEffect::DEFERRED_TRANSFORM_BUFFER_SLOT));
693+
694+ gpu::Shader::makeProgram(*program, slotBindings);
695+
696+ locations->shadowDistances = program->getUniforms().findLocation("shadowDistances");
697+ locations->shadowScale = program->getUniforms().findLocation("shadowScale");
698+
699+ locations->radius = program->getUniforms().findLocation("radius");
700+ locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00");
701+
702+ locations->texcoordMat = program->getUniforms().findLocation("texcoordMat");
703+ locations->coneParam = program->getUniforms().findLocation("coneParam");
704+
705+ locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
706+ locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit");
707+ locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer");
708+
709+ auto state = std::make_shared<gpu::State>();
710+ if (lightVolume) {
711+ state->setCullMode(gpu::State::CULL_BACK);
712+
713+ // No need for z test since the depth buffer is not bound state->setDepthTest(true, false, gpu::LESS_EQUAL);
714+ // TODO: We should bind the true depth buffer both as RT and texture for the depth test
715+ // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases
716+ state->setDepthClampEnable(true);
717+
718+ // additive blending
719+ state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
720+ } else {
721+ state->setCullMode(gpu::State::CULL_BACK);
722+ }
723+ pipeline.reset(gpu::Pipeline::create(program, state));
724+
725+}
726+
727+void DeferredLightingEffect::setAmbientLightMode(int preset) {
728+ if ((preset >= 0) && (preset < gpu::SphericalHarmonics::NUM_PRESET)) {
729+ _ambientLightMode = preset;
730+ auto light = _allocatedLights.front();
731+ light->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(preset % gpu::SphericalHarmonics::NUM_PRESET));
732+ } else {
733+ // force to preset 0
734+ setAmbientLightMode(0);
735+ }
736+}
737+
738+void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) {
739+ auto light = _allocatedLights.front();
740+ light->setDirection(direction);
741+ light->setColor(diffuse);
742+ light->setIntensity(intensity);
743+ light->setAmbientIntensity(ambientIntensity);
744+}
745+
746+void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) {
747+ _skybox = skybox;
748+}
749+
750+model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
751+ if (!_spotLightMesh) {
752+ _spotLightMesh = std::make_shared<model::Mesh>();
753+
754+ int slices = 32;
755+ int rings = 3;
756+ int vertices = 2 + rings * slices;
757+ int originVertex = vertices - 2;
758+ int capVertex = vertices - 1;
759+ int verticesSize = vertices * 3 * sizeof(float);
760+ int indices = 3 * slices * (1 + 1 + 2 * (rings -1));
761+ int ringFloatOffset = slices * 3;
762+
763+
764+ float* vertexData = new float[verticesSize];
765+ float* vertexRing0 = vertexData;
766+ float* vertexRing1 = vertexRing0 + ringFloatOffset;
767+ float* vertexRing2 = vertexRing1 + ringFloatOffset;
768+
769+ for (int i = 0; i < slices; i++) {
770+ float theta = TWO_PI * i / slices;
771+ auto cosin = glm::vec2(cosf(theta), sinf(theta));
772+
773+ *(vertexRing0++) = cosin.x;
774+ *(vertexRing0++) = cosin.y;
775+ *(vertexRing0++) = 0.0f;
776+
777+ *(vertexRing1++) = cosin.x;
778+ *(vertexRing1++) = cosin.y;
779+ *(vertexRing1++) = 0.33f;
780+
781+ *(vertexRing2++) = cosin.x;
782+ *(vertexRing2++) = cosin.y;
783+ *(vertexRing2++) = 0.66f;
784+ }
785+
786+ *(vertexRing2++) = 0.0f;
787+ *(vertexRing2++) = 0.0f;
788+ *(vertexRing2++) = -1.0f;
789+
790+ *(vertexRing2++) = 0.0f;
791+ *(vertexRing2++) = 0.0f;
792+ *(vertexRing2++) = 1.0f;
793+
794+ _spotLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ));
795+ delete[] vertexData;
796+
797+ gpu::uint16* indexData = new gpu::uint16[indices];
798+ gpu::uint16* index = indexData;
799+ for (int i = 0; i < slices; i++) {
800+ *(index++) = originVertex;
801+
802+ int s0 = i;
803+ int s1 = ((i + 1) % slices);
804+ *(index++) = s0;
805+ *(index++) = s1;
806+
807+ int s2 = s0 + slices;
808+ int s3 = s1 + slices;
809+ *(index++) = s1;
810+ *(index++) = s0;
811+ *(index++) = s2;
812+
813+ *(index++) = s1;
814+ *(index++) = s2;
815+ *(index++) = s3;
816+
817+ int s4 = s2 + slices;
818+ int s5 = s3 + slices;
819+ *(index++) = s3;
820+ *(index++) = s2;
821+ *(index++) = s4;
822+
823+ *(index++) = s3;
824+ *(index++) = s4;
825+ *(index++) = s5;
826+
827+
828+ *(index++) = s5;
829+ *(index++) = s4;
830+ *(index++) = capVertex;
831+ }
832+
833+ _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16));
834+ delete[] indexData;
835+
836+ model::Mesh::Part part(0, indices, 0, model::Mesh::TRIANGLES);
837+ //DEBUG: model::Mesh::Part part(0, indices, 0, model::Mesh::LINE_STRIP);
838+
839+ _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL));
840+
841+ _spotLightMesh->makeBufferStream();
842+ }
843+ return _spotLightMesh;
844+}
845+