718 lines · 28.6 KB · C++
RawDownload
////  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.