diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f7628ee240..5cc3584593 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4881,12 +4881,6 @@ QRect Application::getDesirableApplicationGeometry() const { return applicationGeometry; } -glm::vec3 Application::getSunDirection() const { - // Sun direction is in fact just the location of the sun relative to the origin - auto skyStage = DependencyManager::get()->getSkyStage(); - return skyStage->getSunLight()->getDirection(); -} - // FIXME, preprocessor guard this check to occur only in DEBUG builds static QThread * activeRenderingThread = nullptr; @@ -4953,90 +4947,6 @@ namespace render { } } -// Background Render Data & rendering functions -class BackgroundRenderData { -public: - typedef render::Payload Payload; - typedef Payload::DataPointer Pointer; - - static render::ItemID _item; // unique WorldBoxRenderData -}; - -render::ItemID BackgroundRenderData::_item = 0; - -namespace render { - template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { - return ItemKey::Builder::background(); - } - - template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) { - return Item::Bound(); - } - - template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) { - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - - // Background rendering decision - auto skyStage = DependencyManager::get()->getSkyStage(); - auto backgroundMode = skyStage->getBackgroundMode(); - - switch (backgroundMode) { - case model::SunSkyStage::SKY_DEFAULT: { - auto scene = DependencyManager::get()->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: { - auto skybox = skyStage->getSkybox(); - if (!skybox->empty()) { - PerformanceTimer perfTimer("skybox"); - skybox->render(batch, args->getViewFrustum()); - break; - } - // fall through: render defaults (if requested) - } - - case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: { - if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) { - auto scene = DependencyManager::get()->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; - } - } - - case model::SunSkyStage::SKY_DEFAULT_TEXTURE: - if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) { - qApp->getDefaultSkybox()->render(batch, args->getViewFrustum()); - } - break; - - // Any other cases require no extra rendering - case model::SunSkyStage::NO_BACKGROUND: - default: - break; - } - } -} - - void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) { // FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering. @@ -5060,15 +4970,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // The pending changes collecting the changes here render::Transaction transaction; - // FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities - // Background rendering decision - if (!render::Item::isValidID(BackgroundRenderData::_item)) { - auto backgroundRenderData = make_shared(); - auto backgroundRenderPayload = make_shared(backgroundRenderData); - BackgroundRenderData::_item = _main3DScene->allocateID(); - transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); - } - // Assuming nothing gets rendered through that if (!selfAvatarOnly) { if (DependencyManager::get()->shouldRenderEntities()) { @@ -5104,12 +5005,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se }); } - // Setup the current Zone Entity lighting - { - auto stage = DependencyManager::get()->getSkyStage(); - DependencyManager::get()->setGlobalLight(stage->getSunLight()); - } - { PerformanceTimer perfTimer("SceneProcessTransaction"); _main3DScene->enqueueTransaction(transaction); diff --git a/interface/src/Application.h b/interface/src/Application.h index e8507c39e8..9cf03f1cef 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -460,8 +460,6 @@ private: void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend = false); - glm::vec3 getSunDirection() const; - void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed); int sendNackPackets(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index e029ca6ada..06227cdcfc 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include "EntityTreeRenderer.h" @@ -141,7 +140,6 @@ void EntityTreeRenderer::clear() { // reset the zone to the default (while we load the next scene) _layeredZones.clear(); - applyZoneAndHasSkybox(nullptr); OctreeRenderer::clear(); } @@ -196,14 +194,6 @@ void EntityTreeRenderer::update() { // Handle enter/leave entity logic bool updated = checkEnterLeaveEntities(); - // If we haven't already updated and previously attempted to load a texture, - // check if the texture loaded and apply it - if (!updated && - ((_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())) || - (_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())))) { - applySkyboxAndHasAmbient(); - } - // Even if we're not moving the mouse, if we started clicking on an entity and we have // not yet released the hold then this is still considered a holdingClickOnEntity event // and we want to simulate this message here as well as in mouse move @@ -371,176 +361,6 @@ bool EntityTreeRenderer::applyLayeredZones() { return true; } - -bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr& zone) { - auto textureCache = DependencyManager::get(); - auto scene = DependencyManager::get(); - auto sceneStage = scene->getStage(); - auto skyStage = scene->getSkyStage(); - auto sceneKeyLight = sceneStage->getKeyLight(); - - // If there is no zone, use the default background - if (!zone) { - _zoneUserData = QString(); - skyStage->getSkybox()->clear(); - - _pendingSkyboxTexture = false; - _skyboxTexture.clear(); - - _pendingAmbientTexture = false; - _ambientTexture.clear(); - - sceneKeyLight->resetAmbientSphere(); - sceneKeyLight->setAmbientMap(nullptr); - - skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT); - return false; - } - - // Set the keylight - sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); - sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity()); - sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); - sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection()); - - // Set the stage - bool isSunModelEnabled = zone->getStageProperties().getSunModelEnabled(); - sceneStage->setSunModelEnable(isSunModelEnabled); - if (isSunModelEnabled) { - sceneStage->setLocation(zone->getStageProperties().getLongitude(), - zone->getStageProperties().getLatitude(), - zone->getStageProperties().getAltitude()); - - auto sceneTime = sceneStage->getTime(); - sceneTime->setHour(zone->getStageProperties().calculateHour()); - sceneTime->setDay(zone->getStageProperties().calculateDay()); - } - - // Set the ambient texture - _ambientTextureURL = zone->getKeyLightProperties().getAmbientURL(); - if (_ambientTextureURL.isEmpty()) { - _pendingAmbientTexture = false; - _ambientTexture.clear(); - } else { - _pendingAmbientTexture = true; - } - - // Set the skybox texture - return layerZoneAndHasSkybox(zone); -} - -bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptr& zone) { - assert(zone); - - auto textureCache = DependencyManager::get(); - auto scene = DependencyManager::get(); - auto skyStage = scene->getSkyStage(); - auto skybox = skyStage->getSkybox(); - - bool hasSkybox = false; - - switch (zone->getBackgroundMode()) { - case BACKGROUND_MODE_SKYBOX: - hasSkybox = true; - - skybox->setColor(zone->getSkyboxProperties().getColorVec3()); - - if (_zoneUserData != zone->getUserData()) { - _zoneUserData = zone->getUserData(); - std::dynamic_pointer_cast(skybox)->parse(_zoneUserData); - } - - _skyboxTextureURL = zone->getSkyboxProperties().getURL(); - if (_skyboxTextureURL.isEmpty()) { - _pendingSkyboxTexture = false; - _skyboxTexture.clear(); - } else { - _pendingSkyboxTexture = true; - } - - applySkyboxAndHasAmbient(); - skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); - - break; - - case BACKGROUND_MODE_INHERIT: - default: - // Clear the skybox to release its textures - skybox->clear(); - _zoneUserData = QString(); - - _pendingSkyboxTexture = false; - _skyboxTexture.clear(); - - // Let the application background through - if (applySkyboxAndHasAmbient()) { - skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE); - } else { - skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE); - } - - break; - } - - return hasSkybox; -} - -bool EntityTreeRenderer::applySkyboxAndHasAmbient() { - auto textureCache = DependencyManager::get(); - auto scene = DependencyManager::get(); - auto sceneStage = scene->getStage(); - auto skyStage = scene->getSkyStage(); - auto sceneKeyLight = sceneStage->getKeyLight(); - auto skybox = skyStage->getSkybox(); - - bool isAmbientSet = false; - if (_pendingAmbientTexture && !_ambientTexture) { - _ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE); - } - if (_ambientTexture && _ambientTexture->isLoaded()) { - _pendingAmbientTexture = false; - - auto texture = _ambientTexture->getGPUTexture(); - if (texture) { - isAmbientSet = true; - sceneKeyLight->setAmbientSphere(texture->getIrradiance()); - sceneKeyLight->setAmbientMap(texture); - } else { - qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL(); - } - } - - if (_pendingSkyboxTexture && - (!_skyboxTexture || (_skyboxTexture->getURL() != _skyboxTextureURL))) { - _skyboxTexture = textureCache->getTexture(_skyboxTextureURL, image::TextureUsage::CUBE_TEXTURE); - } - if (_skyboxTexture && _skyboxTexture->isLoaded()) { - _pendingSkyboxTexture = false; - - auto texture = _skyboxTexture->getGPUTexture(); - if (texture) { - skybox->setCubemap(texture); - if (!isAmbientSet) { - sceneKeyLight->setAmbientSphere(texture->getIrradiance()); - sceneKeyLight->setAmbientMap(texture); - isAmbientSet = true; - } - } else { - qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << _skyboxTexture->getURL(); - skybox->setCubemap(nullptr); - } - } else { - skybox->setCubemap(nullptr); - } - - if (!isAmbientSet) { - sceneKeyLight->resetAmbientSphere(); - sceneKeyLight->setAmbientMap(nullptr); - } - - return isAmbientSet; -} - const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) { const FBXGeometry* result = NULL; @@ -1186,8 +1006,6 @@ std::pair EntityTreeRenderer:: void EntityTreeRenderer::LayeredZones::apply() { assert(_entityTreeRenderer); - - applyPartial(begin()); } void EntityTreeRenderer::LayeredZones::update(std::shared_ptr zone) { @@ -1202,12 +1020,6 @@ void EntityTreeRenderer::LayeredZones::update(std::shared_ptr zo } else { LayeredZone zoneLayer(zone); - // should we update? only if this zone is tighter than the current skybox zone - bool shouldUpdate = false; - if (_skyboxLayer == end() || zoneLayer <= *_skyboxLayer) { - shouldUpdate = true; - } - // find this zone's layer, if it exists iterator layer = end(); auto it = _map.find(zoneLayer.id); @@ -1227,41 +1039,9 @@ void EntityTreeRenderer::LayeredZones::update(std::shared_ptr zo std::tie(layer, std::ignore) = insert(zoneLayer); _map.emplace(layer->id, layer); } - - if (shouldUpdate) { - applyPartial(layer); - } } } -void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) { - bool hasSkybox = false; - _skyboxLayer = end(); - - if (layer == end()) { - if (empty()) { - _entityTreeRenderer->applyZoneAndHasSkybox(nullptr); - return; - } else { // a layer was removed - reapply from beginning - layer = begin(); - } - } - - if (layer == begin()) { - hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone); - } else { - hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone); - } - - if (layer != end()) { - while (!hasSkybox && ++layer != end()) { - hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone); - } - } - - _skyboxLayer = layer; -} - bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) { bool result = std::equal(other.begin(), other._skyboxLayer, begin()); if (result) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index f4717dca51..bf4148212b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -147,9 +147,6 @@ private: void addEntityToScene(EntityItemPointer entity); bool findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar = nullptr); - bool applyZoneAndHasSkybox(const std::shared_ptr& zone); - bool layerZoneAndHasSkybox(const std::shared_ptr& zone); - bool applySkyboxAndHasAmbient(); bool applyLayeredZones(); void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 6556f18776..3f7c0937e2 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -13,14 +13,90 @@ #include +#include + #include #include #include #include +#include #include "EntityTreeRenderer.h" #include "RenderableEntityItem.h" +#include +#include "DeferredLightingEffect.h" + + +class RenderableZoneEntityItemMeta { +public: + RenderableZoneEntityItemMeta(EntityItemPointer entity); + ~RenderableZoneEntityItemMeta(); + + typedef render::Payload Payload; + typedef Payload::DataPointer Pointer; + + EntityItemPointer entity; + + void render(RenderArgs* args); + + void setVisible(bool visible) { _isVisible = visible; } + bool isVisible() const { return _isVisible; } + + render::Item::Bound& editBound() { _needUpdate = true; return _bound; } + + model::LightPointer editSunLight() { _needSunUpdate = true; return _sunLight; } + model::LightPointer editAmbientLight() { _needAmbientUpdate = true; return _ambientLight; } + model::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; } + model::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } + + void setAmbientURL(const QString& ambientUrl); + + void setSkyboxURL(const QString& skyboxUrl); + + void setBackgroundMode(BackgroundMode mode); + void setSkyboxColor(const glm::vec3& color); + void setProceduralUserData(QString userData); + +protected: + render::Item::Bound _bound; + + model::LightPointer _sunLight; + model::LightPointer _ambientLight; + model::SunSkyStagePointer _background; + BackgroundMode _backgroundMode { BACKGROUND_MODE_INHERIT }; + + 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 _needBackgroundUpdate { true }; + bool _isVisible { true }; + + + void updateAmbientMap(); + void updateSkyboxMap(); + + // More attributes used for rendering: + QString _ambientTextureURL; + NetworkTexturePointer _ambientTexture; + bool _pendingAmbientTexture { false }; + bool _validAmbientTexture { false }; + + QString _skyboxTextureURL; + NetworkTexturePointer _skyboxTexture; + bool _pendingSkyboxTexture { false }; + bool _validSkyboxTexture { false }; + + QString _proceduralUserData; +}; + // Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1 // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; @@ -67,8 +143,15 @@ bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& propert void RenderableZoneEntityItem::somethingChangedNotification() { DependencyManager::get()->updateZone(_id); + + // If graphics elements are changed, we need to update the render items + notifyChangedRenderItem(); + + // Poopagate back to parent + ZoneEntityItem::somethingChangedNotification(); } + int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -174,18 +257,158 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { return false; } -class RenderableZoneEntityItemMeta { -public: - RenderableZoneEntityItemMeta(EntityItemPointer entity) : entity(entity){ } - typedef render::Payload Payload; - typedef Payload::DataPointer Pointer; +bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene, + render::Transaction& transaction) { + _myMetaItem = scene->allocateID(); + + auto renderData = std::make_shared(self); + auto renderPayload = std::make_shared(renderData); + updateKeyZoneItemFromEntity((*renderData)); + updateKeySunFromEntity((*renderData)); + updateKeyAmbientFromEntity((*renderData)); + updateKeyBackgroundFromEntity((*renderData)); + + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(getThisPointer(), statusGetters); + renderPayload->addStatusGetters(statusGetters); + + transaction.resetItem(_myMetaItem, renderPayload); + + return true; +} + +void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, + render::Transaction& transaction) { + transaction.removeItem(_myMetaItem); + render::Item::clearID(_myMetaItem); + if (_model) { + _model->removeFromScene(scene, transaction); + } +} + +void RenderableZoneEntityItem::notifyBoundChanged() { + notifyChangedRenderItem(); +} + +void RenderableZoneEntityItem::updateKeySunFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) { + auto sunLight = keyZonePayload.editSunLight(); + sunLight->setType(model::Light::SUN); + + sunLight->setPosition(this->getPosition()); + sunLight->setOrientation(this->getRotation()); + + // Set the keylight + sunLight->setColor(ColorUtils::toVec3(this->getKeyLightProperties().getColor())); + sunLight->setIntensity(this->getKeyLightProperties().getIntensity()); + sunLight->setDirection(this->getKeyLightProperties().getDirection()); +} + +void RenderableZoneEntityItem::updateKeyAmbientFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) { + auto ambientLight = keyZonePayload.editAmbientLight(); + ambientLight->setType(model::Light::AMBIENT); + + ambientLight->setPosition(this->getPosition()); + ambientLight->setOrientation(this->getRotation()); + + + // Set the keylight + ambientLight->setAmbientIntensity(this->getKeyLightProperties().getAmbientIntensity()); + + if (this->getKeyLightProperties().getAmbientURL().isEmpty()) { + keyZonePayload.setAmbientURL(this->getSkyboxProperties().getURL()); + } else { + keyZonePayload.setAmbientURL(this->getKeyLightProperties().getAmbientURL()); + } + +} + +void RenderableZoneEntityItem::updateKeyBackgroundFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) { + auto background = keyZonePayload.editBackground(); + + keyZonePayload.setBackgroundMode(this->getBackgroundMode()); + keyZonePayload.setSkyboxColor(this->getSkyboxProperties().getColorVec3()); + keyZonePayload.setProceduralUserData(this->getUserData()); + keyZonePayload.setSkyboxURL(this->getSkyboxProperties().getURL()); +} + + +void RenderableZoneEntityItem::updateKeyZoneItemFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) { + + keyZonePayload.setVisible(this->getVisible()); + + bool success; + keyZonePayload.editBound() = this->getAABox(success); + if (!success) { + keyZonePayload.editBound() = render::Item::Bound(); + } + + /* TODO: Implement the sun model behavior / Keep this code here for reference, this is how we + { + // Set the stage + bool isSunModelEnabled = this->getStageProperties().getSunModelEnabled(); + sceneStage->setSunModelEnable(isSunModelEnabled); + if (isSunModelEnabled) { + sceneStage->setLocation(this->getStageProperties().getLongitude(), + this->getStageProperties().getLatitude(), + this->getStageProperties().getAltitude()); + + auto sceneTime = sceneStage->getTime(); + sceneTime->setHour(this->getStageProperties().calculateHour()); + sceneTime->setDay(this->getStageProperties().calculateDay()); + } + }*/ +} + + +void RenderableZoneEntityItem::sceneUpdateRenderItemFromEntity(render::Transaction& transaction) { + if (!render::Item::isValidID(_myMetaItem)) { + return; + } + + bool sunChanged = _keyLightPropertiesChanged; + bool backgroundChanged = _backgroundPropertiesChanged; + bool stageChanged = _stagePropertiesChanged; + bool skyboxChanged = _skyboxPropertiesChanged; + + transaction.updateItem(_myMetaItem, [=](RenderableZoneEntityItemMeta& data) { + + updateKeyZoneItemFromEntity(data); + + if (sunChanged) { + updateKeySunFromEntity(data); + } + + if (sunChanged || skyboxChanged) { + updateKeyAmbientFromEntity(data); + } + if (backgroundChanged || skyboxChanged) { + updateKeyBackgroundFromEntity(data); + } + }); +} + +void RenderableZoneEntityItem::notifyChangedRenderItem() { + if (!render::Item::isValidID(_myMetaItem)) { + return; + } + + render::Transaction transaction; + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + sceneUpdateRenderItemFromEntity(transaction); + scene->enqueueTransaction(transaction); +} + + + + + + + - EntityItemPointer entity; -}; namespace render { template <> const ItemKey payloadGetKey(const RenderableZoneEntityItemMeta::Pointer& payload) { - return ItemKey::Builder::opaqueShape(); + return ItemKey::Builder().withTypeMeta().build(); } template <> const Item::Bound payloadGetBound(const RenderableZoneEntityItemMeta::Pointer& payload) { @@ -200,51 +423,199 @@ namespace render { return render::Item::Bound(); } template <> void payloadRender(const RenderableZoneEntityItemMeta::Pointer& payload, RenderArgs* args) { - if (args) { - if (payload && payload->entity) { - payload->entity->render(args); + payload->render(args); + } +} + +RenderableZoneEntityItemMeta::RenderableZoneEntityItemMeta(EntityItemPointer entity) : + entity(entity), + _sunLight(std::make_shared()), + _ambientLight(std::make_shared()), + _background(std::make_shared()) +{ + _background->setSkybox(std::make_shared()); +} + + +RenderableZoneEntityItemMeta::~RenderableZoneEntityItemMeta() { + if (_stage) { + if (!LightStage::isIndexInvalid(_sunIndex)) { + _stage->removeLight(_sunIndex); + } + if (!LightStage::isIndexInvalid(_ambientIndex)) { + _stage->removeLight(_ambientIndex); + + } + } + + if (_backgroundStage) { + if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) { + _backgroundStage->removeBackground(_backgroundIndex); + } + } +} + +void RenderableZoneEntityItemMeta::setAmbientURL(const QString& ambientUrl) { + // nothing change if nothing change + if (_ambientTextureURL == ambientUrl) { + return; + } + _ambientTextureURL = ambientUrl; + + if (_ambientTextureURL.isEmpty()) { + _validAmbientTexture = false; + _pendingAmbientTexture = false; + _ambientTexture.clear(); + + _ambientLight->setAmbientMap(nullptr); + _ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY); + } else { + _pendingAmbientTexture = true; + auto textureCache = DependencyManager::get(); + _ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE); + + // keep whatever is assigned on the ambient map/sphere until texture is loaded + } +} + +void RenderableZoneEntityItemMeta::updateAmbientMap() { + if (_pendingAmbientTexture) { + if (_ambientTexture && _ambientTexture->isLoaded()) { + _pendingAmbientTexture = false; + + auto texture = _ambientTexture->getGPUTexture(); + if (texture) { + if (texture->getIrradiance()) { + _ambientLight->setAmbientSphere(*texture->getIrradiance()); + } else { + _ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY); + } + editAmbientLight()->setAmbientMap(texture); + _validAmbientTexture = true; + } else { + qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL(); } } } } -bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene, - render::Transaction& transaction) { - _myMetaItem = scene->allocateID(); - auto renderData = std::make_shared(self); - auto renderPayload = std::make_shared(renderData); - - render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(getThisPointer(), statusGetters); - renderPayload->addStatusGetters(statusGetters); - - transaction.resetItem(_myMetaItem, renderPayload); - return true; -} - -void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, - render::Transaction& transaction) { - transaction.removeItem(_myMetaItem); - render::Item::clearID(_myMetaItem); - if (_model) { - _model->removeFromScene(scene, transaction); - } -} - - -void RenderableZoneEntityItem::notifyBoundChanged() { - if (!render::Item::isValidID(_myMetaItem)) { +void RenderableZoneEntityItemMeta::setSkyboxURL(const QString& skyboxUrl) { + // nothing change if nothing change + if (_skyboxTextureURL == skyboxUrl) { return; } - render::Transaction transaction; - render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - if (scene) { - transaction.updateItem(_myMetaItem, [](RenderableZoneEntityItemMeta& data) { - }); + _skyboxTextureURL = skyboxUrl; - scene->enqueueTransaction(transaction); + if (_skyboxTextureURL.isEmpty()) { + _validSkyboxTexture = false; + _pendingSkyboxTexture = false; + _skyboxTexture.clear(); + + editSkybox()->setCubemap(nullptr); } else { - qCWarning(entitiesrenderer) << "RenderableZoneEntityItem::notifyBoundChanged(), Unexpected null scene, possibly during application shutdown"; + _pendingSkyboxTexture = true; + auto textureCache = DependencyManager::get(); + _skyboxTexture = textureCache->getTexture(_skyboxTextureURL, image::TextureUsage::CUBE_TEXTURE); + } +} + +void RenderableZoneEntityItemMeta::updateSkyboxMap() { + if (_pendingSkyboxTexture) { + if (_skyboxTexture && _skyboxTexture->isLoaded()) { + _pendingSkyboxTexture = false; + + auto texture = _skyboxTexture->getGPUTexture(); + if (texture) { + editSkybox()->setCubemap(texture); + _validSkyboxTexture = true; + } else { + qCDebug(entitiesrenderer) << "Failed to load Skybox texture:" << _skyboxTexture->getURL(); + } + } + } +} + +void RenderableZoneEntityItemMeta::setBackgroundMode(BackgroundMode mode) { + _backgroundMode = mode; +} + +void RenderableZoneEntityItemMeta::setSkyboxColor(const glm::vec3& color) { + editSkybox()->setColor(color); +} + +void RenderableZoneEntityItemMeta::setProceduralUserData(QString userData) { + if (_proceduralUserData != userData) { + _proceduralUserData = userData; + std::dynamic_pointer_cast(editSkybox())->parse(_proceduralUserData); + } +} + + + +void RenderableZoneEntityItemMeta::render(RenderArgs* args) { + if (!_stage) { + _stage = DependencyManager::get()->getLightStage(); + } + + if (!_backgroundStage) { + _backgroundStage = DependencyManager::get()->getBackgroundStage(); + } + + { // Sun + // Need an update ? + if (_needSunUpdate) { + // Do we need to allocate the light in the stage ? + if (LightStage::isIndexInvalid(_sunIndex)) { + _sunIndex = _stage->addLight(_sunLight); + } else { + _stage->updateLightArrayBuffer(_sunIndex); + } + _needSunUpdate = false; + } + } + + { // Ambient + updateAmbientMap(); + + // Need an update ? + if (_needAmbientUpdate) { + // Do we need to allocate the light in the stage ? + if (LightStage::isIndexInvalid(_ambientIndex)) { + _ambientIndex = _stage->addLight(_ambientLight); + } else { + _stage->updateLightArrayBuffer(_ambientIndex); + } + _needAmbientUpdate = false; + } + } + + { // 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 + // THe directional key light for sure + _stage->_currentFrame.pushSunLight(_sunIndex); + + // The ambient light only if it has a valid texture to render with + if (_validAmbientTexture || _validSkyboxTexture) { + _stage->_currentFrame.pushAmbientLight(_ambientIndex); + } + + // The background only if the mode is not inherit + if (_backgroundMode != BACKGROUND_MODE_INHERIT) { + _backgroundStage->_currentFrame.pushBackground(_backgroundIndex); + } } } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 7241e34ce8..d0c7f64fbb 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -16,6 +16,9 @@ #include class NetworkGeometry; +class KeyLightPayload; + +class RenderableZoneEntityItemMeta; class RenderableZoneEntityItem : public ZoneEntityItem { public: @@ -42,7 +45,7 @@ public: virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override; render::ItemID getRenderItemID() const { return _myMetaItem; } - + private: virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); } @@ -52,10 +55,18 @@ private: template void changeProperties(Lambda functor); - + + void notifyChangedRenderItem(); + void sceneUpdateRenderItemFromEntity(render::Transaction& transaction); + void updateKeyZoneItemFromEntity(RenderableZoneEntityItemMeta& keyZonePayload); + + void updateKeySunFromEntity(RenderableZoneEntityItemMeta& keyZonePayload); + void updateKeyAmbientFromEntity(RenderableZoneEntityItemMeta& keyZonePayload); + void updateKeyBackgroundFromEntity(RenderableZoneEntityItemMeta& keyZonePayload); + ModelPointer _model; bool _needsInitialSimulation; - + render::ItemID _myMetaItem{ render::Item::INVALID_ITEM_ID }; }; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 1d73902e8d..074437b6b2 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -71,22 +71,6 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - bool somethingChangedInKeyLight = _keyLightProperties.setProperties(properties); - - bool somethingChangedInStage = _stageProperties.setProperties(properties); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); - - bool somethingChangedInSkybox = _skyboxProperties.setProperties(properties); - - somethingChanged = somethingChanged || somethingChangedInKeyLight || somethingChangedInStage || somethingChangedInSkybox; - if (somethingChanged) { bool wantDebug = false; if (wantDebug) { @@ -101,6 +85,30 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } +bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setSubClassProperties(properties); // set the properties in our base class + + + _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties); + + _stagePropertiesChanged = _stageProperties.setProperties(properties); + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode); + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); + + _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); + + somethingChanged = somethingChanged || _keyLightPropertiesChanged || _stagePropertiesChanged || _skyboxPropertiesChanged; + + + return somethingChanged; +} + int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -109,14 +117,14 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, const unsigned char* dataAt = data; int bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, somethingChanged); - + propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); + somethingChanged = somethingChanged || _keyLightPropertiesChanged; bytesRead += bytesFromKeylight; dataAt += bytesFromKeylight; int bytesFromStage = _stageProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, somethingChanged); - + propertyFlags, overwriteLocalData, _stagePropertiesChanged); + somethingChanged = somethingChanged || _stagePropertiesChanged; bytesRead += bytesFromStage; dataAt += bytesFromStage; @@ -125,7 +133,8 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode); int bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, somethingChanged); + propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); + somethingChanged = somethingChanged || _skyboxPropertiesChanged; bytesRead += bytesFromSkybox; dataAt += bytesFromSkybox; @@ -185,6 +194,16 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); } +void ZoneEntityItem::somethingChangedNotification() { + EntityItem::somethingChangedNotification(); + withWriteLock([&] { + _keyLightPropertiesChanged = false; + _backgroundPropertiesChanged = false; + _stagePropertiesChanged = false; + _skyboxPropertiesChanged = false; + }); +} + void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index c868da0954..bcb690f60e 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -29,10 +29,16 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + /// Override this in your derived class if you'd like to be informed when something about the state of the entity + /// has changed. This will be called with properties change or when new data is loaded from a stream + /// Overriding this function to capture the information that a keylight / Ambient / skybox properties has changed + virtual void somethingChangedNotification() override; + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, @@ -64,7 +70,7 @@ public: const KeyLightPropertyGroup& getKeyLightProperties() const { return _keyLightProperties; } - void setBackgroundMode(BackgroundMode value) { _backgroundMode = value; } + void setBackgroundMode(BackgroundMode value) { _backgroundMode = value; _backgroundPropertiesChanged = true; } BackgroundMode getBackgroundMode() const { return _backgroundMode; } const SkyboxPropertyGroup& getSkyboxProperties() const { return _skyboxProperties; } @@ -106,6 +112,14 @@ protected: bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED }; QString _filterURL { DEFAULT_FILTER_URL }; + // Dirty flags turn true when either keylight properties is changing values. + // This gets back to false in the somethingChangedNotification() call + // Which is called after a setProperties() or a readEntitySubClassFromBUfferCall on the entity. + bool _keyLightPropertiesChanged { false }; + bool _backgroundPropertiesChanged { false }; + bool _skyboxPropertiesChanged { false }; + bool _stagePropertiesChanged { false }; + static bool _drawZoneBoundaries; static bool _zonesArePickable; }; diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 11b13606b8..19da084f84 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -145,7 +145,7 @@ void Light::setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset) { _ambientSchemaBuffer.edit().ambientSphere.assignPreset(preset); } -void Light::setAmbientMap(gpu::TexturePointer ambientMap) { +void Light::setAmbientMap(const gpu::TexturePointer& ambientMap) { _ambientMap = ambientMap; if (ambientMap) { setAmbientMapNumMips(_ambientMap->getNumMips()); diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 947474bbfd..4c82eb5d77 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -68,7 +68,8 @@ public: enum Type { - SUN = 0, + AMBIENT = 0, + SUN, POINT, SPOT, @@ -112,7 +113,6 @@ public: void setIntensity(float intensity); bool isRanged() const { return (getType() == POINT) || (getType() == SPOT); } - bool hasAmbient() const { return (getType() == SUN); } // FalloffRradius is the physical radius of the light sphere through which energy shines, // expressed in meters. It is used only to calculate the falloff curve of the light. @@ -143,7 +143,7 @@ public: const gpu::SphericalHarmonics& getAmbientSphere() const { return _ambientSchemaBuffer->ambientSphere; } void setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset); - void setAmbientMap(gpu::TexturePointer ambientMap); + void setAmbientMap(const gpu::TexturePointer& ambientMap); gpu::TexturePointer getAmbientMap() const { return _ambientMap; } void setAmbientMapNumMips(uint16_t numMips); diff --git a/libraries/model/src/model/Skybox.h b/libraries/model/src/model/Skybox.h index d7d95fbe9e..90896fd8c6 100755 --- a/libraries/model/src/model/Skybox.h +++ b/libraries/model/src/model/Skybox.h @@ -25,6 +25,8 @@ typedef glm::vec3 Color; class Skybox { public: + typedef gpu::BufferView UniformBufferView; + Skybox(); Skybox& operator= (const Skybox& skybox); virtual ~Skybox() {}; @@ -43,6 +45,8 @@ public: static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox); + const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } + protected: static const int SKYBOX_SKYMAP_SLOT { 0 }; static const int SKYBOX_CONSTANTS_SLOT { 0 }; diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 454097233a..c359924e0d 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -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() diff --git a/libraries/render-utils/src/BackgroundStage.cpp b/libraries/render-utils/src/BackgroundStage.cpp new file mode 100644 index 0000000000..1a85a70863 --- /dev/null +++ b/libraries/render-utils/src/BackgroundStage.cpp @@ -0,0 +1,141 @@ +// +// 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 + +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()->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()->getDefaultSkybox(); + } + + /* auto backgroundMode = skyStage->getBackgroundMode(); + + switch (backgroundMode) { + case model::SunSkyStage::SKY_DEFAULT: { + auto scene = DependencyManager::get()->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()->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; + } + } + */ + +} \ No newline at end of file diff --git a/libraries/render-utils/src/BackgroundStage.h b/libraries/render-utils/src/BackgroundStage.h new file mode 100644 index 0000000000..1dd1651c98 --- /dev/null +++ b/libraries/render-utils/src/BackgroundStage.h @@ -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 +#include +#include +#include + +#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; + using BackgroundMap = std::unordered_map; + + using BackgroundIndices = std::vector; + + + 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; + + +class DrawBackgroundStage { +public: + using Inputs = LightingModelPointer; + using JobModel = render::Job::ModelI; + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); + +protected: +}; + +#endif diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 93a176f4f3..e1042912aa 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -141,79 +141,69 @@ void DeferredLightingEffect::init() { _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); + _backgroundStage = std::make_shared(); + + auto textureCache = DependencyManager::get(); + + { + PROFILE_RANGE(render, "Process Default Skybox"); + auto textureCache = DependencyManager::get(); + + auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx"; + + _defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl); + _defaultSkyboxAmbientTexture = _defaultSkyboxTexture; + + _defaultSkybox->setCubemap(_defaultSkyboxTexture); } -} -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::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); - } + 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()"); - auto keyLight = _allocatedLights[_globalLights.front()]; + 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, keyLight->getLightSchemaBuffer()); + batch.setUniformBuffer(lightBufferUnit, keySunLight->getLightSchemaBuffer()); } - if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) { - batch.setUniformBuffer(ambientBufferUnit, keyLight->getAmbientSchemaBuffer()); + if (ambientBufferUnit >= 0) { + batch.setUniformBuffer(ambientBufferUnit, keyAmbiLight->getAmbientSchemaBuffer()); } - if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { - batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap()); + if (keyAmbiLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { + batch.setResourceTexture(skyboxCubemapUnit, keyAmbiLight->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)) { + if ((ambientBufferUnit >= 0)) { batch.setUniformBuffer(ambientBufferUnit, nullptr); } - if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { + if ((skyboxCubemapUnit >= 0)) { batch.setResourceTexture(skyboxCubemapUnit, nullptr); } } @@ -334,15 +324,20 @@ static void loadLightVolumeProgram(const char* vertSource, const char* fragSourc } void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) { - auto globalLight = _allocatedLights.front(); + /* 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()); + globalLight->setAmbientMap(light->getAmbientMap());*/ } +const model::LightPointer& DeferredLightingEffect::getGlobalLight() const { + return _allocatedLights.front(); +} + + #include model::MeshPointer DeferredLightingEffect::getPointLightMesh() { @@ -772,16 +767,6 @@ void RenderDeferredCleanup::run(const render::RenderContextPointer& renderContex batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr); } - - auto deferredLightingEffect = DependencyManager::get(); - - // End of the Lighting pass - if (!deferredLightingEffect->_pointLights.empty()) { - deferredLightingEffect->_pointLights.clear(); - } - if (!deferredLightingEffect->_spotLights.empty()) { - deferredLightingEffect->_spotLights.clear(); - } } RenderDeferred::RenderDeferred() { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index dcf0c84622..2f4f9901c3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -20,6 +20,8 @@ #include "model/Light.h" #include "model/Geometry.h" +#include + #include #include "DeferredFrameTransform.h" @@ -28,11 +30,13 @@ #include "LightStage.h" #include "LightClusters.h" +#include "BackgroundStage.h" #include "SurfaceGeometryPass.h" #include "SubsurfaceScattering.h" #include "AmbientOcclusionEffect.h" + class RenderArgs; struct LightLocations; using LightLocationsPtr = std::shared_ptr; @@ -43,34 +47,30 @@ class DeferredLightingEffect : public Dependency { public: void init(); - - void addLight(const model::LightPointer& light); - - /// Adds a point light to render for the current frame. - void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f), - float intensity = 0.5f, float falloffRadius = 0.01f); - - /// Adds a spot light to render for the current frame. - void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), - float intensity = 0.5f, float falloffRadius = 0.01f, - const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); - + void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit); void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit); // update global lighting void setGlobalLight(const model::LightPointer& light); + const model::LightPointer& getGlobalLight() const; - const LightStagePointer getLightStage() { return _lightStage; } + 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 }; @@ -113,8 +113,10 @@ private: Lights _allocatedLights; std::vector _globalLights; - std::vector _pointLights; - std::vector _spotLights; + + model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() }; + gpu::TexturePointer _defaultSkyboxTexture; + gpu::TexturePointer _defaultSkyboxAmbientTexture; friend class LightClusteringPass; friend class RenderDeferredSetup; diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index a670c9f620..dbdf7129ef 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -81,3 +81,71 @@ void LightPayload::render(RenderArgs* args) { } } + +namespace render { + template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload) { + ItemKey::Builder builder; + builder.withTypeLight(); + if (!payload || !payload->isVisible()) { + builder.withInvisible(); + } + return builder.build(); + } + + template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload) { + if (payload) { + return payload->editBound(); + } + return render::Item::Bound(); + } + template <> void payloadRender(const KeyLightPayload::Pointer& payload, RenderArgs* args) { + if (args) { + if (payload) { + payload->render(args); + } + } + } +} + +KeyLightPayload::KeyLightPayload() : +_light(std::make_shared()) +{ +} + + +KeyLightPayload::~KeyLightPayload() { + if (!LightStage::isIndexInvalid(_index)) { + if (_stage) { + _stage->removeLight(_index); + } + } +} + +void KeyLightPayload::render(RenderArgs* args) { + if (!_stage) { + _stage = DependencyManager::get()->getLightStage(); + } + // Do we need to allocate the light in the stage ? + if (LightStage::isIndexInvalid(_index)) { + _index = _stage->addLight(_light); + _needUpdate = false; + } + // Need an update ? + if (_needUpdate) { + _stage->updateLightArrayBuffer(_index); + _needUpdate = false; + } + + if (isVisible()) { + // FInally, push the light visible in the frame + _stage->_currentFrame.pushLight(_index, _light->getType()); + +#ifdef WANT_DEBUG + Q_ASSERT(args->_batch); + gpu::Batch& batch = *args->_batch; + batch.setModelTransform(getTransformToCenter()); + DependencyManager::get()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); +#endif + } +} + diff --git a/libraries/render-utils/src/LightPayload.h b/libraries/render-utils/src/LightPayload.h index 6b5fe83f07..0cf8f8e2de 100644 --- a/libraries/render-utils/src/LightPayload.h +++ b/libraries/render-utils/src/LightPayload.h @@ -15,6 +15,7 @@ #include #include #include "LightStage.h" +#include "TextureCache.h" class LightPayload { public: @@ -46,4 +47,41 @@ namespace render { template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args); } +class KeyLightPayload { +public: + using Payload = render::Payload; + using Pointer = Payload::DataPointer; + + KeyLightPayload(); + ~KeyLightPayload(); + void render(RenderArgs* args); + + model::LightPointer editLight() { _needUpdate = true; return _light; } + render::Item::Bound& editBound() { _needUpdate = true; return _bound; } + + void setVisible(bool visible) { _isVisible = visible; } + bool isVisible() const { return _isVisible; } + + + // More attributes used for rendering: + NetworkTexturePointer _ambientTexture; + QString _ambientTextureURL; + bool _pendingAmbientTexture { false }; + bool _validAmbientTextureURL { false }; + +protected: + model::LightPointer _light; + render::Item::Bound _bound; + LightStagePointer _stage; + LightStage::Index _index { LightStage::INVALID_INDEX }; + bool _needUpdate { true }; + bool _isVisible { true }; +}; + +namespace render { + template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload); + template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload); + template <> void payloadRender(const KeyLightPayload::Pointer& payload, RenderArgs* args); +} + #endif \ No newline at end of file diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index c2293ac099..edbdff28fd 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -77,7 +77,6 @@ public: }; using Descs = std::vector; - Index findLight(const LightPointer& light) const; Index addLight(const LightPointer& light); @@ -118,19 +117,25 @@ public: public: Frame() {} - void clear() { _pointLights.clear(); _spotLights.clear(); } + void clear() { _pointLights.clear(); _spotLights.clear(); _sunLights.clear(); _ambientLights.clear(); } void pushLight(LightStage::Index index, model::Light::Type type) { switch (type) { case model::Light::POINT: { pushPointLight(index); break; } case model::Light::SPOT: { pushSpotLight(index); break; } + case model::Light::SUN: { pushSunLight(index); break; } + case model::Light::AMBIENT: { pushAmbientLight(index); break; } default: { break; } } } void pushPointLight(LightStage::Index index) { _pointLights.emplace_back(index); } void pushSpotLight(LightStage::Index index) { _spotLights.emplace_back(index); } - + void pushSunLight(LightStage::Index index) { _sunLights.emplace_back(index); } + void pushAmbientLight(LightStage::Index index) { _ambientLights.emplace_back(index); } + LightStage::LightIndices _pointLights; LightStage::LightIndices _spotLights; + LightStage::LightIndices _sunLights; + LightStage::LightIndices _ambientLights; }; Frame _currentFrame; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 313b176f19..b844da8bbe 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -75,7 +75,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto deferredFrameTransform = task.addJob("DeferredFrameTransform"); const auto lightingModel = task.addJob("LightingModel"); - // GPU jobs: Start preparing the primary, deferred and lighting buffer const auto primaryFramebuffer = task.addJob("PreparePrimaryBuffer"); @@ -124,6 +123,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. task.addJob("DrawLight", lights); + // Filter zones from the general metas bucket + const auto zones = task.addJob("ZoneRenderer", metas); + // Light Clustering // Create the cluster grid of lights, cpu job for now const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying(); @@ -136,11 +138,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("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", backgroundInputs); - - + // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job + task.addJob("DrawBackgroundDeferred", lightingModel); + // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); @@ -162,7 +162,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawOpaqueBounds", opaques); task.addJob("DrawTransparentBounds", transparents); - task.addJob("ZoneRenderer", opaques); + task.addJob("DrawLightBounds", lights); + task.addJob("DrawZones", zones); } // Overlays @@ -202,6 +203,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); task.addJob("DrawStatus", opaques, DrawStatus(statusIconMap)); } + + task.addJob("DrawZoneStack", deferredFrameTransform); } diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 2cabe58c33..3b4870fd3f 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -10,18 +10,199 @@ // #include "ZoneRenderer.h" + +#include +#include + #include #include +#include "DeferredLightingEffect.h" + +#include "zone_drawKeyLight_frag.h" +#include "zone_drawAmbient_frag.h" +#include "zone_drawSkybox_frag.h" + + using namespace render; +class SetupZones { +public: + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + SetupZones() {} + + void run(const RenderContextPointer& context, const Inputs& inputs); + +protected: +}; + const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" }; void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& ouput) { - + // Filter out the sorted list of zones const auto zoneItems = task.addJob("FilterZones", input, ZONES_SELECTION.c_str()); - // just draw them... - task.addJob("DrawZones", zoneItems); + // just setup the current zone env + task.addJob("SetupZones", zoneItems); + + ouput = zoneItems; } +void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) { + + auto backgroundStage = DependencyManager::get()->getBackgroundStage(); + backgroundStage->_currentFrame.clear(); + + // call render in the correct order first... + render::renderItems(context, inputs); + +} + +const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { + if (!_keyLightPipeline) { + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); + auto ps = gpu::Shader::createPixel(std::string(zone_drawKeyLight_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ZONE_KEYLIGHT_BUFFER)); + + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + _keyLightPipeline = gpu::Pipeline::create(program, state); + } + return _keyLightPipeline; +} + +const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() { + if (!_ambientPipeline) { + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); + auto ps = gpu::Shader::createPixel(std::string(zone_drawAmbient_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), ZONE_AMBIENT_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), ZONE_AMBIENT_MAP)); + + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + _ambientPipeline = gpu::Pipeline::create(program, state); + } + return _ambientPipeline; +} +const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() { + if (!_backgroundPipeline) { + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); + auto ps = gpu::Shader::createPixel(std::string(zone_drawSkybox_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), ZONE_SKYBOX_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("skyboxBuffer"), ZONE_SKYBOX_BUFFER)); + + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + _backgroundPipeline = gpu::Pipeline::create(program, state); + } + return _backgroundPipeline; +} + +void DebugZoneLighting::run(const render::RenderContextPointer& context, const Inputs& inputs) { + RenderArgs* args = context->args; + + auto deferredTransform = inputs; + + auto lightStage = DependencyManager::get()->getLightStage(); + std::vector keyLightStack; + if (lightStage && lightStage->_currentFrame._sunLights.size()) { + for (auto index : lightStage->_currentFrame._sunLights) { + keyLightStack.push_back(lightStage->getLight(index)); + } + } + keyLightStack.push_back(DependencyManager::get()->getGlobalLight()); + + std::vector ambientLightStack; + if (lightStage && lightStage->_currentFrame._ambientLights.size()) { + for (auto index : lightStage->_currentFrame._ambientLights) { + ambientLightStack.push_back(lightStage->getLight(index)); + } + } + ambientLightStack.push_back(DependencyManager::get()->getGlobalLight()); + + + auto backgroundStage = DependencyManager::get()->getBackgroundStage(); + std::vector skyboxStack; + if (backgroundStage && backgroundStage->_currentFrame._backgrounds.size()) { + for (auto index : backgroundStage->_currentFrame._backgrounds) { + auto background = backgroundStage->getBackground(index); + if (background) { + skyboxStack.push_back(background->getSkybox()); + } + } + } + skyboxStack.push_back(DependencyManager::get()->getDefaultSkybox()); + + + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + + batch.setViewportTransform(args->_viewport); + auto viewFrustum = args->getViewFrustum(); + batch.setProjectionTransform(viewFrustum.getProjection()); + batch.resetViewTransform(); + + Transform model; + + batch.setUniformBuffer(ZONE_DEFERRED_TRANSFORM_BUFFER, deferredTransform->getFrameTransformBuffer()); + + batch.setPipeline(getKeyLightPipeline()); + auto numKeys = keyLightStack.size(); + for (int i = numKeys - 1; i >= 0; i--) { + model.setTranslation(glm::vec3(-4.0, -3.0 + (i * 1.0), -10.0 - (i * 3.0))); + batch.setModelTransform(model); + if (keyLightStack[i]) { + batch.setUniformBuffer(ZONE_KEYLIGHT_BUFFER, keyLightStack[i]->getLightSchemaBuffer()); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } + } + + batch.setPipeline(getAmbientPipeline()); + auto numAmbients = ambientLightStack.size(); + for (int i = numAmbients - 1; i >= 0; i--) { + model.setTranslation(glm::vec3(0.0, -3.0 + (i * 1.0), -10.0 - (i * 3.0))); + batch.setModelTransform(model); + if (ambientLightStack[i]) { + batch.setUniformBuffer(ZONE_AMBIENT_BUFFER, ambientLightStack[i]->getAmbientSchemaBuffer()); + if (ambientLightStack[i]->getAmbientMap()) { + batch.setResourceTexture(ZONE_AMBIENT_MAP, ambientLightStack[i]->getAmbientMap()); + } + batch.draw(gpu::TRIANGLE_STRIP, 4); + } + } + + batch.setPipeline(getBackgroundPipeline()); + auto numBackgrounds = skyboxStack.size(); + for (int i = numBackgrounds - 1; i >= 0; i--) { + model.setTranslation(glm::vec3(4.0, -3.0 + (i * 1.0), -10.0 - (i * 3.0))); + batch.setModelTransform(model); + if (skyboxStack[i]) { + batch.setResourceTexture(ZONE_SKYBOX_MAP, skyboxStack[i]->getCubemap()); + batch.setUniformBuffer(ZONE_SKYBOX_BUFFER, skyboxStack[i]->getSchemaBuffer()); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } + } + }); +} diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h index 1218608400..5737499270 100644 --- a/libraries/render-utils/src/ZoneRenderer.h +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -14,12 +14,15 @@ #include "render/Engine.h" +#include "DeferredFrameTransform.h" + class ZoneRendererConfig : public render::Task::Config { Q_OBJECT Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) public: - ZoneRendererConfig() : render::Task::Config(false) {} + ZoneRendererConfig() : render::Task::Config( + ) {} int maxDrawn { -1 }; @@ -49,4 +52,40 @@ protected: int _maxDrawn; // initialized by Config }; +class DebugZoneLighting { +public: + class Config : public render::JobConfig { + public: + Config(bool enabled = false) : JobConfig(enabled) {} + }; + + using Inputs = DeferredFrameTransformPointer; + using JobModel = render::Job::ModelI; + + DebugZoneLighting() {} + + void configure(const Config& configuration) {} + void run(const render::RenderContextPointer& context, const Inputs& inputs); + +protected: + + enum Slots { + ZONE_DEFERRED_TRANSFORM_BUFFER = 0, + ZONE_KEYLIGHT_BUFFER, + ZONE_AMBIENT_BUFFER, + ZONE_AMBIENT_MAP, + ZONE_SKYBOX_BUFFER, + ZONE_SKYBOX_MAP, + }; + + gpu::PipelinePointer _keyLightPipeline; + gpu::PipelinePointer _ambientPipeline; + gpu::PipelinePointer _backgroundPipeline; + + const gpu::PipelinePointer& getKeyLightPipeline(); + const gpu::PipelinePointer& getAmbientPipeline(); + const gpu::PipelinePointer& getBackgroundPipeline(); +}; + + #endif \ No newline at end of file diff --git a/libraries/render-utils/src/zone_draw.slh b/libraries/render-utils/src/zone_draw.slh new file mode 100644 index 0000000000..2cc8fc99f2 --- /dev/null +++ b/libraries/render-utils/src/zone_draw.slh @@ -0,0 +1,37 @@ + +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 5/17/17. +// Copyright 2017 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 DeferredTransform.slh@> +<$declareDeferredFrameTransform()$> + +<@func evalGlobeWidget()@> + const float SCOPE_RADIUS = 1.0; + const float SCOPE_RADIUS2 = SCOPE_RADIUS * SCOPE_RADIUS; + const float EDGE_HALFWIDTH = 0.025; + const float EDGE_HALFWIDTH2 = EDGE_HALFWIDTH * EDGE_HALFWIDTH; + const float OUT_RADIUS = SCOPE_RADIUS + EDGE_HALFWIDTH; + + vec2 sphereUV = (varTexCoord0.xy * 2.0 - vec2(1.0)) * OUT_RADIUS; + float sphereR2 = dot(sphereUV.xy, sphereUV.xy); + if (sphereR2 > OUT_RADIUS * OUT_RADIUS) { + discard; + } + float sphereR = sqrt(sphereR2); + + float edgeFalloff = (SCOPE_RADIUS - sphereR) / (EDGE_HALFWIDTH); + float edgeFalloff2 = min(1.0, edgeFalloff * edgeFalloff); + + vec4 base = vec4(0.0, 0.0, 0.0, 1.0 - edgeFalloff2); + if (sphereR2 > SCOPE_RADIUS2) { + _fragColor = base; + return; + } +<@endfunc@> + diff --git a/libraries/render-utils/src/zone_drawAmbient.slf b/libraries/render-utils/src/zone_drawAmbient.slf new file mode 100644 index 0000000000..f104e5be44 --- /dev/null +++ b/libraries/render-utils/src/zone_drawAmbient.slf @@ -0,0 +1,54 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 5/16/17. +// Copyright 2017 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 zone_draw.slh@> + +<@include model/Light.slh@> + +<@include LightingModel.slh@> +<$declareLightAmbientBuffer()$> + +<@include LightAmbient.slh@> + +<$declareLightingAmbient(_SCRIBE_NULL, 1, _SCRIBE_NULL, _SCRIBE_NULL)$> + +in vec2 varTexCoord0; +out vec4 _fragColor; + +void main(void) { + + <$evalGlobeWidget()$> + + vec3 spherePos = normalize(vec3(sphereUV, sqrt(1.0 - sphereR2))); + + + vec3 fragNormal = vec3(getViewInverse() * vec4(spherePos, 0.0)); + + + LightAmbient lightAmbient = getLightAmbient(); + + + float roughness = 0.1; + float levels = getLightAmbientMapNumMips(lightAmbient); + float lod = min(((roughness)* levels), levels); + vec3 ambientMap = evalSkyboxLight(fragNormal, lod).xyz; + vec3 ambientSH = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz; + + // vec3 ambient = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz; + // _fragColor = vec4( 0.5 * (fragNormal + vec3(1.0)), 1.0); + + vec3 color = (sphereUV.x > 0 ? ambientMap : ambientSH); + + color = color * 1.0 - base.w + base.xyz * base.w; + const float INV_GAMMA_22 = 1.0 / 2.2; + _fragColor = vec4(pow(color, vec3(INV_GAMMA_22)), 1.0); +} + + diff --git a/libraries/render-utils/src/zone_drawKeyLight.slf b/libraries/render-utils/src/zone_drawKeyLight.slf new file mode 100644 index 0000000000..e96239b6dc --- /dev/null +++ b/libraries/render-utils/src/zone_drawKeyLight.slf @@ -0,0 +1,57 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 5/16/17. +// Copyright 2017 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 zone_draw.slh@> + +<@include model/Light.slh@> + +<@include LightingModel.slh@> +<$declareLightBuffer()$> + +<@include LightDirectional.slh@> +<$declareLightingDirectional(_SCRIBE_NULL)$> + +in vec2 varTexCoord0; +out vec4 _fragColor; + +void main(void) { + + <$evalGlobeWidget()$> + + Light light = getLight(); + vec3 lightDirection = normalize(getLightDirection(light)); + vec3 lightIrradiance = getLightIrradiance(light); + vec3 color = vec3(0.0); + + const float INOUT_RATIO = 0.4; + const float SUN_THRESHOLD = 0.99; + + vec3 outSpherePos = normalize(vec3(sphereUV, -sqrt(1.0 - sphereR2))); + vec3 outNormal = vec3(getViewInverse() * vec4(outSpherePos, 0.0)); + + float val = step(SUN_THRESHOLD, dot(-lightDirection, outNormal)); + + color = lightIrradiance * vec3(val); + + if (sphereR2 < INOUT_RATIO * INOUT_RATIO * SCOPE_RADIUS2) { + vec2 inSphereUV = sphereUV / INOUT_RATIO; + vec3 inSpherePos = normalize(vec3(inSphereUV, sqrt(1.0 - dot(inSphereUV.xy, inSphereUV.xy)))); + vec3 inNormal = vec3(getViewInverse() * vec4(inSpherePos, 0.0)); + + vec3 marbleColor = max(lightIrradiance * vec3(dot(-lightDirection, inNormal)), vec3(0.01)); + color += marbleColor; + } + + color = color * 1.0 - base.w + base.xyz * base.w; + const float INV_GAMMA_22 = 1.0 / 2.2; + _fragColor = vec4(pow(color, vec3(INV_GAMMA_22)), 1.0); +} + + diff --git a/libraries/render-utils/src/zone_drawSkybox.slf b/libraries/render-utils/src/zone_drawSkybox.slf new file mode 100644 index 0000000000..fd6976365e --- /dev/null +++ b/libraries/render-utils/src/zone_drawSkybox.slf @@ -0,0 +1,48 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 5/16/17. +// Copyright 2017 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 zone_draw.slh@> + +uniform samplerCube skyboxMap; + +struct Skybox { + vec4 color; +}; + +uniform skyboxBuffer { + Skybox skybox; +}; + +in vec2 varTexCoord0; +out vec4 _fragColor; + +void main(void) { + <$evalGlobeWidget()$> + + vec3 spherePos = normalize(vec3(sphereUV, -sqrt(1.0 - sphereR2))); + + vec3 direction = vec3(getViewInverse() * vec4(spherePos, 0.0)); + + vec3 color = skybox.color.rgb; + + // blend is only set if there is a cubemap + if (skybox.color.a > 0.0) { + color = texture(skyboxMap, direction).rgb; + if (skybox.color.a < 1.0) { + color *= skybox.color.rgb; + } + } + + color = color * 1.0 - base.w + base.xyz * base.w; + const float INV_GAMMA_22 = 1.0 / 2.2; + _fragColor = vec4(pow(color, vec3(INV_GAMMA_22)), 1.0); +} + + diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index bc62117e70..af65f3dbf7 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -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) diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 229a2d1c3b..ff4621a87a 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -64,6 +64,7 @@ Column { "Point:LightingModel:enablePointLight", "Spot:LightingModel:enableSpotLight", "Light Contour:LightingModel:showLightContour", + "Zone Stack:DrawZoneStack:enabled", "Shadow:RenderShadowTask:enabled" ] CheckBox { @@ -162,13 +163,9 @@ Column { } } + Row { Column { - id: metas - CheckBox { - text: "Metas" - checked: Render.getConfig("DrawMetaBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked } - } + CheckBox { text: "Opaques" checked: Render.getConfig("DrawOpaqueBounds")["enabled"] @@ -189,11 +186,24 @@ Column { checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"] onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked } } + } + Column { + CheckBox { + text: "Metas" + checked: Render.getConfig("DrawMetaBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked } + } + CheckBox { + text: "Lights" + checked: Render.getConfig("DrawLightBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawLightBounds")["enabled"] = checked; } + } CheckBox { text: "Zones" checked: Render.getConfig("DrawZones")["enabled"] onCheckedChanged: { Render.getConfig("ZoneRenderer")["enabled"] = checked; Render.getConfig("DrawZones")["enabled"] = checked; } } } + } } diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 1e85dd3ea8..553e7c06e7 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -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()