Showing the changes to libraries/render-utils/src/DeferredLightingEffect.cpp (1 of 17 files). Show all
Unified · Split
| @@ -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*) ¶meters)); | |
| 279 | − _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); | |
| 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*) ¶meters)); | |
| 315 | + _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); | |
| 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 | + | |
| 358 | 394 | 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 | + | |