//// DeferredLightingEffect.cpp// interface/src/renderer//// Created by Andrzej Kapolka on 9/11/14.// Copyright 2014 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "DeferredLightingEffect.h"#include <QtCore/QFileSelector> #include <GLMHelpers.h>#include <PathUtils.h>#include <ViewFrustum.h>#include <shared/FileUtils.h>#include <gpu/Batch.h>#include <gpu/Context.h>#include <shaders/Shaders.h> #include <graphics/ShaderConstants.h> #include "render-utils/ShaderConstants.h"#include "StencilMaskPass.h"#include "AbstractViewStateInterface.h"#include "GeometryCache.h"#include "TextureCache.h"#include "FramebufferCache.h" namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer;} namespace gr { using graphics::slot::texture::Texture; using graphics::slot::buffer::Buffer;} using namespace render; struct LightLocations { bool shadowTransform{ false }; void initialize(const gpu::ShaderPointer& program) { shadowTransform = program->getUniformBuffers().isValid(ru::Buffer::ShadowParams); }}; static void loadLightProgram(int programId, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); void DeferredLightingEffect::init() { _directionalAmbientSphereLightLocations = std::make_shared<LightLocations>(); _directionalSkyboxLightLocations = std::make_shared<LightLocations>(); _directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>(); _directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>(); _localLightLocations = std::make_shared<LightLocations>(); _localLightOutlineLocations = std::make_shared<LightLocations>(); loadLightProgram(shader::render_utils::program::directional_ambient_light, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); loadLightProgram(shader::render_utils::program::directional_skybox_light, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); loadLightProgram(shader::render_utils::program::directional_ambient_light_shadow, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); loadLightProgram(shader::render_utils::program::directional_skybox_light_shadow, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(shader::render_utils::program::local_lights_shading, true, _localLight, _localLightLocations); loadLightProgram(shader::render_utils::program::local_lights_drawOutline, true, _localLightOutline, _localLightOutlineLocations);} void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch) { PerformanceTimer perfTimer("DLE->setupBatch()"); graphics::LightPointer keySunLight; auto lightStage = args->_scene->getStage<LightStage>(); if (lightStage) { keySunLight = lightStage->getCurrentKeyLight(); } graphics::LightPointer keyAmbiLight; if (lightStage) { keyAmbiLight = lightStage->getCurrentAmbientLight(); } if (keySunLight) { batch.setUniformBuffer(gr::Buffer::KeyLight, keySunLight->getLightSchemaBuffer()); } if (keyAmbiLight) { batch.setUniformBuffer(gr::Buffer::AmbientLight, keyAmbiLight->getAmbientSchemaBuffer()); if (keyAmbiLight->getAmbientMap() ) { batch.setResourceTexture(ru::Texture::Skybox, keyAmbiLight->getAmbientMap()); } }} void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch) { batch.setUniformBuffer(gr::Buffer::KeyLight, nullptr); batch.setUniformBuffer(gr::Buffer::AmbientLight, nullptr); batch.setResourceTexture(ru::Texture::Skybox, nullptr);} void DeferredLightingEffect::setupLocalLightsBatch(gpu::Batch& batch, const LightClustersPointer& lightClusters) { // Bind the global list of lights and the visible lights this frame batch.setUniformBuffer(gr::Buffer::Light, lightClusters->_lightStage->getLightArrayBuffer()); batch.setUniformBuffer(ru::Buffer::LightClusterFrustumGrid, lightClusters->_frustumGridBuffer); batch.setUniformBuffer(ru::Buffer::LightClusterGrid, lightClusters->_clusterGridBuffer); batch.setUniformBuffer(ru::Buffer::LightClusterContent, lightClusters->_clusterContentBuffer);} void DeferredLightingEffect::unsetLocalLightsBatch(gpu::Batch& batch) { batch.setUniformBuffer(gr::Buffer::Light, nullptr); batch.setUniformBuffer(ru::Buffer::LightClusterGrid, nullptr); batch.setUniformBuffer(ru::Buffer::LightClusterContent, nullptr); batch.setUniformBuffer(ru::Buffer::LightClusterFrustumGrid, nullptr);} static gpu::ShaderPointer makeLightProgram(int programId, LightLocationsPtr& locations) { gpu::ShaderPointer program = gpu::Shader::createProgram(programId); locations->initialize(program); return program;} static void loadLightProgram(int programId, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { gpu::ShaderPointer program = makeLightProgram(programId, locations); auto state = std::make_shared<gpu::State>(); state->setColorWriteMask(true, true, true, false); if (lightVolume) { PrepareStencil::testShape(*state); state->setCullMode(gpu::State::CULL_BACK); //state->setCullMode(gpu::State::CULL_FRONT); //state->setDepthTest(true, false, gpu::GREATER_EQUAL); //state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } else { // Stencil test all the light passes for objects pixels only, not the background PrepareStencil::testShape(*state); state->setCullMode(gpu::State::CULL_BACK); // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } pipeline = gpu::Pipeline::create(program, state); } #include <shared/Shapes.h> graphics::MeshPointer DeferredLightingEffect::getPointLightMesh() { if (!_pointLightMesh) { _pointLightMesh = std::make_shared<graphics::Mesh>(); // let's use a icosahedron auto solid = geometry::icosahedron(); solid.fitDimension(1.05f); // scaled to 1.05 meters, it will be scaled by the shader accordingly to the light size int verticesSize = (int) (solid.vertices.size() * 3 * sizeof(float)); float* vertexData = (float*) solid.vertices.data(); _pointLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); int nbIndices = (int) solid.faces.size() * 3; gpu::uint16* indexData = new gpu::uint16[nbIndices]; gpu::uint16* index = indexData; for (auto face : solid.faces) { *(index++) = face[0]; *(index++) = face[1]; *(index++) = face[2]; } _pointLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * nbIndices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); delete[] indexData; std::vector<graphics::Mesh::Part> parts; parts.push_back(graphics::Mesh::Part(0, nbIndices, 0, graphics::Mesh::TRIANGLES)); parts.push_back(graphics::Mesh::Part(0, nbIndices, 0, graphics::Mesh::LINE_STRIP)); // outline version _pointLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); } return _pointLightMesh;} graphics::MeshPointer DeferredLightingEffect::getSpotLightMesh() { if (!_spotLightMesh) { _spotLightMesh = std::make_shared<graphics::Mesh>(); int slices = 16; int rings = 3; int vertices = 2 + rings * slices; int originVertex = vertices - 2; int capVertex = vertices - 1; int verticesSize = vertices * 3 * sizeof(float); int indices = 3 * slices * (1 + 1 + 2 * (rings -1)); int ringFloatOffset = slices * 3; float* vertexData = new float[verticesSize]; float* vertexRing0 = vertexData; float* vertexRing1 = vertexRing0 + ringFloatOffset; float* vertexRing2 = vertexRing1 + ringFloatOffset; for (int i = 0; i < slices; i++) { float theta = TWO_PI * i / slices; auto cosin = glm::vec2(cosf(theta), sinf(theta)); *(vertexRing0++) = cosin.x; *(vertexRing0++) = cosin.y; *(vertexRing0++) = 0.0f; *(vertexRing1++) = cosin.x; *(vertexRing1++) = cosin.y; *(vertexRing1++) = 0.33f; *(vertexRing2++) = cosin.x; *(vertexRing2++) = cosin.y; *(vertexRing2++) = 0.66f; } *(vertexRing2++) = 0.0f; *(vertexRing2++) = 0.0f; *(vertexRing2++) = -1.0f; *(vertexRing2++) = 0.0f; *(vertexRing2++) = 0.0f; *(vertexRing2++) = 1.0f; _spotLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); delete[] vertexData; gpu::uint16* indexData = new gpu::uint16[indices]; gpu::uint16* index = indexData; for (int i = 0; i < slices; i++) { *(index++) = originVertex; int s0 = i; int s1 = ((i + 1) % slices); *(index++) = s0; *(index++) = s1; int s2 = s0 + slices; int s3 = s1 + slices; *(index++) = s1; *(index++) = s0; *(index++) = s2; *(index++) = s1; *(index++) = s2; *(index++) = s3; int s4 = s2 + slices; int s5 = s3 + slices; *(index++) = s3; *(index++) = s2; *(index++) = s4; *(index++) = s3; *(index++) = s4; *(index++) = s5; *(index++) = s5; *(index++) = s4; *(index++) = capVertex; } _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); delete[] indexData; std::vector<graphics::Mesh::Part> parts; parts.push_back(graphics::Mesh::Part(0, indices, 0, graphics::Mesh::TRIANGLES)); parts.push_back(graphics::Mesh::Part(0, indices, 0, graphics::Mesh::LINE_STRIP)); // outline version _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); } return _spotLightMesh;} gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name)); auto colorFormat = gpu::Element::COLOR_SRGBA_32; auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); framebuffer->setRenderBuffer(0, primaryColorTexture); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); framebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); return framebuffer;} void PreparePrimaryFramebuffer::configure(const Config& config) { _resolutionScale = config.resolutionScale;} void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, Output& primaryFramebuffer) { glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale); // Resizing framebuffers instead of re-building them seems to cause issues with threaded // rendering if (!_primaryFramebuffer || _primaryFramebuffer->getSize() != scaledFrameSize) { _primaryFramebuffer = createFramebuffer("deferredPrimary", scaledFrameSize); } primaryFramebuffer = _primaryFramebuffer; // Set viewport for the rest of the scaled passes renderContext->args->_viewport.z = scaledFrameSize.x; renderContext->args->_viewport.w = scaledFrameSize.y;} void PrepareDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { auto args = renderContext->args; auto primaryFramebuffer = inputs.get0(); auto lightingModel = inputs.get1(); if (!_deferredFramebuffer) { _deferredFramebuffer = std::make_shared<DeferredFramebuffer>(); } _deferredFramebuffer->updatePrimaryDepth(primaryFramebuffer->getDepthStencilBuffer()); outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); gpu::doInBatch("PrepareDeferred::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); // Clear deferred auto deferredFbo = _deferredFramebuffer->getDeferredFramebuffer(); batch.setFramebuffer(deferredFbo); // Clear Color, Depth and Stencil for deferred buffer batch.clearFramebuffer( gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_COLOR3 | gpu::Framebuffer::BUFFER_DEPTH | gpu::Framebuffer::BUFFER_STENCIL, vec4(vec3(0), 0), 1.0, 0, true); // For the rest of the rendering, bind the lighting model batch.setUniformBuffer(ru::Buffer::LightModel, lightingModel->getParametersBuffer()); }); // Prepare a fresh Light Frame auto lightStage = renderContext->_scene->getStage<LightStage>(); assert(lightStage); lightStage->_currentFrame.clear();} void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, const LightingModelPointer& lightingModel, const graphics::HazePointer& haze, const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource, bool renderShadows) { auto args = renderContext->args; auto& batch = (*args->_batch); { // Framebuffer copy operations cannot function as multipass stereo operations. batch.enableStereo(false); auto textureCache = DependencyManager::get<TextureCache>(); auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>(); // binding the first framebuffer auto lightingFBO = deferredFramebuffer->getLightingFramebuffer(); batch.setFramebuffer(lightingFBO); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); // Bind the G-Buffer surfaces batch.setResourceTexture(ru::Texture::DeferredColor, deferredFramebuffer->getDeferredColorTexture()); batch.setResourceTexture(ru::Texture::DeferredNormal, deferredFramebuffer->getDeferredNormalTexture()); batch.setResourceTexture(ru::Texture::DeferredSpecular, deferredFramebuffer->getDeferredSpecularTexture()); batch.setResourceTexture(ru::Texture::DeferredDepth, deferredFramebuffer->getPrimaryDepthTexture()); // FIXME: Different render modes should have different tasks if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled() && ambientOcclusionFramebuffer) { batch.setResourceTexture(ru::Texture::DeferredObscurance, ambientOcclusionFramebuffer->getOcclusionTexture()); } else { // need to assign the white texture if ao is off batch.setResourceTexture(ru::Texture::DeferredObscurance, textureCache->getWhiteTexture()); } // The Deferred Frame Transform buffer batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); // THe lighting model batch.setUniformBuffer(ru::Buffer::LightModel, lightingModel->getParametersBuffer()); // Subsurface scattering specific if (surfaceGeometryFramebuffer) { batch.setResourceTexture(ru::Texture::DeferredLinearZEye, surfaceGeometryFramebuffer->getLinearDepthTexture()); batch.setResourceTexture(ru::Texture::DeferredCurvature, surfaceGeometryFramebuffer->getCurvatureTexture()); batch.setResourceTexture(ru::Texture::DeferredDiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture()); } if (subsurfaceScatteringResource) { batch.setUniformBuffer(ru::Buffer::SsscParams, subsurfaceScatteringResource->getParametersBuffer()); batch.setResourceTexture(ru::Texture::SsscLut, subsurfaceScatteringResource->getScatteringTable()); batch.setResourceTexture(ru::Texture::SsscSpecularBeckmann, subsurfaceScatteringResource->getScatteringSpecular()); } // Global directional light and ambient pass auto lightStage = renderContext->_scene->getStage<LightStage>(); assert(lightStage); assert(lightStage->getNumLights() > 0); auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; // Bind the shadow buffers if (globalShadow) { batch.setResourceTexture(ru::Texture::Shadow, globalShadow->map); } auto program = deferredLightingEffect->_directionalSkyboxLight; LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations; auto keyLight = lightAndShadow.first; graphics::LightPointer ambientLight; if (lightStage && lightStage->_currentFrame._ambientLights.size()) { ambientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); } bool hasAmbientMap = (ambientLight != nullptr); // Setup the global directional pass pipeline { // Check if keylight casts shadows bool keyLightCastShadows { false }; if (renderShadows && lightStage && lightStage->_currentFrame._sunLights.size()) { graphics::LightPointer keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front()); if (keyLight) { keyLightCastShadows = keyLight->getCastShadows(); } } if (deferredLightingEffect->_shadowMapEnabled && keyLightCastShadows) { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version if (hasAmbientMap) { program = deferredLightingEffect->_directionalSkyboxLightShadow; locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations; } else { program = deferredLightingEffect->_directionalAmbientSphereLightShadow; locations = deferredLightingEffect->_directionalAmbientSphereLightShadowLocations; } } else { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version if (hasAmbientMap) { program = deferredLightingEffect->_directionalSkyboxLight; locations = deferredLightingEffect->_directionalSkyboxLightLocations; } else { program = deferredLightingEffect->_directionalAmbientSphereLight; locations = deferredLightingEffect->_directionalAmbientSphereLightLocations; } } if (locations->shadowTransform && globalShadow) { batch.setUniformBuffer(ru::Buffer::ShadowParams, globalShadow->getBuffer()); } batch.setPipeline(program); } // Setup the global lighting deferredLightingEffect->setupKeyLightBatch(args, batch); Lines 1–500 of 718. Load more
// // DeferredLightingEffect.cpp // interface/src/renderer // // Created by Andrzej Kapolka on 9/11/14. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "DeferredLightingEffect.h" #include <QtCore/QFileSelector> #include <GLMHelpers.h> #include <PathUtils.h> #include <ViewFrustum.h> #include <shared/FileUtils.h> #include <gpu/Batch.h> #include <gpu/Context.h> #include <shaders/Shaders.h> #include <graphics/ShaderConstants.h> #include "render-utils/ShaderConstants.h" #include "StencilMaskPass.h" #include "AbstractViewStateInterface.h" #include "GeometryCache.h" #include "TextureCache.h" #include "FramebufferCache.h" namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; } namespace gr { using graphics::slot::texture::Texture; using graphics::slot::buffer::Buffer; } using namespace render; struct LightLocations { bool shadowTransform{ false }; void initialize(const gpu::ShaderPointer& program) { shadowTransform = program->getUniformBuffers().isValid(ru::Buffer::ShadowParams); } }; static void loadLightProgram(int programId, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); void DeferredLightingEffect::init() { _directionalAmbientSphereLightLocations = std::make_shared<LightLocations>(); _directionalSkyboxLightLocations = std::make_shared<LightLocations>(); _directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>(); _directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>(); _localLightLocations = std::make_shared<LightLocations>(); _localLightOutlineLocations = std::make_shared<LightLocations>(); loadLightProgram(shader::render_utils::program::directional_ambient_light, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); loadLightProgram(shader::render_utils::program::directional_skybox_light, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); loadLightProgram(shader::render_utils::program::directional_ambient_light_shadow, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); loadLightProgram(shader::render_utils::program::directional_skybox_light_shadow, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(shader::render_utils::program::local_lights_shading, true, _localLight, _localLightLocations); loadLightProgram(shader::render_utils::program::local_lights_drawOutline, true, _localLightOutline, _localLightOutlineLocations); } void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch) { PerformanceTimer perfTimer("DLE->setupBatch()"); graphics::LightPointer keySunLight; auto lightStage = args->_scene->getStage<LightStage>(); if (lightStage) { keySunLight = lightStage->getCurrentKeyLight(); } graphics::LightPointer keyAmbiLight; if (lightStage) { keyAmbiLight = lightStage->getCurrentAmbientLight(); } if (keySunLight) { batch.setUniformBuffer(gr::Buffer::KeyLight, keySunLight->getLightSchemaBuffer()); } if (keyAmbiLight) { batch.setUniformBuffer(gr::Buffer::AmbientLight, keyAmbiLight->getAmbientSchemaBuffer()); if (keyAmbiLight->getAmbientMap() ) { batch.setResourceTexture(ru::Texture::Skybox, keyAmbiLight->getAmbientMap()); } } } void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch) { batch.setUniformBuffer(gr::Buffer::KeyLight, nullptr); batch.setUniformBuffer(gr::Buffer::AmbientLight, nullptr); batch.setResourceTexture(ru::Texture::Skybox, nullptr); } void DeferredLightingEffect::setupLocalLightsBatch(gpu::Batch& batch, const LightClustersPointer& lightClusters) { // Bind the global list of lights and the visible lights this frame batch.setUniformBuffer(gr::Buffer::Light, lightClusters->_lightStage->getLightArrayBuffer()); batch.setUniformBuffer(ru::Buffer::LightClusterFrustumGrid, lightClusters->_frustumGridBuffer); batch.setUniformBuffer(ru::Buffer::LightClusterGrid, lightClusters->_clusterGridBuffer); batch.setUniformBuffer(ru::Buffer::LightClusterContent, lightClusters->_clusterContentBuffer); } void DeferredLightingEffect::unsetLocalLightsBatch(gpu::Batch& batch) { batch.setUniformBuffer(gr::Buffer::Light, nullptr); batch.setUniformBuffer(ru::Buffer::LightClusterGrid, nullptr); batch.setUniformBuffer(ru::Buffer::LightClusterContent, nullptr); batch.setUniformBuffer(ru::Buffer::LightClusterFrustumGrid, nullptr); } static gpu::ShaderPointer makeLightProgram(int programId, LightLocationsPtr& locations) { gpu::ShaderPointer program = gpu::Shader::createProgram(programId); locations->initialize(program); return program; } static void loadLightProgram(int programId, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { gpu::ShaderPointer program = makeLightProgram(programId, locations); auto state = std::make_shared<gpu::State>(); state->setColorWriteMask(true, true, true, false); if (lightVolume) { PrepareStencil::testShape(*state); state->setCullMode(gpu::State::CULL_BACK); //state->setCullMode(gpu::State::CULL_FRONT); //state->setDepthTest(true, false, gpu::GREATER_EQUAL); //state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } else { // Stencil test all the light passes for objects pixels only, not the background PrepareStencil::testShape(*state); state->setCullMode(gpu::State::CULL_BACK); // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } pipeline = gpu::Pipeline::create(program, state); } #include <shared/Shapes.h> graphics::MeshPointer DeferredLightingEffect::getPointLightMesh() { if (!_pointLightMesh) { _pointLightMesh = std::make_shared<graphics::Mesh>(); // let's use a icosahedron auto solid = geometry::icosahedron(); solid.fitDimension(1.05f); // scaled to 1.05 meters, it will be scaled by the shader accordingly to the light size int verticesSize = (int) (solid.vertices.size() * 3 * sizeof(float)); float* vertexData = (float*) solid.vertices.data(); _pointLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); int nbIndices = (int) solid.faces.size() * 3; gpu::uint16* indexData = new gpu::uint16[nbIndices]; gpu::uint16* index = indexData; for (auto face : solid.faces) { *(index++) = face[0]; *(index++) = face[1]; *(index++) = face[2]; } _pointLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * nbIndices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); delete[] indexData; std::vector<graphics::Mesh::Part> parts; parts.push_back(graphics::Mesh::Part(0, nbIndices, 0, graphics::Mesh::TRIANGLES)); parts.push_back(graphics::Mesh::Part(0, nbIndices, 0, graphics::Mesh::LINE_STRIP)); // outline version _pointLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); } return _pointLightMesh; } graphics::MeshPointer DeferredLightingEffect::getSpotLightMesh() { if (!_spotLightMesh) { _spotLightMesh = std::make_shared<graphics::Mesh>(); int slices = 16; int rings = 3; int vertices = 2 + rings * slices; int originVertex = vertices - 2; int capVertex = vertices - 1; int verticesSize = vertices * 3 * sizeof(float); int indices = 3 * slices * (1 + 1 + 2 * (rings -1)); int ringFloatOffset = slices * 3; float* vertexData = new float[verticesSize]; float* vertexRing0 = vertexData; float* vertexRing1 = vertexRing0 + ringFloatOffset; float* vertexRing2 = vertexRing1 + ringFloatOffset; for (int i = 0; i < slices; i++) { float theta = TWO_PI * i / slices; auto cosin = glm::vec2(cosf(theta), sinf(theta)); *(vertexRing0++) = cosin.x; *(vertexRing0++) = cosin.y; *(vertexRing0++) = 0.0f; *(vertexRing1++) = cosin.x; *(vertexRing1++) = cosin.y; *(vertexRing1++) = 0.33f; *(vertexRing2++) = cosin.x; *(vertexRing2++) = cosin.y; *(vertexRing2++) = 0.66f; } *(vertexRing2++) = 0.0f; *(vertexRing2++) = 0.0f; *(vertexRing2++) = -1.0f; *(vertexRing2++) = 0.0f; *(vertexRing2++) = 0.0f; *(vertexRing2++) = 1.0f; _spotLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); delete[] vertexData; gpu::uint16* indexData = new gpu::uint16[indices]; gpu::uint16* index = indexData; for (int i = 0; i < slices; i++) { *(index++) = originVertex; int s0 = i; int s1 = ((i + 1) % slices); *(index++) = s0; *(index++) = s1; int s2 = s0 + slices; int s3 = s1 + slices; *(index++) = s1; *(index++) = s0; *(index++) = s2; *(index++) = s1; *(index++) = s2; *(index++) = s3; int s4 = s2 + slices; int s5 = s3 + slices; *(index++) = s3; *(index++) = s2; *(index++) = s4; *(index++) = s3; *(index++) = s4; *(index++) = s5; *(index++) = s5; *(index++) = s4; *(index++) = capVertex; } _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); delete[] indexData; std::vector<graphics::Mesh::Part> parts; parts.push_back(graphics::Mesh::Part(0, indices, 0, graphics::Mesh::TRIANGLES)); parts.push_back(graphics::Mesh::Part(0, indices, 0, graphics::Mesh::LINE_STRIP)); // outline version _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); } return _spotLightMesh; } gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name)); auto colorFormat = gpu::Element::COLOR_SRGBA_32; auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); framebuffer->setRenderBuffer(0, primaryColorTexture); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); framebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); return framebuffer; } void PreparePrimaryFramebuffer::configure(const Config& config) { _resolutionScale = config.resolutionScale; } void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, Output& primaryFramebuffer) { glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale); // Resizing framebuffers instead of re-building them seems to cause issues with threaded // rendering if (!_primaryFramebuffer || _primaryFramebuffer->getSize() != scaledFrameSize) { _primaryFramebuffer = createFramebuffer("deferredPrimary", scaledFrameSize); } primaryFramebuffer = _primaryFramebuffer; // Set viewport for the rest of the scaled passes renderContext->args->_viewport.z = scaledFrameSize.x; renderContext->args->_viewport.w = scaledFrameSize.y; } void PrepareDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { auto args = renderContext->args; auto primaryFramebuffer = inputs.get0(); auto lightingModel = inputs.get1(); if (!_deferredFramebuffer) { _deferredFramebuffer = std::make_shared<DeferredFramebuffer>(); } _deferredFramebuffer->updatePrimaryDepth(primaryFramebuffer->getDepthStencilBuffer()); outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); gpu::doInBatch("PrepareDeferred::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); // Clear deferred auto deferredFbo = _deferredFramebuffer->getDeferredFramebuffer(); batch.setFramebuffer(deferredFbo); // Clear Color, Depth and Stencil for deferred buffer batch.clearFramebuffer( gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_COLOR3 | gpu::Framebuffer::BUFFER_DEPTH | gpu::Framebuffer::BUFFER_STENCIL, vec4(vec3(0), 0), 1.0, 0, true); // For the rest of the rendering, bind the lighting model batch.setUniformBuffer(ru::Buffer::LightModel, lightingModel->getParametersBuffer()); }); // Prepare a fresh Light Frame auto lightStage = renderContext->_scene->getStage<LightStage>(); assert(lightStage); lightStage->_currentFrame.clear(); } void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, const LightingModelPointer& lightingModel, const graphics::HazePointer& haze, const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource, bool renderShadows) { auto args = renderContext->args; auto& batch = (*args->_batch); { // Framebuffer copy operations cannot function as multipass stereo operations. batch.enableStereo(false); auto textureCache = DependencyManager::get<TextureCache>(); auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>(); // binding the first framebuffer auto lightingFBO = deferredFramebuffer->getLightingFramebuffer(); batch.setFramebuffer(lightingFBO); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); // Bind the G-Buffer surfaces batch.setResourceTexture(ru::Texture::DeferredColor, deferredFramebuffer->getDeferredColorTexture()); batch.setResourceTexture(ru::Texture::DeferredNormal, deferredFramebuffer->getDeferredNormalTexture()); batch.setResourceTexture(ru::Texture::DeferredSpecular, deferredFramebuffer->getDeferredSpecularTexture()); batch.setResourceTexture(ru::Texture::DeferredDepth, deferredFramebuffer->getPrimaryDepthTexture()); // FIXME: Different render modes should have different tasks if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled() && ambientOcclusionFramebuffer) { batch.setResourceTexture(ru::Texture::DeferredObscurance, ambientOcclusionFramebuffer->getOcclusionTexture()); } else { // need to assign the white texture if ao is off batch.setResourceTexture(ru::Texture::DeferredObscurance, textureCache->getWhiteTexture()); } // The Deferred Frame Transform buffer batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); // THe lighting model batch.setUniformBuffer(ru::Buffer::LightModel, lightingModel->getParametersBuffer()); // Subsurface scattering specific if (surfaceGeometryFramebuffer) { batch.setResourceTexture(ru::Texture::DeferredLinearZEye, surfaceGeometryFramebuffer->getLinearDepthTexture()); batch.setResourceTexture(ru::Texture::DeferredCurvature, surfaceGeometryFramebuffer->getCurvatureTexture()); batch.setResourceTexture(ru::Texture::DeferredDiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture()); } if (subsurfaceScatteringResource) { batch.setUniformBuffer(ru::Buffer::SsscParams, subsurfaceScatteringResource->getParametersBuffer()); batch.setResourceTexture(ru::Texture::SsscLut, subsurfaceScatteringResource->getScatteringTable()); batch.setResourceTexture(ru::Texture::SsscSpecularBeckmann, subsurfaceScatteringResource->getScatteringSpecular()); } // Global directional light and ambient pass auto lightStage = renderContext->_scene->getStage<LightStage>(); assert(lightStage); assert(lightStage->getNumLights() > 0); auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; // Bind the shadow buffers if (globalShadow) { batch.setResourceTexture(ru::Texture::Shadow, globalShadow->map); } auto program = deferredLightingEffect->_directionalSkyboxLight; LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations; auto keyLight = lightAndShadow.first; graphics::LightPointer ambientLight; if (lightStage && lightStage->_currentFrame._ambientLights.size()) { ambientLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); } bool hasAmbientMap = (ambientLight != nullptr); // Setup the global directional pass pipeline { // Check if keylight casts shadows bool keyLightCastShadows { false }; if (renderShadows && lightStage && lightStage->_currentFrame._sunLights.size()) { graphics::LightPointer keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front()); if (keyLight) { keyLightCastShadows = keyLight->getCastShadows(); } } if (deferredLightingEffect->_shadowMapEnabled && keyLightCastShadows) { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version if (hasAmbientMap) { program = deferredLightingEffect->_directionalSkyboxLightShadow; locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations; } else { program = deferredLightingEffect->_directionalAmbientSphereLightShadow; locations = deferredLightingEffect->_directionalAmbientSphereLightShadowLocations; } } else { // If the keylight has an ambient Map then use the Skybox version of the pass // otherwise use the ambient sphere version if (hasAmbientMap) { program = deferredLightingEffect->_directionalSkyboxLight; locations = deferredLightingEffect->_directionalSkyboxLightLocations; } else { program = deferredLightingEffect->_directionalAmbientSphereLight; locations = deferredLightingEffect->_directionalAmbientSphereLightLocations; } } if (locations->shadowTransform && globalShadow) { batch.setUniformBuffer(ru::Buffer::ShadowParams, globalShadow->getBuffer()); } batch.setPipeline(program); } // Setup the global lighting deferredLightingEffect->setupKeyLightBatch(args, batch);