Introucing the BackgroundStage to manage the background / skybox in one place

This commit is contained in:
samcake 2017-05-09 17:10:05 -07:00
parent c36035d3eb
commit bc41be7ec1
9 changed files with 289 additions and 12 deletions

View file

@ -26,6 +26,8 @@
#include <LightPayload.h>
#include "DeferredLightingEffect.h"
#include <procedural\ProceduralSkybox.h>
class RenderableZoneEntityItemMeta {
public:
RenderableZoneEntityItemMeta(EntityItemPointer entity);
@ -45,7 +47,8 @@ public:
model::LightPointer editSunLight() { _needSunUpdate = true; return _sunLight; }
model::LightPointer editAmbientLight() { _needAmbientUpdate = true; return _ambientLight; }
model::SkyboxPointer editSkybox() { _needSkyboxUpdate = true; return _skybox; }
model::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; }
model::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); }
void setAmbientURL(const QString& ambientUrl);
@ -56,16 +59,19 @@ protected:
model::LightPointer _sunLight;
model::LightPointer _ambientLight;
model::SkyboxPointer _skybox;
model::SunSkyStagePointer _background;
LightStagePointer _stage;
LightStage::Index _sunIndex { LightStage::INVALID_INDEX };
LightStage::Index _ambientIndex { LightStage::INVALID_INDEX };
BackgroundStagePointer _backgroundStage;
BackgroundStage::Index _backgroundIndex { BackgroundStage::INVALID_INDEX };
bool _needUpdate { true };
bool _needSunUpdate { true };
bool _needAmbientUpdate { true };
bool _needSkyboxUpdate { true };
bool _needBackgroundUpdate { true };
bool _isVisible { true };
@ -356,7 +362,7 @@ void RenderableZoneEntityItem::updateKeyAmbientFromEntity(RenderableZoneEntityIt
}
void RenderableZoneEntityItem::updateKeyBackgroundFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) {
auto skybox = keyZonePayload.editSkybox();
auto background = keyZonePayload.editBackground();
this->getBackgroundMode();
@ -436,8 +442,10 @@ RenderableZoneEntityItemMeta::RenderableZoneEntityItemMeta(EntityItemPointer ent
entity(entity),
_sunLight(std::make_shared<model::Light>()),
_ambientLight(std::make_shared<model::Light>()),
_skybox(std::make_shared<model::Skybox>())
{}
_background(std::make_shared<model::SunSkyStage>())
{
_background->setSkybox(std::make_shared<ProceduralSkybox>());
}
RenderableZoneEntityItemMeta::~RenderableZoneEntityItemMeta() {
@ -450,6 +458,12 @@ RenderableZoneEntityItemMeta::~RenderableZoneEntityItemMeta() {
}
}
if (_backgroundStage) {
if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) {
_backgroundStage->removeBackground(_backgroundIndex);
}
}
}
void RenderableZoneEntityItemMeta::setAmbientURL(const QString& ambientUrl) {
@ -541,6 +555,10 @@ void RenderableZoneEntityItemMeta::render(RenderArgs* args) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
}
if (!_backgroundStage) {
_backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
}
{ // Sun
// Need an update ?
if (_needSunUpdate) {
@ -572,11 +590,20 @@ void RenderableZoneEntityItemMeta::render(RenderArgs* args) {
{ // Skybox
updateSkyboxMap();
if (_needBackgroundUpdate) {
if (BackgroundStage::isIndexInvalid(_backgroundIndex)) {
_backgroundIndex = _backgroundStage->addBackground(_background);
} else {
}
_needBackgroundUpdate = false;
}
}
if (isVisible()) {
// FInally, push the light visible in the frame
_stage->_currentFrame.pushSunLight(_sunIndex);
_stage->_currentFrame.pushAmbientLight(_ambientIndex);
_backgroundStage->_currentFrame.pushBackground(_backgroundIndex);
}
}

View file

@ -3,7 +3,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model render)
# pull in the resources.qrc file
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
link_hifi_libraries(shared ktx gpu model model-networking render animation fbx entities image)
link_hifi_libraries(shared ktx gpu model model-networking render animation fbx entities image procedural)
if (NOT ANDROID)
target_nsight()

View file

@ -0,0 +1,142 @@
//
// BackgroundStage.cpp
//
// Created by Sam Gateau on 5/9/2017.
// Copyright 2015 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 "BackgroundStage.h"
#include "DeferredLightingEffect.h"
#include <gpu/Context.h>
BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const {
auto found = _backgroundMap.find(background);
if (found != _backgroundMap.end()) {
return INVALID_INDEX;
} else {
return (*found).second;
}
}
BackgroundStage::Index BackgroundStage::addBackground(const BackgroundPointer& background) {
auto found = _backgroundMap.find(background);
if (found == _backgroundMap.end()) {
auto backgroundId = _backgrounds.newElement(background);
// Avoid failing to allocate a background, just pass
if (backgroundId != INVALID_INDEX) {
// Insert the background and its index in the reverse map
_backgroundMap.insert(BackgroundMap::value_type(background, backgroundId));
}
return backgroundId;
} else {
return (*found).second;
}
}
BackgroundStage::BackgroundPointer BackgroundStage::removeBackground(Index index) {
BackgroundPointer removed = _backgrounds.freeElement(index);
if (removed) {
_backgroundMap.erase(removed);
}
return removed;
}
void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
const auto& lightingModel = inputs;
if (!lightingModel->isBackgroundEnabled()) {
return;
}
// Background rendering decision
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
model::SunSkyStagePointer background;
model::SkyboxPointer skybox;
if (backgroundStage->_currentFrame._backgrounds.size()) {
auto backgroundId = backgroundStage->_currentFrame._backgrounds.front();
auto background = backgroundStage->getBackground(backgroundId);
if (background) {
skybox = background->getSkybox();
}
} else {
skybox = DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox();
}
/* auto backgroundMode = skyStage->getBackgroundMode();
switch (backgroundMode) {
case model::SunSkyStage::SKY_DEFAULT: {
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
auto sceneKeyLight = scene->getKeyLight();
scene->setSunModelEnable(false);
sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR));
sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY);
sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY);
sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION);
// fall through: render a skybox (if available), or the defaults (if requested)
}
case model::SunSkyStage::SKY_BOX: {*/
if (skybox && !skybox->empty()) {
PerformanceTimer perfTimer("skybox");
auto args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.enableSkybox(true);
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
skybox->render(batch, args->getViewFrustum());
});
args->_batch = nullptr;
gpu::Batch& batch = *args->_batch;
// break;
}
// fall through: render defaults (if requested)
// }
/*
case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: {
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
auto sceneKeyLight = scene->getKeyLight();
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
if (defaultSkyboxAmbientTexture) {
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
} else {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
"Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step");
}
// fall through: render defaults skybox
} else {
break;
}
}
backgroundStage->_currentFrame.clear();
}

View file

@ -0,0 +1,80 @@
//
// BackgroundStage.h
// Created by Sam Gateau on 5/9/2017.
// Copyright 2015 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
//
#ifndef hifi_render_utils_BackgroundStage_h
#define hifi_render_utils_BackgroundStage_h
#include <model/Stage.h>
#include <set>
#include <unordered_map>
#include <render/IndexedContainer.h>
#include "LightingModel.h"
// Background stage to set up background-related rendering tasks
class BackgroundStage {
public:
using Index = render::indexed_container::Index;
static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using BackgroundPointer = model::SunSkyStagePointer;
using Backgrounds = render::indexed_container::IndexedPointerVector<model::SunSkyStage>;
using BackgroundMap = std::unordered_map<BackgroundPointer, Index>;
using BackgroundIndices = std::vector<Index>;
Index findBackground(const BackgroundPointer& background) const;
Index addBackground(const BackgroundPointer& background);
BackgroundPointer removeBackground(Index index);
bool checkBackgroundId(Index index) const { return _backgrounds.checkIndex(index); }
Index getNumBackgrounds() const { return _backgrounds.getNumElements(); }
Index getNumFreeBackgrounds() const { return _backgrounds.getNumFreeIndices(); }
Index getNumAllocatedBackgrounds() const { return _backgrounds.getNumAllocatedIndices(); }
BackgroundPointer getBackground(Index backgroundId) const {
return _backgrounds.get(backgroundId);
}
Backgrounds _backgrounds;
BackgroundMap _backgroundMap;
class Frame {
public:
Frame() {}
void clear() { _backgrounds.clear(); }
void pushBackground(BackgroundStage::Index index) { _backgrounds.emplace_back(index); }
BackgroundStage::BackgroundIndices _backgrounds;
};
Frame _currentFrame;
};
using BackgroundStagePointer = std::shared_ptr<BackgroundStage>;
class DrawBackgroundStage {
public:
using Inputs = LightingModelPointer;
using JobModel = render::Job::ModelI<DrawBackgroundStage, Inputs>;
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
protected:
};
#endif

View file

@ -141,6 +141,19 @@ void DeferredLightingEffect::init() {
_globalLights.push_back(_lightStage->addLight(lp));
_lightStage->addShadow(_globalLights[0]);
_backgroundStage = std::make_shared<BackgroundStage>();
auto textureCache = DependencyManager::get<TextureCache>();
QString skyboxUrl { PathUtils::resourcesPath() + "images/Default-Sky-9-cubemap.jpg" };
QString skyboxAmbientUrl { PathUtils::resourcesPath() + "images/Default-Sky-9-ambient.jpg" };
_defaultSkyboxTexture = textureCache->getImageTexture(skyboxUrl, image::TextureUsage::CUBE_TEXTURE, { { "generateIrradiance", false } });
_defaultSkyboxAmbientTexture = textureCache->getImageTexture(skyboxAmbientUrl, image::TextureUsage::CUBE_TEXTURE, { { "generateIrradiance", true } });
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
}
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {

View file

@ -20,6 +20,8 @@
#include "model/Light.h"
#include "model/Geometry.h"
#include <procedural/ProceduralSkybox.h>
#include <render/CullTask.h>
#include "DeferredFrameTransform.h"
@ -28,11 +30,13 @@
#include "LightStage.h"
#include "LightClusters.h"
#include "BackgroundEffect.h"
#include "SurfaceGeometryPass.h"
#include "SubsurfaceScattering.h"
#include "AmbientOcclusionEffect.h"
class RenderArgs;
struct LightLocations;
using LightLocationsPtr = std::shared_ptr<LightLocations>;
@ -51,15 +55,21 @@ public:
void setGlobalLight(const model::LightPointer& light);
const LightStagePointer& getLightStage() { return _lightStage; }
const BackgroundStagePointer& getBackgroundStage() { return _backgroundStage; }
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; }
model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
private:
DeferredLightingEffect() = default;
LightStagePointer _lightStage;
BackgroundStagePointer _backgroundStage;
bool _shadowMapEnabled{ false };
bool _ambientOcclusionEnabled{ false };
@ -103,6 +113,10 @@ private:
Lights _allocatedLights;
std::vector<int> _globalLights;
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture;
friend class LightClusteringPass;
friend class RenderDeferredSetup;
friend class RenderDeferredLocals;

View file

@ -139,9 +139,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<RenderDeferred>("RenderDeferred", deferredLightingInputs);
// Use Stencil and draw background in Lighting buffer to complete filling in the opaque
const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying();
task.addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", backgroundInputs);
//const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying();
//task.addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", backgroundInputs);
task.addJob<DrawBackgroundStage>("DrawBackgroundDeferred", lightingModel);
// Render transparent objects forward in LightingBuffer
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying();

View file

@ -13,7 +13,7 @@ if (WIN32)
setup_hifi_plugin(OpenGL Script Qml Widgets)
link_hifi_libraries(shared gl networking controllers ui
plugins display-plugins ui-plugins input-plugins script-engine
render-utils model gpu gpu-gl render model-networking fbx ktx image)
render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
include_hifi_library_headers(octree)

View file

@ -10,7 +10,7 @@ setup_hifi_project(Quick Gui OpenGL)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries
link_hifi_libraries(shared octree ktx gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics image)
link_hifi_libraries(shared octree ktx gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics image procedural)
package_libraries_for_deployment()