Brad Davistracing polish30a99619 years agoHistory
829 lines · 36.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 <GLMHelpers.h>#include <PathUtils.h>#include <ViewFrustum.h> #include <gpu/Batch.h>#include <gpu/Context.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_light_frag.h"#include "directional_ambient_light_frag.h"#include "directional_skybox_light_frag.h" #include "directional_light_shadow_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"#include "point_light_frag.h"#include "spot_light_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);static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& program, LightLocationsPtr& locations); const char no_light_frag[] =R"SCRIBE(out vec4 _fragColor; void main(void) {    _fragColor = vec4(1.0, 1.0, 1.0, 1.0);})SCRIBE"; void DeferredLightingEffect::init() {    _directionalLightLocations = std::make_shared<LightLocations>();    _directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();    _directionalSkyboxLightLocations = std::make_shared<LightLocations>();     _directionalLightShadowLocations = std::make_shared<LightLocations>();    _directionalAmbientSphereLightShadowLocations = std::make_shared<LightLocations>();    _directionalSkyboxLightShadowLocations = std::make_shared<LightLocations>();     _localLightLocations = std::make_shared<LightLocations>();    _localLightOutlineLocations = std::make_shared<LightLocations>();    _pointLightLocations = std::make_shared<LightLocations>();    _spotLightLocations = std::make_shared<LightLocations>();     loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);    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_light_shadow_frag, false, _directionalLightShadow, _directionalLightShadowLocations);    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);     loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, false, _pointLightBack, _pointLightLocations);    loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, true, _pointLightFront, _pointLightLocations);    loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, false, _spotLightBack, _spotLightLocations);    loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, true, _spotLightFront, _spotLightLocations);     // 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]); } void DeferredLightingEffect::addLight(const model::LightPointer& light) {    assert(light);    auto lightID = _lightStage->addLight(light);    if (light->getType() == model::Light::POINT) {        _pointLights.push_back(lightID);    } else {        _spotLights.push_back(lightID);    }}  void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color,        float intensity, float falloffRadius) {    addSpotLight(position, radius, color, intensity, falloffRadius);} void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,    float intensity, float falloffRadius, const glm::quat& orientation, float exponent, float cutoff) {        unsigned int lightID = (unsigned int)(_pointLights.size() + _spotLights.size() + _globalLights.size());    if (lightID >= _allocatedLights.size()) {        _allocatedLights.push_back(std::make_shared<model::Light>());    }    model::LightPointer lp = _allocatedLights[lightID];     lp->setPosition(position);    lp->setMaximumRadius(radius);    lp->setColor(color);    lp->setIntensity(intensity);    lp->setFalloffRadius(falloffRadius);     if (exponent == 0.0f && cutoff == PI) {        lp->setType(model::Light::POINT);        _pointLights.push_back(lightID);            } else {        lp->setOrientation(orientation);        lp->setSpotAngle(cutoff);        lp->setSpotExponent(exponent);        lp->setType(model::Light::SPOT);        _spotLights.push_back(lightID);    }} void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {    PerformanceTimer perfTimer("DLE->setupBatch()");    auto keyLight = _allocatedLights[_globalLights.front()];     if (lightBufferUnit >= 0) {        batch.setUniformBuffer(lightBufferUnit, keyLight->getLightSchemaBuffer());    }    if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) {        batch.setUniformBuffer(ambientBufferUnit, keyLight->getAmbientSchemaBuffer());    }     if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {        batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap());    }} void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {    auto keyLight = _allocatedLights[_globalLights.front()];     if (lightBufferUnit >= 0) {        batch.setUniformBuffer(lightBufferUnit, nullptr);    }    if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) {        batch.setUniformBuffer(ambientBufferUnit, nullptr);    }     if (keyLight->getAmbientMap() && (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->getBuffers().findLocation("lightBuffer");    locations->ambientBufferUnit = program->getBuffers().findLocation("lightAmbientBuffer");    locations->lightIndexBufferUnit = program->getBuffers().findLocation("lightIndexBuffer");    locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer");    locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer");    locations->shadowTransformBuffer = program->getBuffers().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) {        state->setStencilTest(true, 0x00, gpu::State::StencilTest(1, 0xFF, gpu::LESS_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));               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        state->setStencilTest(true, 0x00, gpu::State::StencilTest(0, 0x01, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));         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); }  static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) {    gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations);     auto state = std::make_shared<gpu::State>();     // Stencil test all the light passes for objects pixels only, not the background     if (front) {        state->setCullMode(gpu::State::CULL_BACK);        state->setDepthTest(true, false, gpu::LESS_EQUAL);        state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_DECR, gpu::State::STENCIL_OP_KEEP));       //  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);         //state->setColorWriteMask(true, true, true, false);        state->setColorWriteMask(false, false, false, false);    } else {        state->setCullMode(gpu::State::CULL_FRONT);        state->setDepthTest(true, false, gpu::LESS_EQUAL);        state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP));        // additive blending       // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);        // state->setColorWriteMask(true, true, true, false);        state->setColorWriteMask(false, false, false, false);    }    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());} #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 SceneContextPointer& sceneContext, 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::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler)); 

Lines 1–500 of 829.