mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 00:56:48 +02:00
add deeply nested skyboxes
This commit is contained in:
parent
1971063b9a
commit
f30308b68c
2 changed files with 271 additions and 121 deletions
|
@ -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<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool didUpdate = false;
|
||||
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
|
||||
QVector<EntityItemPointer> 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<EntityTree>(_tree)->findEntities(avatarPosition, radius, foundEntities);
|
||||
std::static_pointer_cast<EntityTree>(_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<float>::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<ZoneEntityItem>(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<ZoneEntityItem>(entity);
|
||||
} else if (entity->getEntityItemID() < _bestZone->getEntityItemID()) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
}
|
||||
}
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(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<EntityItemID> 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<ZoneEntityItem> zone) {
|
||||
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
|
||||
// Skybox and procedural skybox data
|
||||
auto skybox = std::dynamic_pointer_cast<ProceduralSkybox>(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_ptr<ZoneEntityIt
|
|||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the keylight
|
||||
|
@ -394,35 +388,34 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
}
|
||||
|
||||
// Set the ambient texture
|
||||
bool isAmbientTextureSet = false;
|
||||
if (zone->getKeyLightProperties().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<ZoneEntityItem>& zone) {
|
||||
assert(zone);
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
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<ProceduralSkybox>(skybox)->parse(_zoneUserData);
|
||||
}
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
skybox->setCubemap(nullptr);
|
||||
|
@ -432,29 +425,11 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
_skyboxTexture = textureCache->getTexture(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_ptr<ZoneEntityIt
|
|||
_pendingSkyboxTexture = false;
|
||||
|
||||
// Let the application background through
|
||||
if (isAmbientTextureSet) {
|
||||
if (applySkyboxAndHasAmbient()) {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
|
||||
} else {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
|
||||
|
@ -474,10 +449,56 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
break;
|
||||
}
|
||||
|
||||
if (!isAmbientTextureSet) {
|
||||
return hasSkybox;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::applySkyboxAndHasAmbient() {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
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<ZoneEntityItem>(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bestZone && _bestZone->getID() == id) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
// Get in the zone!
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(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<LayeredZone>::clear();
|
||||
_map.clear();
|
||||
_skyboxLayer = end();
|
||||
}
|
||||
|
||||
std::pair<EntityTreeRenderer::LayeredZones::iterator, bool> EntityTreeRenderer::LayeredZones::insert(const LayeredZone& layer) {
|
||||
iterator it;
|
||||
bool success;
|
||||
std::tie(it, success) = std::set<LayeredZone>::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<ZoneEntityItem> 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());
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
|
||||
std::shared_ptr<ZoneEntityItem> 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<EntityItemID>* entitiesContainingAvatar);
|
||||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool applySkyboxAndHasAmbient();
|
||||
|
||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
|
||||
|
||||
QList<ModelPointer> _releasedModels;
|
||||
|
@ -156,15 +159,9 @@ private:
|
|||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
glm::vec3 _lastAvatarPosition { 0.0f };
|
||||
glm::vec3 _avatarPosition { 0.0f };
|
||||
QVector<EntityItemID> _currentEntitiesInside;
|
||||
|
||||
bool _pendingSkyboxTexture { false };
|
||||
NetworkTexturePointer _skyboxTexture;
|
||||
|
||||
bool _pendingAmbientTexture { false };
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
|
||||
bool _wantScripts;
|
||||
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
||||
|
||||
|
@ -185,26 +182,60 @@ private:
|
|||
|
||||
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> _bestZone;
|
||||
float _bestZoneVolume;
|
||||
class LayeredZone {
|
||||
public:
|
||||
LayeredZone(std::shared_ptr<ZoneEntityItem> zone, QUuid id, float volume) : zone(zone), id(id), volume(volume) {}
|
||||
LayeredZone(std::shared_ptr<ZoneEntityItem> 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<ZoneEntityItem> zone;
|
||||
QUuid id;
|
||||
float volume;
|
||||
};
|
||||
|
||||
class LayeredZones : public std::set<LayeredZone> {
|
||||
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<iterator, bool> insert(const LayeredZone& layer);
|
||||
|
||||
void apply();
|
||||
void update(std::shared_ptr<ZoneEntityItem> zone);
|
||||
|
||||
bool contains(const LayeredZones& other);
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> getZone() { return empty() ? nullptr : begin()->zone; }
|
||||
|
||||
private:
|
||||
void applyPartial(iterator layer);
|
||||
|
||||
std::map<QUuid, iterator> _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<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID> _entityIDsLastInScene;
|
||||
|
|
Loading…
Reference in a new issue