189 lines · 7.3 KB · C++
RawDownload
////  RenderShadowTask.cpp//  render-utils/src/////  Created by Zach Pomerantz on 1/7/2016.//  Copyright 2016 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 "RenderShadowTask.h" #include <gpu/Context.h> #include <ViewFrustum.h> #include <render/CullTask.h>#include <render/SortTask.h>#include <render/DrawTask.h> #include "DeferredLightingEffect.h"#include "FramebufferCache.h" #include "model_shadow_vert.h"#include "skin_model_shadow_vert.h" #include "model_shadow_frag.h"#include "skin_model_shadow_frag.h" #include "model_shadow_fade_vert.h"#include "skin_model_shadow_fade_vert.h" #include "model_shadow_fade_frag.h"#include "skin_model_shadow_fade_frag.h" using namespace render; void RenderShadowMap::run(const render::RenderContextPointer& renderContext,                          const render::ShapeBounds& inShapes) {    assert(renderContext->args);    assert(renderContext->args->hasViewFrustum());     auto lightStage = renderContext->_scene->getStage<LightStage>();    assert(lightStage);    LightStage::Index globalLightIndex { 0 };     const auto globalLight = lightStage->getLight(globalLightIndex);    const auto shadow = lightStage->getShadow(globalLightIndex);    if (!shadow) return;     const auto& fbo = shadow->framebuffer;     RenderArgs* args = renderContext->args;    ShapeKey::Builder defaultKeyBuilder;     gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {        args->_batch = &batch;        batch.enableStereo(false);         glm::ivec4 viewport{0, 0, fbo->getWidth(), fbo->getHeight()};        batch.setViewportTransform(viewport);        batch.setStateScissorRect(viewport);         batch.setFramebuffer(fbo);        batch.clearFramebuffer(            gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,            vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true);         batch.setProjectionTransform(shadow->getProjection());        batch.setViewTransform(shadow->getView(), false);         auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);        auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());         std::vector<ShapeKey> skinnedShapeKeys{};         // Iterate through all inShapes and render the unskinned        args->_shapePipeline = shadowPipeline;        batch.setPipeline(shadowPipeline->pipeline);        for (auto items : inShapes) {            if (items.first.isSkinned()) {                skinnedShapeKeys.push_back(items.first);            } else {                renderItems(renderContext, items.second);            }        }         // Reiterate to render the skinned        args->_shapePipeline = shadowSkinnedPipeline;        batch.setPipeline(shadowSkinnedPipeline->pipeline);        for (const auto& key : skinnedShapeKeys) {            renderItems(renderContext, inShapes.at(key));        }         args->_shapePipeline = nullptr;        args->_batch = nullptr;    });} void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {    cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };     // Prepare the ShapePipeline    ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();    {        auto state = std::make_shared<gpu::State>();        state->setCullMode(gpu::State::CULL_BACK);        state->setDepthTest(true, true, gpu::LESS_EQUAL);         auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));        auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));        gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel);        shapePlumber->addPipeline(            ShapeKey::Filter::Builder().withoutSkinned().withoutFade(),            modelProgram, state);         auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));        auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag));        gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel);        shapePlumber->addPipeline(            ShapeKey::Filter::Builder().withSkinned().withoutFade(),            skinProgram, state);         auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert));        auto modelFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag));        gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel);        shapePlumber->addPipeline(            ShapeKey::Filter::Builder().withoutSkinned().withFade(),            modelFadeProgram, state);         auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert));        auto skinFadePixel = gpu::Shader::createPixel(std::string(skin_model_shadow_fade_frag));        gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, skinFadePixel);        shapePlumber->addPipeline(            ShapeKey::Filter::Builder().withSkinned().withFade(),            skinFadeProgram, state);    }     const auto cachedMode = task.addJob<RenderShadowSetup>("ShadowSetup");     // CPU jobs:    // Fetch and cull the items from the scene    auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();    const auto shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowSelection", shadowFilter);    const auto culledShadowSelection = task.addJob<CullSpatialSelection>("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter);     // Sort    const auto sortedPipelines = task.addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);    const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);     // GPU jobs: Render to shadow map    task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);     task.addJob<RenderShadowTeardown>("ShadowTeardown", cachedMode);} void RenderShadowTask::configure(const Config& configuration) {    DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.enabled);    // This is a task, so must still propogate configure() to its Jobs//    Task::configure(configuration);} void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) {    auto lightStage = renderContext->_scene->getStage<LightStage>();    assert(lightStage);    const auto globalShadow = lightStage->getShadow(0);     // Cache old render args    RenderArgs* args = renderContext->args;    output = args->_renderMode;     auto nearClip = args->getViewFrustum().getNearClip();    float nearDepth = -args->_boomOffset.z;    const int SHADOW_FAR_DEPTH = 20;    globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH);     // Set the keylight render args    args->pushViewFrustum(*(globalShadow->getFrustum()));    args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;} void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) {    RenderArgs* args = renderContext->args;     // Reset the render args    args->popViewFrustum();    args->_renderMode = input;};