mirror of
https://github.com/overte-org/overte.git
synced 2025-04-26 02:36:45 +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),
|
_viewState(viewState),
|
||||||
_scriptingServices(scriptingServices),
|
_scriptingServices(scriptingServices),
|
||||||
_displayModelBounds(false),
|
_displayModelBounds(false),
|
||||||
_dontDoPrecisionPicking(false)
|
_dontDoPrecisionPicking(false),
|
||||||
|
_layeredZones(this)
|
||||||
{
|
{
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||||
|
@ -135,8 +136,11 @@ void EntityTreeRenderer::clear() {
|
||||||
_entitiesInScene.clear();
|
_entitiesInScene.clear();
|
||||||
|
|
||||||
// reset the zone to the default (while we load the next scene)
|
// reset the zone to the default (while we load the next scene)
|
||||||
_bestZone = nullptr;
|
_layeredZones.clear();
|
||||||
applyZonePropertiesToScene(_bestZone);
|
_pendingAmbientTexture = _pendingSkyboxTexture = false;
|
||||||
|
_ambientTexture.clear();
|
||||||
|
_skyboxTexture.clear();
|
||||||
|
applyZoneAndHasSkybox(nullptr);
|
||||||
|
|
||||||
OctreeRenderer::clear();
|
OctreeRenderer::clear();
|
||||||
}
|
}
|
||||||
|
@ -192,10 +196,10 @@ void EntityTreeRenderer::update() {
|
||||||
|
|
||||||
// If we haven't already updated and previously attempted to load a texture,
|
// If we haven't already updated and previously attempted to load a texture,
|
||||||
// check if the texture loaded and apply it
|
// check if the texture loaded and apply it
|
||||||
if (!updated && (
|
if (!updated &&
|
||||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) ||
|
((_pendingSkyboxTexture && _skyboxTexture && _skyboxTexture->isLoaded()) ||
|
||||||
(_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) {
|
(_pendingAmbientTexture && _ambientTexture && _ambientTexture->isLoaded()))) {
|
||||||
applyZonePropertiesToScene(_bestZone);
|
applySkyboxAndHasAmbient();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if we're not moving the mouse, if we started clicking on an entity and we have
|
// 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();
|
deleteReleasedModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar) {
|
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||||
bool didUpdate = false;
|
bool didUpdate = false;
|
||||||
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
|
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
|
||||||
QVector<EntityItemPointer> foundEntities;
|
QVector<EntityItemPointer> foundEntities;
|
||||||
|
@ -220,12 +224,10 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
|
||||||
_tree->withReadLock([&] {
|
_tree->withReadLock([&] {
|
||||||
|
|
||||||
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
|
// 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.
|
LayeredZones oldLayeredZones(std::move(_layeredZones));
|
||||||
auto oldBestZone = _bestZone;
|
_layeredZones.clear();
|
||||||
_bestZone = nullptr; // NOTE: Is this what we want?
|
|
||||||
_bestZoneVolume = std::numeric_limits<float>::max();
|
|
||||||
|
|
||||||
// create a list of entities that actually contain the avatar's position
|
// create a list of entities that actually contain the avatar's position
|
||||||
for (auto& entity : foundEntities) {
|
for (auto& entity : foundEntities) {
|
||||||
|
@ -239,38 +241,34 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
|
||||||
if (isZone || hasScript) {
|
if (isZone || hasScript) {
|
||||||
// now check to see if the point contains our entity, this can be expensive if
|
// now check to see if the point contains our entity, this can be expensive if
|
||||||
// the entity has a collision hull
|
// the entity has a collision hull
|
||||||
if (entity->contains(avatarPosition)) {
|
if (entity->contains(_avatarPosition)) {
|
||||||
if (entitiesContainingAvatar) {
|
if (entitiesContainingAvatar) {
|
||||||
*entitiesContainingAvatar << entity->getEntityItemID();
|
*entitiesContainingAvatar << entity->getEntityItemID();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this entity is a zone and visible, determine if it is the bestZone
|
// if this entity is a zone and visible, determine if it is the bestZone
|
||||||
if (isZone && entity->getVisible()) {
|
if (isZone && entity->getVisible()) {
|
||||||
float entityVolumeEstimate = entity->getVolumeEstimate();
|
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||||
if (entityVolumeEstimate < _bestZoneVolume) {
|
_layeredZones.insert(zone);
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bestZone != oldBestZone) {
|
// check if our layered zones have changed
|
||||||
applyZonePropertiesToScene(_bestZone);
|
if (_layeredZones.empty()) {
|
||||||
didUpdate = true;
|
if (oldLayeredZones.empty()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (!oldLayeredZones.empty()) {
|
||||||
|
if (_layeredZones.contains(oldLayeredZones)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_layeredZones.apply();
|
||||||
|
didUpdate = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return didUpdate;
|
return didUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,13 +284,14 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
||||||
// if some amount of time has elapsed since we last checked. We check the time
|
// 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
|
// elapsed because zones or entities might have been created "around us" while we've
|
||||||
// been stationary
|
// 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;
|
auto enoughTimeElapsed = (now - _lastZoneCheck) > ZONE_CHECK_INTERVAL;
|
||||||
|
|
||||||
if (movedEnough || enoughTimeElapsed) {
|
if (movedEnough || enoughTimeElapsed) {
|
||||||
|
_avatarPosition = avatarPosition;
|
||||||
_lastZoneCheck = now;
|
_lastZoneCheck = now;
|
||||||
QVector<EntityItemID> entitiesContainingAvatar;
|
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
|
// 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
|
// EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts
|
||||||
|
@ -318,7 +317,6 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_currentEntitiesInside = entitiesContainingAvatar;
|
_currentEntitiesInside = entitiesContainingAvatar;
|
||||||
_lastAvatarPosition = avatarPosition;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return didUpdate;
|
return didUpdate;
|
||||||
|
@ -342,24 +340,20 @@ void EntityTreeRenderer::leaveAllEntities() {
|
||||||
void EntityTreeRenderer::forceRecheckEntities() {
|
void EntityTreeRenderer::forceRecheckEntities() {
|
||||||
// make sure our "last avatar position" is something other than our current position,
|
// 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.
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||||
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
|
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||||
auto sceneStage = scene->getStage();
|
auto sceneStage = scene->getStage();
|
||||||
auto skyStage = scene->getSkyStage();
|
auto skyStage = scene->getSkyStage();
|
||||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
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 there is no zone, use the default background
|
||||||
if (!zone) {
|
if (!zone) {
|
||||||
_zoneUserData = QString();
|
_zoneUserData = QString();
|
||||||
skybox->clear();
|
skyStage->getSkybox()->clear();
|
||||||
|
|
||||||
_pendingSkyboxTexture = false;
|
_pendingSkyboxTexture = false;
|
||||||
_skyboxTexture.clear();
|
_skyboxTexture.clear();
|
||||||
|
@ -371,7 +365,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
sceneKeyLight->setAmbientMap(nullptr);
|
sceneKeyLight->setAmbientMap(nullptr);
|
||||||
|
|
||||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the keylight
|
// Set the keylight
|
||||||
|
@ -394,35 +388,34 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the ambient texture
|
// Set the ambient texture
|
||||||
bool isAmbientTextureSet = false;
|
|
||||||
if (zone->getKeyLightProperties().getAmbientURL().isEmpty()) {
|
if (zone->getKeyLightProperties().getAmbientURL().isEmpty()) {
|
||||||
_pendingAmbientTexture = false;
|
_pendingAmbientTexture = false;
|
||||||
_ambientTexture.clear();
|
_ambientTexture.clear();
|
||||||
} else {
|
} else {
|
||||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE);
|
|
||||||
_pendingAmbientTexture = true;
|
_pendingAmbientTexture = true;
|
||||||
|
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the skybox 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()) {
|
switch (zone->getBackgroundMode()) {
|
||||||
case BACKGROUND_MODE_SKYBOX: {
|
case BACKGROUND_MODE_SKYBOX:
|
||||||
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||||
if (_zoneUserData != zone->getUserData()) {
|
if (_zoneUserData != zone->getUserData()) {
|
||||||
_zoneUserData = zone->getUserData();
|
_zoneUserData = zone->getUserData();
|
||||||
skybox->parse(_zoneUserData);
|
std::dynamic_pointer_cast<ProceduralSkybox>(skybox)->parse(_zoneUserData);
|
||||||
}
|
}
|
||||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||||
skybox->setCubemap(nullptr);
|
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
|
// Update the Texture of the Skybox with the one pointed by this zone
|
||||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE);
|
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE);
|
||||||
_pendingSkyboxTexture = true;
|
_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);
|
skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||||
|
hasSkybox = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case BACKGROUND_MODE_INHERIT:
|
case BACKGROUND_MODE_INHERIT:
|
||||||
default:
|
default:
|
||||||
|
@ -466,7 +441,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
_pendingSkyboxTexture = false;
|
_pendingSkyboxTexture = false;
|
||||||
|
|
||||||
// Let the application background through
|
// Let the application background through
|
||||||
if (isAmbientTextureSet) {
|
if (applySkyboxAndHasAmbient()) {
|
||||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
|
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
|
||||||
} else {
|
} else {
|
||||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
|
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
|
||||||
|
@ -474,10 +449,56 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
break;
|
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->resetAmbientSphere();
|
||||||
sceneKeyLight->setAmbientMap(nullptr);
|
sceneKeyLight->setAmbientMap(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isAmbientSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
|
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
|
||||||
|
@ -1046,21 +1067,119 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::updateZone(const EntityItemID& id) {
|
void EntityTreeRenderer::updateZone(const EntityItemID& id) {
|
||||||
if (!_bestZone) {
|
|
||||||
// Get in the zone!
|
// Get in the zone!
|
||||||
auto zone = getTree()->findEntityByEntityItemID(id);
|
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(getTree()->findEntityByEntityItemID(id));
|
||||||
if (zone && zone->contains(_lastAvatarPosition)) {
|
if (zone && zone->contains(_avatarPosition)) {
|
||||||
_currentEntitiesInside << id;
|
_layeredZones.update(zone);
|
||||||
emit enterEntity(id);
|
|
||||||
if (_entitiesScriptEngine) {
|
|
||||||
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
|
||||||
}
|
}
|
||||||
if (zone->getVisible()) {
|
}
|
||||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_bestZone && _bestZone->getID() == id) {
|
|
||||||
applyZonePropertiesToScene(_bestZone);
|
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
|
// For Scene.shouldRenderEntities
|
||||||
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
|
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
|
||||||
|
|
||||||
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
|
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _layeredZones.getZone(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
@ -138,9 +138,12 @@ private:
|
||||||
void resetEntitiesScriptEngine();
|
void resetEntitiesScriptEngine();
|
||||||
|
|
||||||
void addEntityToScene(EntityItemPointer entity);
|
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);
|
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
|
||||||
|
|
||||||
QList<ModelPointer> _releasedModels;
|
QList<ModelPointer> _releasedModels;
|
||||||
|
@ -156,15 +159,9 @@ private:
|
||||||
void leaveAllEntities();
|
void leaveAllEntities();
|
||||||
void forceRecheckEntities();
|
void forceRecheckEntities();
|
||||||
|
|
||||||
glm::vec3 _lastAvatarPosition { 0.0f };
|
glm::vec3 _avatarPosition { 0.0f };
|
||||||
QVector<EntityItemID> _currentEntitiesInside;
|
QVector<EntityItemID> _currentEntitiesInside;
|
||||||
|
|
||||||
bool _pendingSkyboxTexture { false };
|
|
||||||
NetworkTexturePointer _skyboxTexture;
|
|
||||||
|
|
||||||
bool _pendingAmbientTexture { false };
|
|
||||||
NetworkTexturePointer _ambientTexture;
|
|
||||||
|
|
||||||
bool _wantScripts;
|
bool _wantScripts;
|
||||||
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
||||||
|
|
||||||
|
@ -185,26 +182,60 @@ private:
|
||||||
|
|
||||||
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
||||||
|
|
||||||
std::shared_ptr<ZoneEntityItem> _bestZone;
|
class LayeredZone {
|
||||||
float _bestZoneVolume;
|
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;
|
QString _zoneUserData;
|
||||||
|
NetworkTexturePointer _skyboxTexture;
|
||||||
|
NetworkTexturePointer _ambientTexture;
|
||||||
|
bool _pendingSkyboxTexture { false };
|
||||||
|
bool _pendingAmbientTexture { false };
|
||||||
|
|
||||||
quint64 _lastZoneCheck { 0 };
|
quint64 _lastZoneCheck { 0 };
|
||||||
const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
|
const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
|
||||||
const float ZONE_CHECK_DISTANCE = 0.001f;
|
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;
|
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||||
// For Scene.shouldRenderEntities
|
// For Scene.shouldRenderEntities
|
||||||
QList<EntityItemID> _entityIDsLastInScene;
|
QList<EntityItemID> _entityIDsLastInScene;
|
||||||
|
|
Loading…
Reference in a new issue