From 1e7c00c0c8535415a87977c25d9291c5fffb9a82 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 29 Aug 2016 13:40:56 -0700 Subject: [PATCH 1/9] fix Skybox::clear to set _empty --- libraries/model/src/model/Skybox.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index bfbc883978..4901a3c61b 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -26,13 +26,15 @@ Skybox::Skybox() { } void Skybox::setColor(const Color& color) { - _empty = false; _schemaBuffer.edit().color = color; + _empty = false; } void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { - _empty = false; _cubemap = cubemap; + if (cubemap) { + _empty = false; + } } void Skybox::updateSchemaBuffer() const { @@ -52,9 +54,9 @@ void Skybox::updateSchemaBuffer() const { } void Skybox::clear() { - _empty = true; _schemaBuffer.edit().color = vec3(0); - setCubemap(nullptr); + _cubemap = nullptr; + _empty = true; } void Skybox::prepare(gpu::Batch& batch, int textureSlot, int bufferSlot) const { From 1971063b9a954fbeb6398404d72312994bde1e25 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 29 Aug 2016 13:56:39 -0700 Subject: [PATCH 2/9] clean up Procedural::parseShader --- libraries/procedural/src/procedural/Procedural.cpp | 8 +++++--- libraries/procedural/src/procedural/Procedural.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 97bfcf4fe5..1c5ba40891 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -100,7 +100,9 @@ bool Procedural::parseVersion(const QJsonValue& version) { return (_version == 1 || _version == 2); } -bool Procedural::parseUrl(const QUrl& shaderUrl) { +bool Procedural::parseShader(const QUrl& shaderPath) { + auto shaderUrl = ResourceManager::normalizeURL(shaderPath); + if (!shaderUrl.isValid()) { if (!shaderUrl.isEmpty()) { qWarning() << "Invalid shader URL: " << shaderUrl; @@ -168,7 +170,6 @@ void Procedural::parse(const QJsonObject& proceduralData) { auto version = proceduralData[VERSION_KEY]; auto shaderUrl = proceduralData[URL_KEY].toString(); - shaderUrl = ResourceManager::normalizeURL(shaderUrl); auto uniforms = proceduralData[UNIFORMS_KEY].toObject(); auto channels = proceduralData[CHANNELS_KEY].toArray(); @@ -176,7 +177,7 @@ void Procedural::parse(const QJsonObject& proceduralData) { // Run through parsing regardless of validity to clear old cached resources isValid = parseVersion(version) && isValid; - isValid = parseUrl(shaderUrl) && isValid; + isValid = parseShader(shaderUrl) && isValid; isValid = parseUniforms(uniforms) && isValid; isValid = parseTextures(channels) && isValid; @@ -221,6 +222,7 @@ bool Procedural::ready() { _hasStartedFade = true; _isFading = true; } + return true; } diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index c128da0be0..ac71174727 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -107,7 +107,7 @@ private: // This should only be called from the render thread, as it shares data with Procedural::prepare void parse(const QJsonObject&); bool parseVersion(const QJsonValue& version); - bool parseUrl(const QUrl& url); + bool parseShader(const QUrl& shaderPath); bool parseUniforms(const QJsonObject& uniforms); bool parseTextures(const QJsonArray& channels); From f30308b68c81bee240767ba79de8816deee280c4 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 29 Aug 2016 13:57:14 -0700 Subject: [PATCH 3/9] add deeply nested skyboxes --- .../src/EntityTreeRenderer.cpp | 315 ++++++++++++------ .../src/EntityTreeRenderer.h | 77 +++-- 2 files changed, 271 insertions(+), 121 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ece667422c..36563bad85 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -52,7 +52,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf _viewState(viewState), _scriptingServices(scriptingServices), _displayModelBounds(false), - _dontDoPrecisionPicking(false) + _dontDoPrecisionPicking(false), + _layeredZones(this) { REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory) @@ -135,8 +136,11 @@ void EntityTreeRenderer::clear() { _entitiesInScene.clear(); // reset the zone to the default (while we load the next scene) - _bestZone = nullptr; - applyZonePropertiesToScene(_bestZone); + _layeredZones.clear(); + _pendingAmbientTexture = _pendingSkyboxTexture = false; + _ambientTexture.clear(); + _skyboxTexture.clear(); + applyZoneAndHasSkybox(nullptr); OctreeRenderer::clear(); } @@ -192,10 +196,10 @@ void EntityTreeRenderer::update() { // If we haven't already updated and previously attempted to load a texture, // check if the texture loaded and apply it - if (!updated && ( - (_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) || - (_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) { - applyZonePropertiesToScene(_bestZone); + if (!updated && + ((_pendingSkyboxTexture && _skyboxTexture && _skyboxTexture->isLoaded()) || + (_pendingAmbientTexture && _ambientTexture && _ambientTexture->isLoaded()))) { + applySkyboxAndHasAmbient(); } // Even if we're not moving the mouse, if we started clicking on an entity and we have @@ -210,7 +214,7 @@ void EntityTreeRenderer::update() { deleteReleasedModels(); } -bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector* entitiesContainingAvatar) { +bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar) { bool didUpdate = false; float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later QVector foundEntities; @@ -220,12 +224,10 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& _tree->withReadLock([&] { // FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster - std::static_pointer_cast(_tree)->findEntities(avatarPosition, radius, foundEntities); + std::static_pointer_cast(_tree)->findEntities(_avatarPosition, radius, foundEntities); - // Whenever you're in an intersection between zones, we will always choose the smallest zone. - auto oldBestZone = _bestZone; - _bestZone = nullptr; // NOTE: Is this what we want? - _bestZoneVolume = std::numeric_limits::max(); + LayeredZones oldLayeredZones(std::move(_layeredZones)); + _layeredZones.clear(); // create a list of entities that actually contain the avatar's position for (auto& entity : foundEntities) { @@ -239,38 +241,34 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& if (isZone || hasScript) { // now check to see if the point contains our entity, this can be expensive if // the entity has a collision hull - if (entity->contains(avatarPosition)) { + if (entity->contains(_avatarPosition)) { if (entitiesContainingAvatar) { *entitiesContainingAvatar << entity->getEntityItemID(); } // if this entity is a zone and visible, determine if it is the bestZone if (isZone && entity->getVisible()) { - float entityVolumeEstimate = entity->getVolumeEstimate(); - if (entityVolumeEstimate < _bestZoneVolume) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entity); - } else if (entityVolumeEstimate == _bestZoneVolume) { - // in the case of the volume being equal, we will use the - // EntityItemID to deterministically pick one entity over the other - if (!_bestZone) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entity); - } else if (entity->getEntityItemID() < _bestZone->getEntityItemID()) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entity); - } - } + auto zone = std::dynamic_pointer_cast(entity); + _layeredZones.insert(zone); } } } } - if (_bestZone != oldBestZone) { - applyZonePropertiesToScene(_bestZone); - didUpdate = true; + // check if our layered zones have changed + if (_layeredZones.empty()) { + if (oldLayeredZones.empty()) { + return; + } + } else if (!oldLayeredZones.empty()) { + if (_layeredZones.contains(oldLayeredZones)) { + return; + } } + _layeredZones.apply(); + didUpdate = true; }); + return didUpdate; } @@ -286,13 +284,14 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { // if some amount of time has elapsed since we last checked. We check the time // elapsed because zones or entities might have been created "around us" while we've // been stationary - auto movedEnough = glm::distance(avatarPosition, _lastAvatarPosition) > ZONE_CHECK_DISTANCE; + auto movedEnough = glm::distance(avatarPosition, _avatarPosition) > ZONE_CHECK_DISTANCE; auto enoughTimeElapsed = (now - _lastZoneCheck) > ZONE_CHECK_INTERVAL; if (movedEnough || enoughTimeElapsed) { + _avatarPosition = avatarPosition; _lastZoneCheck = now; QVector entitiesContainingAvatar; - didUpdate = findBestZoneAndMaybeContainingEntities(avatarPosition, &entitiesContainingAvatar); + didUpdate = findBestZoneAndMaybeContainingEntities(&entitiesContainingAvatar); // Note: at this point we don't need to worry about the tree being locked, because we only deal with // EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts @@ -318,7 +317,6 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { } } _currentEntitiesInside = entitiesContainingAvatar; - _lastAvatarPosition = avatarPosition; } } return didUpdate; @@ -342,24 +340,20 @@ void EntityTreeRenderer::leaveAllEntities() { void EntityTreeRenderer::forceRecheckEntities() { // make sure our "last avatar position" is something other than our current position, // so that on our next chance, we'll check for enter/leave entity events. - _lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE); + _avatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE); } - -void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr zone) { +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(); - // Skybox and procedural skybox data - auto skybox = std::dynamic_pointer_cast(skyStage->getSkybox()); - // If there is no zone, use the default background if (!zone) { _zoneUserData = QString(); - skybox->clear(); + skyStage->getSkybox()->clear(); _pendingSkyboxTexture = false; _skyboxTexture.clear(); @@ -371,7 +365,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrsetAmbientMap(nullptr); skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT); - return; + return false; } // Set the keylight @@ -394,35 +388,34 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetKeyLightProperties().getAmbientURL().isEmpty()) { _pendingAmbientTexture = false; _ambientTexture.clear(); } else { - _ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE); _pendingAmbientTexture = true; - - if (_ambientTexture && _ambientTexture->isLoaded()) { - _pendingAmbientTexture = false; - - auto texture = _ambientTexture->getGPUTexture(); - if (texture) { - sceneKeyLight->setAmbientSphere(texture->getIrradiance()); - sceneKeyLight->setAmbientMap(texture); - isAmbientTextureSet = true; - } else { - qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << zone->getKeyLightProperties().getAmbientURL(); - } - } + _ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE); } // 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: { + case BACKGROUND_MODE_SKYBOX: skybox->setColor(zone->getSkyboxProperties().getColorVec3()); if (_zoneUserData != zone->getUserData()) { _zoneUserData = zone->getUserData(); - skybox->parse(_zoneUserData); + std::dynamic_pointer_cast(skybox)->parse(_zoneUserData); } if (zone->getSkyboxProperties().getURL().isEmpty()) { skybox->setCubemap(nullptr); @@ -432,29 +425,11 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE); _pendingSkyboxTexture = true; - - if (_skyboxTexture && _skyboxTexture->isLoaded()) { - _pendingSkyboxTexture = false; - - auto texture = _skyboxTexture->getGPUTexture(); - if (texture) { - skybox->setCubemap(texture); - if (!isAmbientTextureSet) { - sceneKeyLight->setAmbientSphere(texture->getIrradiance()); - sceneKeyLight->setAmbientMap(texture); - isAmbientTextureSet = true; - } - } else { - qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << zone->getSkyboxProperties().getURL(); - skybox->setCubemap(nullptr); - } - } else { - skybox->setCubemap(nullptr); - } } + applySkyboxAndHasAmbient(); skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + hasSkybox = true; break; - } case BACKGROUND_MODE_INHERIT: default: @@ -466,7 +441,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrsetBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE); } else { skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE); @@ -474,10 +449,56 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr(); + auto scene = DependencyManager::get(); + auto sceneStage = scene->getStage(); + auto skyStage = scene->getSkyStage(); + auto sceneKeyLight = sceneStage->getKeyLight(); + auto skybox = skyStage->getSkybox(); + + bool isAmbientSet = false; + 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 (_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) { @@ -1046,21 +1067,119 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) { } void EntityTreeRenderer::updateZone(const EntityItemID& id) { - if (!_bestZone) { - // Get in the zone! - auto zone = getTree()->findEntityByEntityItemID(id); - if (zone && zone->contains(_lastAvatarPosition)) { - _currentEntitiesInside << id; - emit enterEntity(id); - if (_entitiesScriptEngine) { - _entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity"); - } - if (zone->getVisible()) { - _bestZone = std::dynamic_pointer_cast(zone); - } - } - } - if (_bestZone && _bestZone->getID() == id) { - applyZonePropertiesToScene(_bestZone); + // Get in the zone! + auto zone = std::dynamic_pointer_cast(getTree()->findEntityByEntityItemID(id)); + if (zone && zone->contains(_avatarPosition)) { + _layeredZones.update(zone); } } + +EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) { + // In a swap: + // > All iterators and references remain valid. The past-the-end iterator is invalidated. + bool isSkyboxLayerValid = (other._skyboxLayer != other.end()); + + swap(other); + _map.swap(other._map); + _skyboxLayer = other._skyboxLayer; + + if (!isSkyboxLayerValid) { + _skyboxLayer = end(); + } +} + +void EntityTreeRenderer::LayeredZones::clear() { + std::set::clear(); + _map.clear(); + _skyboxLayer = end(); +} + +std::pair EntityTreeRenderer::LayeredZones::insert(const LayeredZone& layer) { + iterator it; + bool success; + std::tie(it, success) = std::set::insert(layer); + + if (success) { + _map.emplace(it->id, it); + } + + return { it, success }; +} + +void EntityTreeRenderer::LayeredZones::apply() { + assert(_entityTreeRenderer); + + applyPartial(begin()); +} + +void EntityTreeRenderer::LayeredZones::update(std::shared_ptr zone) { + assert(_entityTreeRenderer); + bool isVisible = zone->isVisible(); + + if (empty() && isVisible) { + // there are no zones: set this one + insert(zone); + apply(); + return; + } 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); + if (it != _map.end()) { + layer = it->second; + // if the volume changed, we need to resort the layer (reinsertion) + // if the visibility changed, we need to erase the layer + if (zoneLayer.volume != layer->volume || !isVisible) { + erase(layer); + _map.erase(it); + layer = end(); + } + } + + // (re)insert this zone's layer if necessary + if (layer == end() && isVisible) { + 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(); + + // empty + if (layer == end()) { + assert(layer == begin()); + _entityTreeRenderer->applyZoneAndHasSkybox(nullptr); + return; + } + + if (layer == begin()) { + hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone); + } + + if (layer != end()) { + while (!hasSkybox && ++layer != end()) { + hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone); + } + } + + _skyboxLayer = layer; +} + +bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) { + return std::equal(other.begin(), other._skyboxLayer, begin()); +} diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 7ca11ccdbb..03aaaf2280 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -95,7 +95,7 @@ public: // For Scene.shouldRenderEntities QList& getEntitiesLastInScene() { return _entityIDsLastInScene; } - std::shared_ptr myAvatarZone() { return _bestZone; } + std::shared_ptr myAvatarZone() { return _layeredZones.getZone(); } signals: void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); @@ -138,9 +138,12 @@ private: void resetEntitiesScriptEngine(); void addEntityToScene(EntityItemPointer entity); - bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector* entitiesContainingAvatar); + bool findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar = nullptr); + + bool applyZoneAndHasSkybox(const std::shared_ptr& zone); + bool layerZoneAndHasSkybox(const std::shared_ptr& zone); + bool applySkyboxAndHasAmbient(); - void applyZonePropertiesToScene(std::shared_ptr zone); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); QList _releasedModels; @@ -156,15 +159,9 @@ private: void leaveAllEntities(); void forceRecheckEntities(); - glm::vec3 _lastAvatarPosition { 0.0f }; + glm::vec3 _avatarPosition { 0.0f }; QVector _currentEntitiesInside; - bool _pendingSkyboxTexture { false }; - NetworkTexturePointer _skyboxTexture; - - bool _pendingAmbientTexture { false }; - NetworkTexturePointer _ambientTexture; - bool _wantScripts; QSharedPointer _entitiesScriptEngine; @@ -185,26 +182,60 @@ private: QMultiMap _waitingOnPreload; - std::shared_ptr _bestZone; - float _bestZoneVolume; + class LayeredZone { + public: + LayeredZone(std::shared_ptr zone, QUuid id, float volume) : zone(zone), id(id), volume(volume) {} + LayeredZone(std::shared_ptr zone) : LayeredZone(zone, zone->getID(), zone->getVolumeEstimate()) {} + bool operator<(const LayeredZone& r) const { return std::tie(volume, id) < std::tie(r.volume, r.id); } + bool operator==(const LayeredZone& r) const { return id == r.id; } + bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); } + + std::shared_ptr zone; + QUuid id; + float volume; + }; + + class LayeredZones : public std::set { + public: + LayeredZones(EntityTreeRenderer* parent) : _entityTreeRenderer(parent) {} + LayeredZones(LayeredZones&& other); + + // avoid accidental misconstruction + LayeredZones() = delete; + LayeredZones(const LayeredZones&) = delete; + LayeredZones& operator=(const LayeredZones&) = delete; + LayeredZones& operator=(LayeredZones&&) = delete; + + void clear(); + std::pair insert(const LayeredZone& layer); + + void apply(); + void update(std::shared_ptr zone); + + bool contains(const LayeredZones& other); + + std::shared_ptr getZone() { return empty() ? nullptr : begin()->zone; } + + private: + void applyPartial(iterator layer); + + std::map _map; + iterator _skyboxLayer{ end() }; + EntityTreeRenderer* _entityTreeRenderer; + }; + + LayeredZones _layeredZones; QString _zoneUserData; + NetworkTexturePointer _skyboxTexture; + NetworkTexturePointer _ambientTexture; + bool _pendingSkyboxTexture { false }; + bool _pendingAmbientTexture { false }; quint64 _lastZoneCheck { 0 }; const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz const float ZONE_CHECK_DISTANCE = 0.001f; - glm::vec3 _previousKeyLightColor; - float _previousKeyLightIntensity; - float _previousKeyLightAmbientIntensity; - glm::vec3 _previousKeyLightDirection; - bool _previousStageSunModelEnabled; - float _previousStageLongitude; - float _previousStageLatitude; - float _previousStageAltitude; - float _previousStageHour; - int _previousStageDay; - QHash _entitiesInScene; // For Scene.shouldRenderEntities QList _entityIDsLastInScene; From abde84b0682877d14516d9494d34f5006207342f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 30 Aug 2016 16:30:53 -0700 Subject: [PATCH 4/9] fix async skybox tex loading --- .../src/EntityTreeRenderer.cpp | 35 +++++++++++-------- .../src/EntityTreeRenderer.h | 6 ++-- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 36563bad85..5047d10206 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -137,9 +137,6 @@ void EntityTreeRenderer::clear() { // reset the zone to the default (while we load the next scene) _layeredZones.clear(); - _pendingAmbientTexture = _pendingSkyboxTexture = false; - _ambientTexture.clear(); - _skyboxTexture.clear(); applyZoneAndHasSkybox(nullptr); OctreeRenderer::clear(); @@ -197,8 +194,8 @@ void EntityTreeRenderer::update() { // If we haven't already updated and previously attempted to load a texture, // check if the texture loaded and apply it if (!updated && - ((_pendingSkyboxTexture && _skyboxTexture && _skyboxTexture->isLoaded()) || - (_pendingAmbientTexture && _ambientTexture && _ambientTexture->isLoaded()))) { + ((_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())) || + (_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())))) { applySkyboxAndHasAmbient(); } @@ -388,12 +385,12 @@ bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptrgetKeyLightProperties().getAmbientURL().isEmpty()) { + _ambientTextureURL = zone->getKeyLightProperties().getAmbientURL(); + if (_ambientTextureURL.isEmpty()) { _pendingAmbientTexture = false; _ambientTexture.clear(); } else { _pendingAmbientTexture = true; - _ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE); } // Set the skybox texture @@ -412,33 +409,36 @@ bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptrgetBackgroundMode()) { 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); } - if (zone->getSkyboxProperties().getURL().isEmpty()) { - skybox->setCubemap(nullptr); + + _skyboxTextureURL = zone->getSkyboxProperties().getURL(); + if (_skyboxTextureURL.isEmpty()) { _pendingSkyboxTexture = false; _skyboxTexture.clear(); } else { - // Update the Texture of the Skybox with the one pointed by this zone - _skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE); _pendingSkyboxTexture = true; } + applySkyboxAndHasAmbient(); skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); - hasSkybox = true; + break; case BACKGROUND_MODE_INHERIT: default: // Clear the skybox to release its textures - _zoneUserData = QString(); skybox->clear(); + _zoneUserData = QString(); - _skyboxTexture.clear(); _pendingSkyboxTexture = false; + _skyboxTexture.clear(); // Let the application background through if (applySkyboxAndHasAmbient()) { @@ -446,6 +446,7 @@ bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptrsetBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE); } + break; } @@ -461,6 +462,9 @@ bool EntityTreeRenderer::applySkyboxAndHasAmbient() { auto skybox = skyStage->getSkybox(); bool isAmbientSet = false; + if (_pendingAmbientTexture && !_ambientTexture) { + _ambientTexture = textureCache->getTexture(_ambientTextureURL, NetworkTexture::CUBE_TEXTURE); + } if (_ambientTexture && _ambientTexture->isLoaded()) { _pendingAmbientTexture = false; @@ -474,6 +478,9 @@ bool EntityTreeRenderer::applySkyboxAndHasAmbient() { } } + if (_pendingSkyboxTexture && !_skyboxTexture) { + _skyboxTexture = textureCache->getTexture(_skyboxTextureURL, NetworkTexture::CUBE_TEXTURE); + } if (_skyboxTexture && _skyboxTexture->isLoaded()) { _pendingSkyboxTexture = false; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 03aaaf2280..5c4bc04510 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -227,10 +227,12 @@ private: LayeredZones _layeredZones; QString _zoneUserData; - NetworkTexturePointer _skyboxTexture; NetworkTexturePointer _ambientTexture; - bool _pendingSkyboxTexture { false }; + NetworkTexturePointer _skyboxTexture; + QString _ambientTextureURL; + QString _skyboxTextureURL; bool _pendingAmbientTexture { false }; + bool _pendingSkyboxTexture { false }; quint64 _lastZoneCheck { 0 }; const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz From bb39cdafda6dd92f1682146692264664e87c5efa Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 30 Aug 2016 16:34:52 -0700 Subject: [PATCH 5/9] fix applyPartial for last zone --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 5047d10206..8dae58c29c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1176,6 +1176,8 @@ void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) { if (layer == begin()) { hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone); + } else { + hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone); } if (layer != end()) { From 0e9ff04c4ca6834afadcfe9f7cce25148876aa40 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 30 Aug 2016 16:58:28 -0700 Subject: [PATCH 6/9] fix layered zone applications --- .../src/EntityTreeRenderer.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 8dae58c29c..d9f1234674 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1167,11 +1167,13 @@ void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) { bool hasSkybox = false; _skyboxLayer = end(); - // empty if (layer == end()) { - assert(layer == begin()); - _entityTreeRenderer->applyZoneAndHasSkybox(nullptr); - return; + if (empty()) { + _entityTreeRenderer->applyZoneAndHasSkybox(nullptr); + return; + } else { // a layer was removed - reapply from beginning + layer = begin(); + } } if (layer == begin()) { @@ -1190,5 +1192,10 @@ void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) { } bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) { - return std::equal(other.begin(), other._skyboxLayer, begin()); + bool result = std::equal(other.begin(), other._skyboxLayer, begin()); + if (result) { + // if valid, set the _skyboxLayer from the other LayeredZones + _skyboxLayer = std::next(begin(), std::distance(other.begin(), other._skyboxLayer)); + } + return result; } From 372c52fea55b01469c8c99a8fa50384a87f71f3e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 30 Aug 2016 14:43:37 -0700 Subject: [PATCH 7/9] restore default ambient skybox --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7b0c2a31c1..35c2ac1dd8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4348,8 +4348,7 @@ namespace render { auto scene = DependencyManager::get()->getStage(); auto sceneKeyLight = scene->getKeyLight(); auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture(); - // set the ambient sphere uniformly - the defaultSkyboxAmbientTexture has peaks that cause flashing when turning - sceneKeyLight->setAmbientSphere(DependencyManager::get()->getWhiteTexture()->getIrradiance()); + sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance()); sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture); // fall through: render defaults skybox } else { From 441005bba02aaa2195b8e9a32e58e08329f0ea5b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 31 Aug 2016 09:47:53 -0700 Subject: [PATCH 8/9] use existing defaults for zoneless keylight --- interface/src/Application.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 35c2ac1dd8..9c44876e6e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4318,18 +4318,14 @@ namespace render { switch (backgroundMode) { case model::SunSkyStage::SKY_DEFAULT: { - static const glm::vec3 DEFAULT_SKYBOX_COLOR{ 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f }; - static const float DEFAULT_SKYBOX_INTENSITY{ 0.2f }; - static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY{ 2.0f }; - static const glm::vec3 DEFAULT_SKYBOX_DIRECTION{ 0.0f, 0.0f, -1.0f }; - auto scene = DependencyManager::get()->getStage(); auto sceneKeyLight = scene->getKeyLight(); + scene->setSunModelEnable(false); - sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR); - sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY); - sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY); - sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION); + 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) } From b9a97712d590169b31af2100b2b8592328778ab3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 31 Aug 2016 15:17:57 -0700 Subject: [PATCH 9/9] Don't show address bar when starting up in a connected state --- interface/src/ConnectionMonitor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/ConnectionMonitor.cpp b/interface/src/ConnectionMonitor.cpp index ec4e277fbd..bab626c0b9 100644 --- a/interface/src/ConnectionMonitor.cpp +++ b/interface/src/ConnectionMonitor.cpp @@ -29,7 +29,9 @@ void ConnectionMonitor::init() { _timer.setSingleShot(true); _timer.setInterval(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS); - _timer.start(); + if (!domainHandler.isConnected()) { + _timer.start(); + } auto dialogsManager = DependencyManager::get(); connect(&_timer, &QTimer::timeout, dialogsManager.data(), &DialogsManager::showAddressBar);