mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #10537 from samcake/brown
Fix the flickering and other lighting issues related to zone entities (part 1)
This commit is contained in:
commit
bc44a03e13
29 changed files with 1340 additions and 503 deletions
|
@ -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<SceneScriptingInterface>()->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<BackgroundRenderData> 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<SceneScriptingInterface>()->getSkyStage();
|
||||
auto backgroundMode = skyStage->getBackgroundMode();
|
||||
|
||||
switch (backgroundMode) {
|
||||
case model::SunSkyStage::SKY_DEFAULT: {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
|
||||
scene->setSunModelEnable(false);
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR));
|
||||
sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION);
|
||||
// fall through: render a skybox (if available), or the defaults (if requested)
|
||||
}
|
||||
|
||||
case model::SunSkyStage::SKY_BOX: {
|
||||
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<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
|
||||
if (defaultSkyboxAmbientTexture) {
|
||||
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
|
||||
} else {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||
"Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step");
|
||||
}
|
||||
// fall through: render defaults skybox
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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<BackgroundRenderData>();
|
||||
auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData);
|
||||
BackgroundRenderData::_item = _main3DScene->allocateID();
|
||||
transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload);
|
||||
}
|
||||
|
||||
// Assuming nothing gets rendered through that
|
||||
if (!selfAvatarOnly) {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
|
@ -5104,12 +5005,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
});
|
||||
}
|
||||
|
||||
// Setup the current Zone Entity lighting
|
||||
{
|
||||
auto stage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(stage->getSunLight());
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("SceneProcessTransaction");
|
||||
_main3DScene->enqueueTransaction(transaction);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <PerfStat.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#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<ZoneEntityItem>& zone) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
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<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:
|
||||
hasSkybox = true;
|
||||
|
||||
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
|
||||
if (_zoneUserData != zone->getUserData()) {
|
||||
_zoneUserData = zone->getUserData();
|
||||
std::dynamic_pointer_cast<ProceduralSkybox>(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<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 (_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::LayeredZones::iterator, bool> EntityTreeRenderer::
|
|||
|
||||
void EntityTreeRenderer::LayeredZones::apply() {
|
||||
assert(_entityTreeRenderer);
|
||||
|
||||
applyPartial(begin());
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
|
@ -1202,12 +1020,6 @@ void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> 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<ZoneEntityItem> 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) {
|
||||
|
|
|
@ -147,9 +147,6 @@ private:
|
|||
void addEntityToScene(EntityItemPointer entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool applySkyboxAndHasAmbient();
|
||||
bool applyLayeredZones();
|
||||
|
||||
void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false);
|
||||
|
|
|
@ -13,14 +13,90 @@
|
|||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <model/Stage.h>
|
||||
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <PerfStat.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
#include <LightPayload.h>
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
|
||||
class RenderableZoneEntityItemMeta {
|
||||
public:
|
||||
RenderableZoneEntityItemMeta(EntityItemPointer entity);
|
||||
~RenderableZoneEntityItemMeta();
|
||||
|
||||
typedef render::Payload<RenderableZoneEntityItemMeta> 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<EntityTreeRenderer>()->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<RenderableZoneEntityItemMeta> 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<RenderableZoneEntityItemMeta>(self);
|
||||
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(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<RenderableZoneEntityItemMeta>(_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<model::Light>()),
|
||||
_ambientLight(std::make_shared<model::Light>()),
|
||||
_background(std::make_shared<model::SunSkyStage>())
|
||||
{
|
||||
_background->setSkybox(std::make_shared<ProceduralSkybox>());
|
||||
}
|
||||
|
||||
|
||||
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<TextureCache>();
|
||||
_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<RenderableZoneEntityItemMeta>(self);
|
||||
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(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<RenderableZoneEntityItemMeta>(_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<TextureCache>();
|
||||
_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<ProceduralSkybox>(editSkybox())->parse(_proceduralUserData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RenderableZoneEntityItemMeta::render(RenderArgs* args) {
|
||||
if (!_stage) {
|
||||
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||
}
|
||||
|
||||
if (!_backgroundStage) {
|
||||
_backgroundStage = DependencyManager::get<DeferredLightingEffect>()->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <ZoneEntityItem.h>
|
||||
|
||||
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<typename Lambda>
|
||||
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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -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() << "---------------------------------------------";
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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()
|
||||
|
|
141
libraries/render-utils/src/BackgroundStage.cpp
Normal file
141
libraries/render-utils/src/BackgroundStage.cpp
Normal file
|
@ -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 <gpu/Context.h>
|
||||
|
||||
BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const {
|
||||
auto found = _backgroundMap.find(background);
|
||||
if (found != _backgroundMap.end()) {
|
||||
return INVALID_INDEX;
|
||||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BackgroundStage::Index BackgroundStage::addBackground(const BackgroundPointer& background) {
|
||||
|
||||
auto found = _backgroundMap.find(background);
|
||||
if (found == _backgroundMap.end()) {
|
||||
auto backgroundId = _backgrounds.newElement(background);
|
||||
// Avoid failing to allocate a background, just pass
|
||||
if (backgroundId != INVALID_INDEX) {
|
||||
|
||||
// Insert the background and its index in the reverse map
|
||||
_backgroundMap.insert(BackgroundMap::value_type(background, backgroundId));
|
||||
}
|
||||
return backgroundId;
|
||||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BackgroundStage::BackgroundPointer BackgroundStage::removeBackground(Index index) {
|
||||
BackgroundPointer removed = _backgrounds.freeElement(index);
|
||||
|
||||
if (removed) {
|
||||
_backgroundMap.erase(removed);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
||||
void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
|
||||
const auto& lightingModel = inputs;
|
||||
if (!lightingModel->isBackgroundEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Background rendering decision
|
||||
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
|
||||
model::SunSkyStagePointer background;
|
||||
model::SkyboxPointer skybox;
|
||||
if (backgroundStage->_currentFrame._backgrounds.size()) {
|
||||
auto backgroundId = backgroundStage->_currentFrame._backgrounds.front();
|
||||
auto background = backgroundStage->getBackground(backgroundId);
|
||||
if (background) {
|
||||
skybox = background->getSkybox();
|
||||
}
|
||||
} else {
|
||||
skybox = DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox();
|
||||
}
|
||||
|
||||
/* auto backgroundMode = skyStage->getBackgroundMode();
|
||||
|
||||
switch (backgroundMode) {
|
||||
case model::SunSkyStage::SKY_DEFAULT: {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
|
||||
scene->setSunModelEnable(false);
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR));
|
||||
sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION);
|
||||
// fall through: render a skybox (if available), or the defaults (if requested)
|
||||
}
|
||||
|
||||
case model::SunSkyStage::SKY_BOX: {*/
|
||||
if (skybox && !skybox->empty()) {
|
||||
PerformanceTimer perfTimer("skybox");
|
||||
auto args = renderContext->args;
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
||||
batch.enableSkybox(true);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
skybox->render(batch, args->getViewFrustum());
|
||||
});
|
||||
args->_batch = nullptr;
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
// break;
|
||||
}
|
||||
// fall through: render defaults (if requested)
|
||||
// }
|
||||
/*
|
||||
case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
|
||||
if (defaultSkyboxAmbientTexture) {
|
||||
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
|
||||
} else {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||
"Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step");
|
||||
}
|
||||
// fall through: render defaults skybox
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
80
libraries/render-utils/src/BackgroundStage.h
Normal file
80
libraries/render-utils/src/BackgroundStage.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// BackgroundStage.h
|
||||
|
||||
// Created by Sam Gateau on 5/9/2017.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_render_utils_BackgroundStage_h
|
||||
#define hifi_render_utils_BackgroundStage_h
|
||||
|
||||
#include <model/Stage.h>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <render/IndexedContainer.h>
|
||||
|
||||
#include "LightingModel.h"
|
||||
|
||||
|
||||
// Background stage to set up background-related rendering tasks
|
||||
class BackgroundStage {
|
||||
public:
|
||||
using Index = render::indexed_container::Index;
|
||||
static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
|
||||
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
|
||||
|
||||
using BackgroundPointer = model::SunSkyStagePointer;
|
||||
using Backgrounds = render::indexed_container::IndexedPointerVector<model::SunSkyStage>;
|
||||
using BackgroundMap = std::unordered_map<BackgroundPointer, Index>;
|
||||
|
||||
using BackgroundIndices = std::vector<Index>;
|
||||
|
||||
|
||||
Index findBackground(const BackgroundPointer& background) const;
|
||||
Index addBackground(const BackgroundPointer& background);
|
||||
|
||||
BackgroundPointer removeBackground(Index index);
|
||||
|
||||
bool checkBackgroundId(Index index) const { return _backgrounds.checkIndex(index); }
|
||||
|
||||
Index getNumBackgrounds() const { return _backgrounds.getNumElements(); }
|
||||
Index getNumFreeBackgrounds() const { return _backgrounds.getNumFreeIndices(); }
|
||||
Index getNumAllocatedBackgrounds() const { return _backgrounds.getNumAllocatedIndices(); }
|
||||
|
||||
BackgroundPointer getBackground(Index backgroundId) const {
|
||||
return _backgrounds.get(backgroundId);
|
||||
}
|
||||
|
||||
Backgrounds _backgrounds;
|
||||
BackgroundMap _backgroundMap;
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
Frame() {}
|
||||
|
||||
void clear() { _backgrounds.clear(); }
|
||||
|
||||
void pushBackground(BackgroundStage::Index index) { _backgrounds.emplace_back(index); }
|
||||
|
||||
BackgroundStage::BackgroundIndices _backgrounds;
|
||||
};
|
||||
|
||||
Frame _currentFrame;
|
||||
};
|
||||
using BackgroundStagePointer = std::shared_ptr<BackgroundStage>;
|
||||
|
||||
|
||||
class DrawBackgroundStage {
|
||||
public:
|
||||
using Inputs = LightingModelPointer;
|
||||
using JobModel = render::Job::ModelI<DrawBackgroundStage, Inputs>;
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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<BackgroundStage>();
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "Process Default Skybox");
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
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::Light>());
|
||||
}
|
||||
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 <shared/Shapes.h>
|
||||
|
||||
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<DeferredLightingEffect>();
|
||||
|
||||
// End of the Lighting pass
|
||||
if (!deferredLightingEffect->_pointLights.empty()) {
|
||||
deferredLightingEffect->_pointLights.clear();
|
||||
}
|
||||
if (!deferredLightingEffect->_spotLights.empty()) {
|
||||
deferredLightingEffect->_spotLights.clear();
|
||||
}
|
||||
}
|
||||
|
||||
RenderDeferred::RenderDeferred() {
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "model/Light.h"
|
||||
#include "model/Geometry.h"
|
||||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include <render/CullTask.h>
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
@ -28,11 +30,13 @@
|
|||
|
||||
#include "LightStage.h"
|
||||
#include "LightClusters.h"
|
||||
#include "BackgroundStage.h"
|
||||
|
||||
#include "SurfaceGeometryPass.h"
|
||||
#include "SubsurfaceScattering.h"
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
|
||||
|
||||
class RenderArgs;
|
||||
struct LightLocations;
|
||||
using LightLocationsPtr = std::shared_ptr<LightLocations>;
|
||||
|
@ -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<int> _globalLights;
|
||||
std::vector<int> _pointLights;
|
||||
std::vector<int> _spotLights;
|
||||
|
||||
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
|
||||
gpu::TexturePointer _defaultSkyboxTexture;
|
||||
gpu::TexturePointer _defaultSkyboxAmbientTexture;
|
||||
|
||||
friend class LightClusteringPass;
|
||||
friend class RenderDeferredSetup;
|
||||
|
|
|
@ -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<model::Light>())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyLightPayload::~KeyLightPayload() {
|
||||
if (!LightStage::isIndexInvalid(_index)) {
|
||||
if (_stage) {
|
||||
_stage->removeLight(_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyLightPayload::render(RenderArgs* args) {
|
||||
if (!_stage) {
|
||||
_stage = DependencyManager::get<DeferredLightingEffect>()->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<GeometryCache>()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <model/Light.h>
|
||||
#include <render/Item.h>
|
||||
#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<KeyLightPayload>;
|
||||
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
|
|
@ -77,7 +77,6 @@ public:
|
|||
};
|
||||
using Descs = std::vector<Desc>;
|
||||
|
||||
|
||||
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;
|
||||
|
|
|
@ -75,7 +75,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto deferredFrameTransform = task.addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform");
|
||||
const auto lightingModel = task.addJob<MakeLightingModel>("LightingModel");
|
||||
|
||||
|
||||
// GPU jobs: Start preparing the primary, deferred and lighting buffer
|
||||
const auto primaryFramebuffer = task.addJob<PreparePrimaryFramebuffer>("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>("DrawLight", lights);
|
||||
|
||||
// Filter zones from the general metas bucket
|
||||
const auto zones = task.addJob<ZoneRendererTask>("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>("RenderDeferred", deferredLightingInputs);
|
||||
|
||||
// Use Stencil and draw background in Lighting buffer to complete filling in the opaque
|
||||
const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying();
|
||||
task.addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", backgroundInputs);
|
||||
|
||||
|
||||
// Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job
|
||||
task.addJob<DrawBackgroundStage>("DrawBackgroundDeferred", lightingModel);
|
||||
|
||||
// Render transparent objects forward in LightingBuffer
|
||||
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying();
|
||||
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||
|
@ -162,7 +162,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
||||
|
||||
task.addJob<ZoneRendererTask>("ZoneRenderer", opaques);
|
||||
task.addJob<DrawBounds>("DrawLightBounds", lights);
|
||||
task.addJob<DrawBounds>("DrawZones", zones);
|
||||
}
|
||||
|
||||
// Overlays
|
||||
|
@ -202,6 +203,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE);
|
||||
task.addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
|
||||
}
|
||||
|
||||
task.addJob<DebugZoneLighting>("DrawZoneStack", deferredFrameTransform);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,18 +10,199 @@
|
|||
//
|
||||
#include "ZoneRenderer.h"
|
||||
|
||||
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <render/FilterTask.h>
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
#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, Inputs>;
|
||||
|
||||
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<render::SelectSortItems>("FilterZones", input, ZONES_SELECTION.c_str());
|
||||
|
||||
// just draw them...
|
||||
task.addJob<DrawBounds>("DrawZones", zoneItems);
|
||||
// just setup the current zone env
|
||||
task.addJob<SetupZones>("SetupZones", zoneItems);
|
||||
|
||||
ouput = zoneItems;
|
||||
}
|
||||
|
||||
void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) {
|
||||
|
||||
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->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<DeferredLightingEffect>()->getLightStage();
|
||||
std::vector<model::LightPointer> keyLightStack;
|
||||
if (lightStage && lightStage->_currentFrame._sunLights.size()) {
|
||||
for (auto index : lightStage->_currentFrame._sunLights) {
|
||||
keyLightStack.push_back(lightStage->getLight(index));
|
||||
}
|
||||
}
|
||||
keyLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
|
||||
|
||||
std::vector<model::LightPointer> ambientLightStack;
|
||||
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
|
||||
for (auto index : lightStage->_currentFrame._ambientLights) {
|
||||
ambientLightStack.push_back(lightStage->getLight(index));
|
||||
}
|
||||
}
|
||||
ambientLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
|
||||
|
||||
|
||||
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
|
||||
std::vector<model::SkyboxPointer> 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<DeferredLightingEffect>()->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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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, Inputs, Config>;
|
||||
|
||||
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
|
37
libraries/render-utils/src/zone_draw.slh
Normal file
37
libraries/render-utils/src/zone_draw.slh
Normal file
|
@ -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@>
|
||||
|
54
libraries/render-utils/src/zone_drawAmbient.slf
Normal file
54
libraries/render-utils/src/zone_drawAmbient.slf
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
|
57
libraries/render-utils/src/zone_drawKeyLight.slf
Normal file
57
libraries/render-utils/src/zone_drawKeyLight.slf
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
|
48
libraries/render-utils/src/zone_drawSkybox.slf
Normal file
48
libraries/render-utils/src/zone_drawSkybox.slf
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in a new issue