754 lines · 32.1 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 <GLMHelpers.h>#include <PathUtils.h>#include <ViewFrustum.h> #include <gpu/Batch.h>#include <gpu/Context.h> #include "StencilMaskPass.h"#include "AbstractViewStateInterface.h"#include "GeometryCache.h"#include "TextureCache.h"#include "FramebufferCache.h" #include "deferred_light_vert.h"#include "deferred_light_point_vert.h"#include "deferred_light_spot_vert.h" #include "directional_ambient_light_frag.h"#include "directional_skybox_light_frag.h" #include "directional_ambient_light_shadow_frag.h"#include "directional_skybox_light_shadow_frag.h" #include "local_lights_shading_frag.h"#include "local_lights_drawOutline_frag.h"  using namespace render; struct LightLocations {    int radius{ -1 };    int lightBufferUnit{ -1 };    int ambientBufferUnit { -1 };    int lightIndexBufferUnit { -1 };    int texcoordFrameTransform{ -1 };    int deferredFrameTransformBuffer{ -1 };    int subsurfaceScatteringParametersBuffer{ -1 };    int shadowTransformBuffer{ -1 };}; enum DeferredShader_MapSlot {    DEFERRED_BUFFER_COLOR_UNIT = 0,    DEFERRED_BUFFER_NORMAL_UNIT = 1,    DEFERRED_BUFFER_EMISSIVE_UNIT = 2,    DEFERRED_BUFFER_DEPTH_UNIT = 3,    DEFERRED_BUFFER_OBSCURANCE_UNIT = 4,    SHADOW_MAP_UNIT = 5,    SKYBOX_MAP_UNIT = 6,    DEFERRED_BUFFER_LINEAR_DEPTH_UNIT,    DEFERRED_BUFFER_CURVATURE_UNIT,    DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT,    SCATTERING_LUT_UNIT,    SCATTERING_SPECULAR_UNIT,};enum DeferredShader_BufferSlot {    DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0,    CAMERA_CORRECTION_BUFFER_SLOT,    SCATTERING_PARAMETERS_BUFFER_SLOT,    LIGHTING_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::LIGHTING_MODEL,    LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT,    LIGHT_AMBIENT_SLOT,    LIGHT_INDEX_GPU_SLOT,    LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT,    LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT,    LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, }; static void loadLightProgram(const char* vertSource, const char* fragSource, 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(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);    loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);     loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations);    loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations);     loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations);    loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations);     // Light Stage and clusters    _lightStage = std::make_shared<LightStage>();        // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light    _allocatedLights.push_back(std::make_shared<model::Light>());    model::LightPointer lp = _allocatedLights[0];    lp->setType(model::Light::SUN);    lp->setDirection(glm::vec3(-1.0f));    lp->setColor(glm::vec3(1.0f));    lp->setIntensity(1.0f);    lp->setType(model::Light::SUN);    lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE);     // Add the global light to the light stage (for later shadow rendering)    _globalLights.push_back(_lightStage->addLight(lp));    _lightStage->addShadow(_globalLights[0]);      _backgroundStage = std::make_shared<BackgroundStage>();     auto textureCache = DependencyManager::get<TextureCache>();     {        PROFILE_RANGE(render, "Process Default Skybox");        auto textureCache = DependencyManager::get<TextureCache>();         auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";         _defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);        _defaultSkyboxAmbientTexture = _defaultSkyboxTexture;         _defaultSkybox->setCubemap(_defaultSkyboxTexture);    }      lp->setAmbientIntensity(0.5f);    lp->setAmbientMap(_defaultSkyboxAmbientTexture);    auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();    if (irradianceSH) {        lp->setAmbientSphere((*irradianceSH));    }} void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {    PerformanceTimer perfTimer("DLE->setupBatch()");    model::LightPointer keySunLight;    if (_lightStage && _lightStage->_currentFrame._sunLights.size()) {        keySunLight = _lightStage->getLight(_lightStage->_currentFrame._sunLights.front());    } else {        keySunLight = _allocatedLights[_globalLights.front()];    }     model::LightPointer keyAmbiLight;    if (_lightStage && _lightStage->_currentFrame._ambientLights.size()) {        keyAmbiLight = _lightStage->getLight(_lightStage->_currentFrame._ambientLights.front());    } else {        keyAmbiLight = _allocatedLights[_globalLights.front()];    }     if (lightBufferUnit >= 0) {        batch.setUniformBuffer(lightBufferUnit, keySunLight->getLightSchemaBuffer());    }    if (ambientBufferUnit >= 0) {        batch.setUniformBuffer(ambientBufferUnit, keyAmbiLight->getAmbientSchemaBuffer());    }     if (keyAmbiLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {        batch.setResourceTexture(skyboxCubemapUnit, keyAmbiLight->getAmbientMap());    }} void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {    if (lightBufferUnit >= 0) {        batch.setUniformBuffer(lightBufferUnit, nullptr);    }    if ((ambientBufferUnit >= 0)) {        batch.setUniformBuffer(ambientBufferUnit, nullptr);    }     if ((skyboxCubemapUnit >= 0)) {        batch.setResourceTexture(skyboxCubemapUnit, nullptr);    }} static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* fragSource, LightLocationsPtr& locations) {    auto VS = gpu::Shader::createVertex(std::string(vertSource));    auto PS = gpu::Shader::createPixel(std::string(fragSource));        gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS);     gpu::Shader::BindingSet slotBindings;    slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), DEFERRED_BUFFER_COLOR_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), DEFERRED_BUFFER_NORMAL_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), DEFERRED_BUFFER_EMISSIVE_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DEFERRED_BUFFER_DEPTH_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("obscuranceMap"), DEFERRED_BUFFER_OBSCURANCE_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), SHADOW_MAP_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), SKYBOX_MAP_UNIT));     slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), DEFERRED_BUFFER_CURVATURE_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("diffusedCurvatureMap"), DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), SCATTERING_LUT_UNIT));    slotBindings.insert(gpu::Shader::Binding(std::string("scatteringSpecularBeckmann"), SCATTERING_SPECULAR_UNIT));      slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), LIGHTING_MODEL_BUFFER_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), LIGHT_AMBIENT_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("lightIndexBuffer"), LIGHT_INDEX_GPU_SLOT));      slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));    slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));     gpu::Shader::makeProgram(*program, slotBindings);     locations->radius = program->getUniforms().findLocation("radius");     locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform");     locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer");    locations->ambientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer");    locations->lightIndexBufferUnit = program->getUniformBuffers().findLocation("lightIndexBuffer");    locations->deferredFrameTransformBuffer = program->getUniformBuffers().findLocation("deferredFrameTransformBuffer");    locations->subsurfaceScatteringParametersBuffer = program->getUniformBuffers().findLocation("subsurfaceScatteringParametersBuffer");    locations->shadowTransformBuffer = program->getUniformBuffers().findLocation("shadowTransformBuffer");     return program;} static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) {     gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, 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); } void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) { /*   auto globalLight = _allocatedLights.front();    globalLight->setDirection(light->getDirection());    globalLight->setColor(light->getColor());    globalLight->setIntensity(light->getIntensity());    globalLight->setAmbientIntensity(light->getAmbientIntensity());    globalLight->setAmbientSphere(light->getAmbientSphere());    globalLight->setAmbientMap(light->getAmbientMap());*/} const model::LightPointer& DeferredLightingEffect::getGlobalLight() const {    return _allocatedLights.front();}  #include <shared/Shapes.h> model::MeshPointer DeferredLightingEffect::getPointLightMesh() {    if (!_pointLightMesh) {        _pointLightMesh = std::make_shared<model::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<model::Mesh::Part> parts;        parts.push_back(model::Mesh::Part(0, nbIndices, 0, model::Mesh::TRIANGLES));        parts.push_back(model::Mesh::Part(0, nbIndices, 0, model::Mesh::LINE_STRIP)); // outline version          _pointLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));    }    return _pointLightMesh;} model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {    if (!_spotLightMesh) {        _spotLightMesh = std::make_shared<model::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<model::Mesh::Part> parts;        parts.push_back(model::Mesh::Part(0, indices, 0, model::Mesh::TRIANGLES));        parts.push_back(model::Mesh::Part(0, indices, 0, model::Mesh::LINE_STRIP)); // outline version                 _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));    }    return _spotLightMesh;} void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {     auto framebufferCache = DependencyManager::get<FramebufferCache>();    auto framebufferSize = framebufferCache->getFrameBufferSize();    glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height());     // Resizing framebuffers instead of re-building them seems to cause issues with threaded     // rendering    if (_primaryFramebuffer && _primaryFramebuffer->getSize() != frameSize) {        _primaryFramebuffer.reset();    }     if (!_primaryFramebuffer) {        _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("deferredPrimary"));        auto colorFormat = gpu::Element::COLOR_SRGBA_32;         auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);        auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);          _primaryFramebuffer->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);         _primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);    }         primaryFramebuffer = _primaryFramebuffer;} 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(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, 1, true);         // For the rest of the rendering, bind the lighting model        batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, lightingModel->getParametersBuffer());    });            // Prepare a fresh Light Frame    auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();    deferredLightingEffect->getLightStage()->_currentFrame.clear();}  void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,    const DeferredFrameTransformPointer& frameTransform,    const DeferredFramebufferPointer& deferredFramebuffer,    const LightingModelPointer& lightingModel,    const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer,    const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer,    const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource) {

Lines 1–500 of 754.