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:
Sam Gateau 2017-05-26 18:22:56 -07:00 committed by GitHub
commit bc44a03e13
29 changed files with 1340 additions and 503 deletions

View file

@ -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);

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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 };
};

View file

@ -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() << "---------------------------------------------";

View file

@ -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;
};

View file

@ -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());

View file

@ -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);

View file

@ -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 };

View file

@ -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()

View 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;
}
}
*/
}

View 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

View file

@ -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() {

View file

@ -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;

View file

@ -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
}
}

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}
}
});
}

View file

@ -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

View 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@>

View 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);
}

View 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);
}

View 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);
}

View file

@ -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)

View file

@ -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; }
}
}
}
}

View file

@ -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()