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