add tonemapping props to zones, wip ambient occlusion

This commit is contained in:
HifiExperiments 2024-06-25 16:14:15 -07:00
parent 54d70a5679
commit 6317bd45ac
39 changed files with 1754 additions and 223 deletions

View file

@ -68,6 +68,20 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity
_bloomIndex = INVALID_INDEX;
}
}
if (_tonemappingStage) {
if (!TonemappingStage::isIndexInvalid(_tonemappingIndex)) {
_tonemappingStage->removeTonemapping(_tonemappingIndex);
_tonemappingIndex = INVALID_INDEX;
}
}
if (_ambientOcclusionStage) {
if (!AmbientOcclusionStage::isIndexInvalid(_ambientOcclusionIndex)) {
_ambientOcclusionStage->removeAmbientOcclusion(_ambientOcclusionIndex);
_ambientOcclusionIndex = INVALID_INDEX;
}
}
}
void ZoneEntityRenderer::doRender(RenderArgs* args) {
@ -96,6 +110,16 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
assert(_bloomStage);
}
if (!_tonemappingStage) {
_tonemappingStage = args->_scene->getStage<TonemappingStage>();
assert(_tonemappingStage);
}
if (!_ambientOcclusionStage) {
_ambientOcclusionStage = args->_scene->getStage<AmbientOcclusionStage>();
assert(_ambientOcclusionStage);
}
{ // Sun
if (_needSunUpdate) {
if (LightStage::isIndexInvalid(_sunIndex)) {
@ -149,6 +173,24 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
}
}
{
if (_needTonemappingUpdate) {
if (TonemappingStage::isIndexInvalid(_tonemappingIndex)) {
_tonemappingIndex = _tonemappingStage->addTonemapping(_tonemapping);
}
_needTonemappingUpdate = false;
}
}
{
if (_needAmbientOcclusionUpdate) {
if (AmbientOcclusionStage::isIndexInvalid(_ambientOcclusionIndex)) {
_ambientOcclusionIndex = _ambientOcclusionStage->addAmbientOcclusion(_ambientOcclusion);
}
_needAmbientOcclusionUpdate = false;
}
}
if (_visible) {
// Finally, push the lights visible in the frame
//
@ -184,6 +226,18 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
} else if (_bloomMode == COMPONENT_MODE_ENABLED) {
_bloomStage->_currentFrame.pushBloom(_bloomIndex);
}
if (_tonemappingMode == COMPONENT_MODE_DISABLED) {
_tonemappingStage->_currentFrame.pushTonemapping(0); // Use the fallback tonemapping for "off"
} else if (_tonemappingMode == COMPONENT_MODE_ENABLED) {
_tonemappingStage->_currentFrame.pushTonemapping(_tonemappingIndex);
}
if (_ambientOcclusionMode == COMPONENT_MODE_DISABLED) {
_ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(INVALID_INDEX);
} else if (_ambientOcclusionMode == COMPONENT_MODE_ENABLED) {
_ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(_ambientOcclusionIndex);
}
}
CullTest::_containingZones.insert(_entityID);
@ -216,6 +270,8 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
bool skyboxChanged = entity->skyboxPropertiesChanged() || proceduralUserDataChanged;
bool hazeChanged = entity->hazePropertiesChanged();
bool bloomChanged = entity->bloomPropertiesChanged();
bool tonemappingChanged = entity->tonemappingPropertiesChanged();
bool ambientOcclusionChanged = entity->ambientOcclusionPropertiesChanged();
entity->resetRenderingPropertiesChanged();
if (transformChanged) {
@ -255,6 +311,16 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
updateBloomFromEntity(entity);
}
if (tonemappingChanged) {
_tonemappingProperties = entity->getTonemappingProperties();
updateTonemappingFromEntity(entity);
}
if (ambientOcclusionChanged) {
_ambientOcclusionProperties = entity->getAmbientOcclusionProperties();
updateAmbientOcclusionFromEntity(entity);
}
bool visuallyReady = true;
uint32_t skyboxMode = entity->getSkyboxMode();
if (skyboxMode == COMPONENT_MODE_ENABLED && !_skyboxTextureURL.isEmpty()) {
@ -275,7 +341,9 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
entity->ambientLightPropertiesChanged() ||
entity->hazePropertiesChanged() ||
entity->bloomPropertiesChanged() ||
entity->skyboxPropertiesChanged()) {
entity->skyboxPropertiesChanged() ||
entity->tonemappingPropertiesChanged() ||
entity->ambientOcclusionPropertiesChanged()) {
return true;
}
@ -360,6 +428,32 @@ void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity)
bloom->setBloomSize(_bloomProperties.getBloomSize());
}
void ZoneEntityRenderer::updateTonemappingFromEntity(const TypedEntityPointer& entity) {
_tonemappingMode = (ComponentMode)entity->getTonemappingMode();
const auto& tonemapping = editTonemapping();
tonemapping->setCurve(_tonemappingProperties.getCurve());
tonemapping->setExposure(_tonemappingProperties.getExposure());
}
void ZoneEntityRenderer::updateAmbientOcclusionFromEntity(const TypedEntityPointer& entity) {
_ambientOcclusionMode = (ComponentMode)entity->getAmbientOcclusionMode();
const auto& ambientOcclusion = editAmbientOcclusion();
ambientOcclusion->setTechnique(_ambientOcclusionProperties.getTechnique());
ambientOcclusion->setJitter(_ambientOcclusionProperties.getJitter());
ambientOcclusion->setResolutionLevel(_ambientOcclusionProperties.getResolutionLevel());
ambientOcclusion->setEdgeSharpness(_ambientOcclusionProperties.getEdgeSharpness());
ambientOcclusion->setBlurRadius(_ambientOcclusionProperties.getBlurRadius());
ambientOcclusion->setAORadius(_ambientOcclusionProperties.getAORadius());
ambientOcclusion->setAOObscuranceLevel(_ambientOcclusionProperties.getAOObscuranceLevel());
ambientOcclusion->setAOFalloffAngle(_ambientOcclusionProperties.getAOFalloffAngle());
ambientOcclusion->setAONumSamples(_ambientOcclusionProperties.getAONumSamples());
ambientOcclusion->setSSAONumSpiralTurns(_ambientOcclusionProperties.getSSAONumSpiralTurns());
}
void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) {
_skyboxMode = (ComponentMode)entity->getSkyboxMode();

View file

@ -20,6 +20,8 @@
#include <BackgroundStage.h>
#include <HazeStage.h>
#include <BloomStage.h>
#include <TonemappingStage.h>
#include <AmbientOcclusionStage.h>
#include <TextureCache.h>
#include "RenderableEntityItem.h"
#include <ComponentMode.h>
@ -47,6 +49,8 @@ private:
void updateHazeFromEntity(const TypedEntityPointer& entity);
void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity);
void updateBloomFromEntity(const TypedEntityPointer& entity);
void updateTonemappingFromEntity(const TypedEntityPointer& entity);
void updateAmbientOcclusionFromEntity(const TypedEntityPointer& entity);
void updateAmbientMap();
void updateSkyboxMap();
void setAmbientURL(const QString& ambientUrl);
@ -61,6 +65,8 @@ private:
graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); }
graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; }
graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; }
graphics::TonemappingPointer editTonemapping() { _needTonemappingUpdate = true; return _tonemapping; }
graphics::AmbientOcclusionPointer editAmbientOcclusion() { _needAmbientOcclusionUpdate = true; return _ambientOcclusion; }
glm::vec3 _lastPosition;
glm::vec3 _lastDimensions;
@ -73,12 +79,16 @@ private:
const graphics::SunSkyStagePointer _background { std::make_shared<graphics::SunSkyStage>() };
const graphics::HazePointer _haze { std::make_shared<graphics::Haze>() };
const graphics::BloomPointer _bloom { std::make_shared<graphics::Bloom>() };
const graphics::TonemappingPointer _tonemapping { std::make_shared<graphics::Tonemapping>() };
const graphics::AmbientOcclusionPointer _ambientOcclusion { std::make_shared<graphics::AmbientOcclusion>() };
ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT };
ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT };
ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT };
ComponentMode _hazeMode { COMPONENT_MODE_INHERIT };
ComponentMode _bloomMode { COMPONENT_MODE_INHERIT };
ComponentMode _tonemappingMode { COMPONENT_MODE_INHERIT };
ComponentMode _ambientOcclusionMode { COMPONENT_MODE_INHERIT };
indexed_container::Index _sunIndex { LightStage::INVALID_INDEX };
indexed_container::Index _ambientIndex { LightStage::INVALID_INDEX };
@ -92,27 +102,37 @@ private:
BloomStagePointer _bloomStage;
BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX };
bool _needUpdate{ true };
bool _needSunUpdate{ true };
bool _needAmbientUpdate{ true };
bool _needBackgroundUpdate{ true };
bool _needHazeUpdate{ true };
TonemappingStagePointer _tonemappingStage;
TonemappingStage::Index _tonemappingIndex { TonemappingStage::INVALID_INDEX };
AmbientOcclusionStagePointer _ambientOcclusionStage;
AmbientOcclusionStage::Index _ambientOcclusionIndex { AmbientOcclusionStage::INVALID_INDEX };
bool _needUpdate { true };
bool _needSunUpdate { true };
bool _needAmbientUpdate { true };
bool _needBackgroundUpdate { true };
bool _needHazeUpdate { true };
bool _needBloomUpdate { true };
bool _needTonemappingUpdate { true };
bool _needAmbientOcclusionUpdate { true };
KeyLightPropertyGroup _keyLightProperties;
AmbientLightPropertyGroup _ambientLightProperties;
HazePropertyGroup _hazeProperties;
SkyboxPropertyGroup _skyboxProperties;
BloomPropertyGroup _bloomProperties;
TonemappingPropertyGroup _tonemappingProperties;
AmbientOcclusionPropertyGroup _ambientOcclusionProperties;
// More attributes used for rendering:
QString _ambientTextureURL;
NetworkTexturePointer _ambientTexture;
bool _pendingAmbientTexture{ false };
bool _pendingAmbientTexture { false };
QString _skyboxTextureURL;
NetworkTexturePointer _skyboxTexture;
bool _pendingSkyboxTexture{ false };
bool _pendingSkyboxTexture { false };
QString _proceduralUserData;
};

View file

@ -0,0 +1,300 @@
//
// AmbientOcclusionPropertyGroup.cpp
// libraries/entities/src
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
#include "AmbientOcclusionPropertyGroup.h"
#include <OctreePacketData.h>
#include "EntityItemProperties.h"
#include "EntityItemPropertiesMacros.h"
inline void addAmbientOcclusionTechnique(QHash<QString, AmbientOcclusionTechnique>& lookup, AmbientOcclusionTechnique technique) { lookup[AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(technique)] = technique; }
const QHash<QString, AmbientOcclusionTechnique> stringToAmbientOcclusionTechniqueLookup = [] {
QHash<QString, AmbientOcclusionTechnique> toReturn;
addAmbientOcclusionTechnique(toReturn, AmbientOcclusionTechnique::SSAO);
addAmbientOcclusionTechnique(toReturn, AmbientOcclusionTechnique::HBAO);
return toReturn;
}();
QString AmbientOcclusionPropertyGroup::getTechniqueAsString() const { return AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(_technique); }
void AmbientOcclusionPropertyGroup::setTechniqueFromString(const QString& technique) {
auto techniqueItr = stringToAmbientOcclusionTechniqueLookup.find(technique.toLower());
if (techniqueItr != stringToAmbientOcclusionTechniqueLookup.end()) {
_technique = techniqueItr.value();
_techniqueChanged = true;
}
}
void AmbientOcclusionPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine,
bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_OCCLUSION_TECHNIQUE, AmbientOcclusion, ambientOcclusion, Technique, technique, getTechniqueAsString);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_JITTER, AmbientOcclusion, ambientOcclusion, Jitter, jitter);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, AmbientOcclusion, ambientOcclusion, ResolutionLevel, resolutionLevel);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, AmbientOcclusion, ambientOcclusion, EdgeSharpness, edgeSharpness);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, AmbientOcclusion, ambientOcclusion, BlurRadius, blurRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_AO_RADIUS, AmbientOcclusion, ambientOcclusion, AORadius, aoRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, AmbientOcclusion, ambientOcclusion, AOObscuranceLevel, aoObscuranceLevel);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, AmbientOcclusion, ambientOcclusion, AOFalloffAngle, aoFalloffAngle);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, AmbientOcclusion, ambientOcclusion, AONumSamples, aoNumSamples);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, AmbientOcclusion, ambientOcclusion, SSAONumSpiralTurns, ssaoNumSpiralTurns);
}
void AmbientOcclusionPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientOcclusion, technique, Technique);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, jitter, bool, setJitter);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, resolutionLevel, uint8_t, setResolutionLevel);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, edgeSharpness, float, setEdgeSharpness);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, blurRadius, uint8_t, setBlurRadius);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, aoRadius, float, setAORadius);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, aoObscuranceLevel, float, setAOObscuranceLevel);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, aoFalloffAngle, float, setAOFalloffAngle);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, aoNumSamples, uint8_t, setAONumSamples);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientOcclusion, ssaoNumSpiralTurns, float, setSSAONumSpiralTurns);
}
void AmbientOcclusionPropertyGroup::merge(const AmbientOcclusionPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(technique);
COPY_PROPERTY_IF_CHANGED(jitter);
COPY_PROPERTY_IF_CHANGED(resolutionLevel);
COPY_PROPERTY_IF_CHANGED(edgeSharpness);
COPY_PROPERTY_IF_CHANGED(blurRadius);
COPY_PROPERTY_IF_CHANGED(aoRadius);
COPY_PROPERTY_IF_CHANGED(aoObscuranceLevel);
COPY_PROPERTY_IF_CHANGED(aoFalloffAngle);
COPY_PROPERTY_IF_CHANGED(aoNumSamples);
COPY_PROPERTY_IF_CHANGED(ssaoNumSpiralTurns);
}
void AmbientOcclusionPropertyGroup::debugDump() const {
qCDebug(entities) << " AmbientOcclusionPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " Technique:" << getTechniqueAsString();
qCDebug(entities) << " Jitter:" << getJitter();
qCDebug(entities) << " ResolutionLevel:" << getResolutionLevel();
qCDebug(entities) << " EdgeSharpness:" << getEdgeSharpness();
qCDebug(entities) << " BlurRadius:" << getBlurRadius();
qCDebug(entities) << " AORadius:" << getAORadius();
qCDebug(entities) << " AOObscuranceLevel:" << getAOObscuranceLevel();
qCDebug(entities) << " AOFalloffAngle:" << getAOFalloffAngle();
qCDebug(entities) << " AONumSamples:" << getAONumSamples();
qCDebug(entities) << " SSAONumSpiralTurns:" << getSSAONumSpiralTurns();
}
void AmbientOcclusionPropertyGroup::listChangedProperties(QList<QString>& out) {
if (techniqueChanged()) {
out << "ambientOcclusion-technique";
}
if (jitterChanged()) {
out << "ambientOcclusion-jitter";
}
if (resolutionLevelChanged()) {
out << "ambientOcclusion-resolutionLevel";
}
if (edgeSharpnessChanged()) {
out << "ambientOcclusion-edgeSharpness";
}
if (blurRadiusChanged()) {
out << "ambientOcclusion-blurRadius";
}
if (aoRadiusChanged()) {
out << "ambientOcclusion-aoRadius";
}
if (aoObscuranceLevelChanged()) {
out << "ambientOcclusion-aoObscuranceLevel";
}
if (aoFalloffAngleChanged()) {
out << "ambientOcclusion-aoFalloffAngle";
}
if (aoNumSamplesChanged()) {
out << "ambientOcclusion-aoNumSamples";
}
if (ssaoNumSpiralTurnsChanged()) {
out << "ambientOcclusion-ssaoNumSpiralTurns";
}
}
bool AmbientOcclusionPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_TECHNIQUE, (uint32_t)getTechnique());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_JITTER, getJitter());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, getResolutionLevel());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, getEdgeSharpness());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, getBlurRadius());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_RADIUS, getAORadius());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, getAOObscuranceLevel());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, getAOFalloffAngle());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, getAONumSamples());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, getSSAONumSpiralTurns());
return true;
}
bool AmbientOcclusionPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0;
bool overwriteLocalData = true;
bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_TECHNIQUE, AmbientOcclusionTechnique, setTechnique);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_JITTER, bool, setJitter);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, uint8_t, setResolutionLevel);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, float, setEdgeSharpness);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, uint8_t, setBlurRadius);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_RADIUS, float, setAORadius);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, float, setAOObscuranceLevel);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, float, setAOFalloffAngle);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, uint8_t, setAONumSamples);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, float, setSSAONumSpiralTurns);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_TECHNIQUE, Technique);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_JITTER, Jitter);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, ResolutionLevel);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, EdgeSharpness);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, BlurRadius);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_AO_RADIUS, AORadius);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, AOObscuranceLevel);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, AOFalloffAngle);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, AONumSamples);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, SSAONumSpiralTurns);
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}
void AmbientOcclusionPropertyGroup::markAllChanged() {
_techniqueChanged = true;
_jitterChanged = true;
_resolutionLevelChanged = true;
_edgeSharpnessChanged = true;
_blurRadiusChanged = true;
_aoRadiusChanged = true;
_aoObscuranceLevelChanged = true;
_aoFalloffAngleChanged = true;
_aoNumSamplesChanged = true;
_ssaoNumSpiralTurnsChanged = true;
}
EntityPropertyFlags AmbientOcclusionPropertyGroup::getChangedProperties() const {
EntityPropertyFlags changedProperties;
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_TECHNIQUE, technique);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_JITTER, jitter);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, resolutionLevel);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, edgeSharpness);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, blurRadius);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_AO_RADIUS, aoRadius);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, aoObscuranceLevel);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, aoFalloffAngle);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, aoNumSamples);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, ssaoNumSpiralTurns);
return changedProperties;
}
void AmbientOcclusionPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, Technique, getTechnique);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, Jitter, getJitter);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, ResolutionLevel, getResolutionLevel);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, EdgeSharpness, getEdgeSharpness);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, BlurRadius, getBlurRadius);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, AORadius, getAORadius);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, AOObscuranceLevel, getAOObscuranceLevel);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, AOFalloffAngle, getAOFalloffAngle);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, AONumSamples, getAONumSamples);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientOcclusion, SSAONumSpiralTurns, getSSAONumSpiralTurns);
}
bool AmbientOcclusionPropertyGroup::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, Technique, technique, setTechnique);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, Jitter, jitter, setJitter);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, ResolutionLevel, resolutionLevel, setResolutionLevel);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, EdgeSharpness, edgeSharpness, setEdgeSharpness);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, BlurRadius, blurRadius, setBlurRadius);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, AORadius, aoRadius, setAORadius);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, AOObscuranceLevel, aoObscuranceLevel, setAOObscuranceLevel);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, AOFalloffAngle, aoFalloffAngle, setAOFalloffAngle);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, AONumSamples, aoNumSamples, setAONumSamples);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientOcclusion, SSAONumSpiralTurns, ssaoNumSpiralTurns, setSSAONumSpiralTurns);
return somethingChanged;
}
EntityPropertyFlags AmbientOcclusionPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_AMBIENT_OCCLUSION_TECHNIQUE;
requestedProperties += PROP_AMBIENT_OCCLUSION_JITTER;
requestedProperties += PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL;
requestedProperties += PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS;
requestedProperties += PROP_AMBIENT_OCCLUSION_BLUR_RADIUS;
requestedProperties += PROP_AMBIENT_OCCLUSION_AO_RADIUS;
requestedProperties += PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL;
requestedProperties += PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE;
requestedProperties += PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES;
requestedProperties += PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS;
return requestedProperties;
}
void AmbientOcclusionPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_TECHNIQUE, (uint32_t)getTechnique());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_JITTER, getJitter());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, getResolutionLevel());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, getEdgeSharpness());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, getBlurRadius());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_RADIUS, getAORadius());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, getAOObscuranceLevel());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, getAOFalloffAngle());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, getAONumSamples());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, getSSAONumSpiralTurns());
}
int AmbientOcclusionPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_TECHNIQUE, AmbientOcclusionTechnique, setTechnique);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_JITTER, bool, setJitter);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, uint8_t, setResolutionLevel);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, float, setEdgeSharpness);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, uint8_t, setBlurRadius);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_RADIUS, float, setAORadius);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, float, setAOObscuranceLevel);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, float, setAOFalloffAngle);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, uint8_t, setAONumSamples);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, float, setSSAONumSpiralTurns);
return bytesRead;
}

View file

@ -0,0 +1,95 @@
//
// AmbientOcclusionPropertyGroup.h
// libraries/entities/src
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
#ifndef hifi_AmbientOcclusionPropertyGroup_h
#define hifi_AmbientOcclusionPropertyGroup_h
#include <AmbientOcclusionTechnique.h>
#include "PropertyGroup.h"
#include "EntityItemPropertiesMacros.h"
class EntityItemProperties;
class EncodeBitstreamParams;
class OctreePacketData;
class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams;
class ScriptEngine;
class ScriptValue;
/*@jsdoc
* AmbientOcclusion is defined by the following properties:
* @typedef {object} Entities.AmbientOcclusion
* @property {AmbientOcclusionTechnique} technique="ssao" - The AO technique used.
* TODO
*/
class AmbientOcclusionPropertyGroup : public PropertyGroup {
public:
// EntityItemProperty related helpers
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties,
ScriptEngine* engine, bool skipDefaults,
EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags,
bool isMyOwnAvatarEntity) const override;
virtual void copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, bool& _defaultSettings) override;
void merge(const AmbientOcclusionPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_OCCLUSION_TECHNIQUE, Technique, technique, AmbientOcclusionTechnique, AmbientOcclusionTechnique::SSAO);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_JITTER, Jitter, jitter, bool, false);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL, ResolutionLevel, resolutionLevel, uint8_t, 2);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS, EdgeSharpness, edgeSharpness, float, 1.0f);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_BLUR_RADIUS, BlurRadius, blurRadius, uint8_t, 4);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_RADIUS, AORadius, aoRadius, float, 1.0f);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL, AOObscuranceLevel, aoObscuranceLevel, float, 0.5f);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE, AOFalloffAngle, aoFalloffAngle, float, 0.25f);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES, AONumSamples, aoNumSamples, uint8_t, 32);
DEFINE_PROPERTY(PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS, SSAONumSpiralTurns, ssaoNumSpiralTurns, float, 7.0f);
};
#endif // hifi_AmbientOcclusionPropertyGroup_h

View file

@ -48,6 +48,8 @@ BloomPropertyGroup EntityItemProperties::_staticBloom;
ZoneAudioPropertyGroup EntityItemProperties::_staticAudio;
KeyLightPropertyGroup EntityItemProperties::_staticKeyLight;
AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight;
TonemappingPropertyGroup EntityItemProperties::_staticTonemapping;
AmbientOcclusionPropertyGroup EntityItemProperties::_staticAmbientOcclusion;
GrabPropertyGroup EntityItemProperties::_staticGrab;
PulsePropertyGroup EntityItemProperties::_staticPulse;
RingGizmoPropertyGroup EntityItemProperties::_staticRing;
@ -90,6 +92,8 @@ void EntityItemProperties::debugDump() const {
getAmbientLight().debugDump();
getBloom().debugDump();
getAudio().debugDump();
getTonemapping().debugDump();
getAmbientOcclusion().debugDump();
getGrab().debugDump();
qCDebug(entities) << " changed properties...";
@ -254,6 +258,8 @@ QString EntityItemProperties::getKeyLightModeAsString() const { return getCompon
QString EntityItemProperties::getAmbientLightModeAsString() const { return getComponentModeAsString(_ambientLightMode); }
QString EntityItemProperties::getHazeModeAsString() const { return getComponentModeAsString(_hazeMode); }
QString EntityItemProperties::getBloomModeAsString() const { return getComponentModeAsString(_bloomMode); }
QString EntityItemProperties::getTonemappingModeAsString() const { return getComponentModeAsString(_tonemappingMode); }
QString EntityItemProperties::getAmbientOcclusionModeAsString() const { return getComponentModeAsString(_ambientOcclusionMode); }
void EntityItemProperties::setSkyboxModeFromString(const QString& mode) {
auto modeItr = stringToComponentMode.find(mode.toLower());
if (modeItr != stringToComponentMode.end()) {
@ -289,6 +295,20 @@ void EntityItemProperties::setBloomModeFromString(const QString& mode) {
_bloomModeChanged = true;
}
}
void EntityItemProperties::setTonemappingModeFromString(const QString& mode) {
auto modeItr = stringToComponentMode.find(mode.toLower());
if (modeItr != stringToComponentMode.end()) {
_tonemappingMode = modeItr.value();
_tonemappingModeChanged = true;
}
}
void EntityItemProperties::setAmbientOcclusionModeFromString(const QString& mode) {
auto modeItr = stringToComponentMode.find(mode.toLower());
if (modeItr != stringToComponentMode.end()) {
_ambientOcclusionMode = modeItr.value();
_ambientOcclusionModeChanged = true;
}
}
inline void addAvatarPriorityMode(QHash<QString, AvatarPriorityMode>& lookup, AvatarPriorityMode mode) { lookup[AvatarPriorityModeHelpers::getNameForAvatarPriorityMode(mode)] = mode; }
const QHash<QString, AvatarPriorityMode> stringToAvatarPriority = [] {
@ -625,6 +645,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
changedProperties += _haze.getChangedProperties();
changedProperties += _bloom.getChangedProperties();
changedProperties += _audio.getChangedProperties();
changedProperties += _tonemapping.getChangedProperties();
changedProperties += _ambientOcclusion.getChangedProperties();
CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed);
CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
CHECK_PROPERTY_CHANGE(PROP_FILTER_URL, filterURL);
@ -635,6 +657,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode);
CHECK_PROPERTY_CHANGE(PROP_AVATAR_PRIORITY, avatarPriority);
CHECK_PROPERTY_CHANGE(PROP_SCREENSHARE, screenshare);
CHECK_PROPERTY_CHANGE(PROP_TONEMAPPING_MODE, tonemappingMode);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_OCCLUSION_MODE, ambientOcclusionMode);
// Polyvox
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
@ -1547,6 +1571,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
*
* @property {Entities.ZoneAudio} audio - The audio properties of the zone.
*
* @property {Entities.ComponentMode} tonemappingMode="inherit" - Configures the tonemapping in the zone.
* @property {Entities.Tonemapping} tonemapping - The tonemapping properties of the zone.
*
* @property {Entities.ComponentMode} ambientOcclusionMode="inherit" - Configures the ambient occlusion in the zone.
* @property {Entities.AmbientOcclusion} ambientOcclusion - The ambient occlusion properties of the zone.
*
* @property {boolean} flyingAllowed=true - <code>true</code> if visitors can fly in the zone; <code>false</code> if they
* cannot. Only works for domain entities.
* @property {boolean} ghostingAllowed=true - <code>true</code> if visitors with avatar collisions turned off will not
@ -1911,6 +1941,8 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
_haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity);
_bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity);
_audio.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity);
_tonemapping.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity);
_ambientOcclusion.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
@ -1923,6 +1955,8 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AVATAR_PRIORITY, avatarPriority, getAvatarPriorityAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SCREENSHARE, screenshare, getScreenshareAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TONEMAPPING_MODE, tonemappingMode, getTonemappingModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_OCCLUSION_MODE, ambientOcclusionMode, getAmbientOcclusionModeAsString());
}
// Web only
@ -2297,6 +2331,8 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h
_haze.copyFromScriptValue(object, namesSet, _defaultSettings);
_bloom.copyFromScriptValue(object, namesSet, _defaultSettings);
_audio.copyFromScriptValue(object, namesSet, _defaultSettings);
_tonemapping.copyFromScriptValue(object, namesSet, _defaultSettings);
_ambientOcclusion.copyFromScriptValue(object, namesSet, _defaultSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(flyingAllowed, bool, setFlyingAllowed);
COPY_PROPERTY_FROM_QSCRIPTVALUE(ghostingAllowed, bool, setGhostingAllowed);
COPY_PROPERTY_FROM_QSCRIPTVALUE(filterURL, QString, setFilterURL);
@ -2307,6 +2343,8 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(avatarPriority, AvatarPriority);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(screenshare, Screenshare);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(tonemappingMode, TonemappingMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientOcclusionMode, AmbientOcclusionMode);
// Polyvox
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize);
@ -2591,6 +2629,8 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
_haze.merge(other._haze);
_bloom.merge(other._bloom);
_audio.merge(other._audio);
_tonemapping.merge(other._tonemapping);
_ambientOcclusion.merge(other._ambientOcclusion);
COPY_PROPERTY_IF_CHANGED(flyingAllowed);
COPY_PROPERTY_IF_CHANGED(ghostingAllowed);
COPY_PROPERTY_IF_CHANGED(filterURL);
@ -2601,6 +2641,8 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(bloomMode);
COPY_PROPERTY_IF_CHANGED(avatarPriority);
COPY_PROPERTY_IF_CHANGED(screenshare);
COPY_PROPERTY_IF_CHANGED(tonemappingMode);
COPY_PROPERTY_IF_CHANGED(ambientOcclusionMode);
// Polyvox
COPY_PROPERTY_IF_CHANGED(voxelVolumeSize);
@ -3007,6 +3049,13 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_GROUP_PROPERTY_TO_MAP(PROP_LISTENER_ZONES, Audio, audio, ListenerZones, listenerZones);
ADD_GROUP_PROPERTY_TO_MAP(PROP_LISTENER_ATTENUATION_COEFFICIENTS, Audio, audio, ListenerAttenuationCoefficients, listenerAttenuationCoefficients);
}
{ // Tonemapping
ADD_GROUP_PROPERTY_TO_MAP(PROP_TONEMAPPING_CURVE, Tonemapping, tonemapping, Curve, curve);
ADD_GROUP_PROPERTY_TO_MAP(PROP_TONEMAPPING_EXPOSURE, Tonemapping, tonemapping, Exposure, exposure);
}
{ // Ambient Occlusion
// TODO
}
ADD_PROPERTY_TO_MAP(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool);
ADD_PROPERTY_TO_MAP(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool);
ADD_PROPERTY_TO_MAP(PROP_FILTER_URL, FilterURL, filterURL, QString);
@ -3017,6 +3066,8 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_SCREENSHARE, Screenshare, screenshare, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_TONEMAPPING_MODE, TonemappingMode, tonemappingMode, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_AMBIENT_OCCLUSION_MODE, AmbientOcclusionMode, ambientOcclusionMode, uint32_t);
// Polyvox
ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, vec3);
@ -3434,6 +3485,12 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticAudio.setProperties(properties);
_staticAudio.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
_staticTonemapping.setProperties(properties);
_staticTonemapping.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
_staticAmbientOcclusion.setProperties(properties);
_staticAmbientOcclusion.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed());
APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, properties.getFilterURL());
@ -3445,6 +3502,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode());
APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, (uint32_t)properties.getAvatarPriority());
APPEND_ENTITY_PROPERTY(PROP_SCREENSHARE, (uint32_t)properties.getScreenshare());
APPEND_ENTITY_PROPERTY(PROP_TONEMAPPING_MODE, (uint32_t)properties.getTonemappingMode());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_MODE, (uint32_t)properties.getAmbientOcclusionMode());
}
if (properties.getType() == EntityTypes::PolyVox) {
@ -3913,6 +3972,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getAudio().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getTonemapping().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
properties.getAmbientOcclusion().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
@ -3925,6 +3986,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AVATAR_PRIORITY, uint32_t, setAvatarPriority);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCREENSHARE, uint32_t, setScreenshare);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TONEMAPPING_MODE, uint32_t, setTonemappingMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_OCCLUSION_MODE, uint32_t, setAmbientOcclusionMode);
}
if (properties.getType() == EntityTypes::PolyVox) {
@ -4295,6 +4358,8 @@ void EntityItemProperties::markAllChanged() {
_haze.markAllChanged();
_bloom.markAllChanged();
_audio.markAllChanged();
_tonemapping.markAllChanged();
_ambientOcclusion.markAllChanged();
_flyingAllowedChanged = true;
_ghostingAllowedChanged = true;
_filterURLChanged = true;
@ -4305,6 +4370,8 @@ void EntityItemProperties::markAllChanged() {
_bloomModeChanged = true;
_avatarPriorityChanged = true;
_screenshareChanged = true;
_tonemappingModeChanged = true;
_ambientOcclusionModeChanged = true;
// Polyvox
_voxelVolumeSizeChanged = true;
@ -4907,6 +4974,8 @@ QList<QString> EntityItemProperties::listChangedProperties() {
getHaze().listChangedProperties(out);
getBloom().listChangedProperties(out);
getAudio().listChangedProperties(out);
getTonemapping().listChangedProperties(out);
getAmbientOcclusion().listChangedProperties(out);
if (flyingAllowedChanged()) {
out += "flyingAllowed";
}
@ -4937,6 +5006,12 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (screenshareChanged()) {
out += "screenshare";
}
if (tonemappingModeChanged()) {
out += "tonemappingMode";
}
if (ambientOcclusionModeChanged()) {
out += "ambientOcclusionMode";
}
// Polyvox
if (voxelVolumeSizeChanged()) {

View file

@ -63,6 +63,8 @@
#include "PulsePropertyGroup.h"
#include "RingGizmoPropertyGroup.h"
#include "ZoneAudioPropertyGroup.h"
#include "TonemappingPropertyGroup.h"
#include "AmbientOcclusionPropertyGroup.h"
#include "MaterialMappingMode.h"
#include "BillboardMode.h"
@ -343,6 +345,8 @@ public:
DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup);
DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup);
DEFINE_PROPERTY_GROUP(Audio, audio, ZoneAudioPropertyGroup);
DEFINE_PROPERTY_GROUP(Tonemapping, tonemapping, TonemappingPropertyGroup);
DEFINE_PROPERTY_GROUP(AmbientOcclusion, ambientOcclusion, AmbientOcclusionPropertyGroup);
DEFINE_PROPERTY(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool, ZoneEntityItem::DEFAULT_FLYING_ALLOWED);
DEFINE_PROPERTY(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool, ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED);
DEFINE_PROPERTY(PROP_FILTER_URL, FilterURL, filterURL, QString, ZoneEntityItem::DEFAULT_FILTER_URL);
@ -353,6 +357,8 @@ public:
DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_SCREENSHARE, Screenshare, screenshare, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_TONEMAPPING_MODE, TonemappingMode, tonemappingMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_OCCLUSION_MODE, AmbientOcclusionMode, ambientOcclusionMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
// Polyvox
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);

View file

@ -175,6 +175,23 @@ enum EntityPropertyList {
PROP_DERIVED_38,
PROP_DERIVED_39,
PROP_DERIVED_40,
PROP_DERIVED_41,
PROP_DERIVED_42,
PROP_DERIVED_43,
PROP_DERIVED_44,
PROP_DERIVED_45,
PROP_DERIVED_46,
PROP_DERIVED_47,
PROP_DERIVED_48,
PROP_DERIVED_49,
PROP_DERIVED_50,
PROP_DERIVED_51,
PROP_DERIVED_52,
PROP_DERIVED_53,
PROP_DERIVED_54,
PROP_DERIVED_55,
PROP_DERIVED_56,
PROP_DERIVED_57,
PROP_AFTER_LAST_ITEM,
@ -276,44 +293,44 @@ enum EntityPropertyList {
// Zone
// Keylight
PROP_KEYLIGHT_COLOR = PROP_DERIVED_0,
PROP_KEYLIGHT_INTENSITY = PROP_DERIVED_1,
PROP_KEYLIGHT_DIRECTION = PROP_DERIVED_2,
PROP_KEYLIGHT_CAST_SHADOW = PROP_DERIVED_3,
PROP_KEYLIGHT_SHADOW_BIAS = PROP_DERIVED_4,
PROP_KEYLIGHT_SHADOW_MAX_DISTANCE = PROP_DERIVED_5,
PROP_KEY_LIGHT_MODE = PROP_DERIVED_0,
PROP_KEYLIGHT_COLOR = PROP_DERIVED_1,
PROP_KEYLIGHT_INTENSITY = PROP_DERIVED_2,
PROP_KEYLIGHT_DIRECTION = PROP_DERIVED_3,
PROP_KEYLIGHT_CAST_SHADOW = PROP_DERIVED_4,
PROP_KEYLIGHT_SHADOW_BIAS = PROP_DERIVED_5,
PROP_KEYLIGHT_SHADOW_MAX_DISTANCE = PROP_DERIVED_6,
// Ambient light
PROP_AMBIENT_LIGHT_INTENSITY = PROP_DERIVED_6,
PROP_AMBIENT_LIGHT_URL = PROP_DERIVED_7,
PROP_AMBIENT_LIGHT_COLOR = PROP_DERIVED_8,
PROP_AMBIENT_LIGHT_MODE = PROP_DERIVED_7,
PROP_AMBIENT_LIGHT_INTENSITY = PROP_DERIVED_8,
PROP_AMBIENT_LIGHT_URL = PROP_DERIVED_9,
PROP_AMBIENT_LIGHT_COLOR = PROP_DERIVED_10,
// Skybox
PROP_SKYBOX_COLOR = PROP_DERIVED_9,
PROP_SKYBOX_URL = PROP_DERIVED_10,
PROP_SKYBOX_MODE = PROP_DERIVED_11,
PROP_SKYBOX_COLOR = PROP_DERIVED_12,
PROP_SKYBOX_URL = PROP_DERIVED_13,
// Haze
PROP_HAZE_RANGE = PROP_DERIVED_11,
PROP_HAZE_COLOR = PROP_DERIVED_12,
PROP_HAZE_GLARE_COLOR = PROP_DERIVED_13,
PROP_HAZE_ENABLE_GLARE = PROP_DERIVED_14,
PROP_HAZE_GLARE_ANGLE = PROP_DERIVED_15,
PROP_HAZE_ALTITUDE_EFFECT = PROP_DERIVED_16,
PROP_HAZE_CEILING = PROP_DERIVED_17,
PROP_HAZE_BASE_REF = PROP_DERIVED_18,
PROP_HAZE_BACKGROUND_BLEND = PROP_DERIVED_19,
PROP_HAZE_ATTENUATE_KEYLIGHT = PROP_DERIVED_20,
PROP_HAZE_KEYLIGHT_RANGE = PROP_DERIVED_21,
PROP_HAZE_KEYLIGHT_ALTITUDE = PROP_DERIVED_22,
PROP_HAZE_MODE = PROP_DERIVED_14,
PROP_HAZE_RANGE = PROP_DERIVED_15,
PROP_HAZE_COLOR = PROP_DERIVED_16,
PROP_HAZE_GLARE_COLOR = PROP_DERIVED_17,
PROP_HAZE_ENABLE_GLARE = PROP_DERIVED_18,
PROP_HAZE_GLARE_ANGLE = PROP_DERIVED_19,
PROP_HAZE_ALTITUDE_EFFECT = PROP_DERIVED_20,
PROP_HAZE_CEILING = PROP_DERIVED_21,
PROP_HAZE_BASE_REF = PROP_DERIVED_22,
PROP_HAZE_BACKGROUND_BLEND = PROP_DERIVED_23,
PROP_HAZE_ATTENUATE_KEYLIGHT = PROP_DERIVED_24,
PROP_HAZE_KEYLIGHT_RANGE = PROP_DERIVED_25,
PROP_HAZE_KEYLIGHT_ALTITUDE = PROP_DERIVED_26,
// Bloom
PROP_BLOOM_INTENSITY = PROP_DERIVED_23,
PROP_BLOOM_THRESHOLD = PROP_DERIVED_24,
PROP_BLOOM_SIZE = PROP_DERIVED_25,
PROP_FLYING_ALLOWED = PROP_DERIVED_26,
PROP_GHOSTING_ALLOWED = PROP_DERIVED_27,
PROP_FILTER_URL = PROP_DERIVED_28,
PROP_KEY_LIGHT_MODE = PROP_DERIVED_29,
PROP_AMBIENT_LIGHT_MODE = PROP_DERIVED_30,
PROP_SKYBOX_MODE = PROP_DERIVED_31,
PROP_HAZE_MODE = PROP_DERIVED_32,
PROP_BLOOM_MODE = PROP_DERIVED_33,
PROP_BLOOM_MODE = PROP_DERIVED_27,
PROP_BLOOM_INTENSITY = PROP_DERIVED_28,
PROP_BLOOM_THRESHOLD = PROP_DERIVED_29,
PROP_BLOOM_SIZE = PROP_DERIVED_30,
PROP_FLYING_ALLOWED = PROP_DERIVED_31,
PROP_GHOSTING_ALLOWED = PROP_DERIVED_32,
PROP_FILTER_URL = PROP_DERIVED_33,
// Avatar priority
PROP_AVATAR_PRIORITY = PROP_DERIVED_34,
// Screen-sharing
@ -324,6 +341,22 @@ enum EntityPropertyList {
PROP_REVERB_WET_LEVEL = PROP_DERIVED_38,
PROP_LISTENER_ZONES = PROP_DERIVED_39,
PROP_LISTENER_ATTENUATION_COEFFICIENTS = PROP_DERIVED_40,
// Tonemapping
PROP_TONEMAPPING_MODE = PROP_DERIVED_41,
PROP_TONEMAPPING_CURVE = PROP_DERIVED_42,
PROP_TONEMAPPING_EXPOSURE = PROP_DERIVED_43,
// Ambient Occlusion
PROP_AMBIENT_OCCLUSION_MODE = PROP_DERIVED_44,
PROP_AMBIENT_OCCLUSION_TECHNIQUE = PROP_DERIVED_45,
PROP_AMBIENT_OCCLUSION_JITTER = PROP_DERIVED_46,
PROP_AMBIENT_OCCLUSION_RESOLUTION_LEVEL = PROP_DERIVED_47,
PROP_AMBIENT_OCCLUSION_EDGE_SHARPNESS = PROP_DERIVED_48,
PROP_AMBIENT_OCCLUSION_BLUR_RADIUS = PROP_DERIVED_49,
PROP_AMBIENT_OCCLUSION_AO_RADIUS = PROP_DERIVED_50,
PROP_AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL = PROP_DERIVED_51,
PROP_AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE = PROP_DERIVED_52,
PROP_AMBIENT_OCCLUSION_AO_NUM_SAMPLES = PROP_DERIVED_53,
PROP_AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS = PROP_DERIVED_54,
// Polyvox
PROP_VOXEL_VOLUME_SIZE = PROP_DERIVED_0,

View file

@ -0,0 +1,167 @@
//
// TonemappingPropertyGroup.cpp
// libraries/entities/src
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
#include "TonemappingPropertyGroup.h"
#include <OctreePacketData.h>
#include "EntityItemProperties.h"
#include "EntityItemPropertiesMacros.h"
inline void addTonemappingCurve(QHash<QString, TonemappingCurve>& lookup, TonemappingCurve curve) { lookup[TonemappingCurveHelpers::getNameForTonemappingCurve(curve)] = curve; }
const QHash<QString, TonemappingCurve> stringToTonemappingCurveLookup = [] {
QHash<QString, TonemappingCurve> toReturn;
addTonemappingCurve(toReturn, TonemappingCurve::RGB);
addTonemappingCurve(toReturn, TonemappingCurve::SRGB);
addTonemappingCurve(toReturn, TonemappingCurve::FILMIC);
addTonemappingCurve(toReturn, TonemappingCurve::REINHARD);
return toReturn;
}();
QString TonemappingPropertyGroup::getCurveAsString() const { return TonemappingCurveHelpers::getNameForTonemappingCurve(_curve); }
void TonemappingPropertyGroup::setCurveFromString(const QString& curve) {
auto curveItr = stringToTonemappingCurveLookup.find(curve.toLower());
if (curveItr != stringToTonemappingCurveLookup.end()) {
_curve = curveItr.value();
_curveChanged = true;
}
}
void TonemappingPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine,
bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TONEMAPPING_CURVE, Tonemapping, tonemapping, Curve, curve, getCurveAsString);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_TONEMAPPING_EXPOSURE, Tonemapping, tonemapping, Exposure, exposure);
}
void TonemappingPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(tonemapping, curve, Curve);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(tonemapping, exposure, float, setExposure);
}
void TonemappingPropertyGroup::merge(const TonemappingPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(curve);
COPY_PROPERTY_IF_CHANGED(exposure);
}
void TonemappingPropertyGroup::debugDump() const {
qCDebug(entities) << " TonemappingPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " Curve:" << getCurveAsString();
qCDebug(entities) << " Exposure:" << getExposure();
}
void TonemappingPropertyGroup::listChangedProperties(QList<QString>& out) {
if (curveChanged()) {
out << "tonemapping-curve";
}
if (exposureChanged()) {
out << "tonemapping-exposure";
}
}
bool TonemappingPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_TONEMAPPING_CURVE, (uint32_t)getCurve());
APPEND_ENTITY_PROPERTY(PROP_TONEMAPPING_EXPOSURE, getExposure());
return true;
}
bool TonemappingPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0;
bool overwriteLocalData = true;
bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_TONEMAPPING_CURVE, TonemappingCurve, setCurve);
READ_ENTITY_PROPERTY(PROP_TONEMAPPING_EXPOSURE, float, setExposure);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_TONEMAPPING_CURVE, Curve);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_TONEMAPPING_EXPOSURE, Exposure);
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}
void TonemappingPropertyGroup::markAllChanged() {
_curveChanged = true;
_exposureChanged = true;
}
EntityPropertyFlags TonemappingPropertyGroup::getChangedProperties() const {
EntityPropertyFlags changedProperties;
CHECK_PROPERTY_CHANGE(PROP_TONEMAPPING_CURVE, curve);
CHECK_PROPERTY_CHANGE(PROP_TONEMAPPING_EXPOSURE, exposure);
return changedProperties;
}
void TonemappingPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Tonemapping, Curve, getCurve);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Tonemapping, Exposure, getExposure);
}
bool TonemappingPropertyGroup::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Tonemapping, Curve, curve, setCurve);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Tonemapping, Exposure, exposure, setExposure);
return somethingChanged;
}
EntityPropertyFlags TonemappingPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_TONEMAPPING_CURVE;
requestedProperties += PROP_TONEMAPPING_EXPOSURE;
return requestedProperties;
}
void TonemappingPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_TONEMAPPING_CURVE, (uint32_t)getCurve());
APPEND_ENTITY_PROPERTY(PROP_TONEMAPPING_EXPOSURE, getExposure());
}
int TonemappingPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_TONEMAPPING_CURVE, TonemappingCurve, setCurve);
READ_ENTITY_PROPERTY(PROP_TONEMAPPING_EXPOSURE, float, setExposure);
return bytesRead;
}

View file

@ -0,0 +1,87 @@
//
// TonemappingPropertyGroup.h
// libraries/entities/src
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
#ifndef hifi_TonemappingPropertyGroup_h
#define hifi_TonemappingPropertyGroup_h
#include <TonemappingCurve.h>
#include "PropertyGroup.h"
#include "EntityItemPropertiesMacros.h"
class EntityItemProperties;
class EncodeBitstreamParams;
class OctreePacketData;
class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams;
class ScriptEngine;
class ScriptValue;
/*@jsdoc
* Tonemapping is defined by the following properties:
* @typedef {object} Entities.Tonemapping
* @property {TonemappingCurve} curve="srgb" - The tonemapping curve used.
* @property {number} exposure=0.0 - The applied exposure.
*/
class TonemappingPropertyGroup : public PropertyGroup {
public:
// EntityItemProperty related helpers
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties,
ScriptEngine* engine, bool skipDefaults,
EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags,
bool isMyOwnAvatarEntity) const override;
virtual void copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, bool& _defaultSettings) override;
void merge(const TonemappingPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
DEFINE_PROPERTY_REF_ENUM(PROP_TONEMAPPING_CURVE, Curve, curve, TonemappingCurve, TonemappingCurve::SRGB);
DEFINE_PROPERTY(PROP_TONEMAPPING_EXPOSURE, Exposure, exposure, float, 0.0);
};
#endif // hifi_TonemappingPropertyGroup_h

View file

@ -61,6 +61,8 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de
_hazeProperties.getProperties(properties);
_bloomProperties.getProperties(properties);
_audioProperties.getProperties(properties);
_tonemappingProperties.getProperties(properties);
_ambientOcclusionProperties.getProperties(properties);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed);
@ -73,6 +75,8 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de
COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(avatarPriority, getAvatarPriority);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(screenshare, getScreenshare);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(tonemappingMode, getTonemappingMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientOcclusionMode, getAmbientOcclusionMode);
return properties;
}
@ -92,6 +96,8 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
_hazePropertiesChanged |= _hazeProperties.setProperties(properties);
_bloomPropertiesChanged |= _bloomProperties.setProperties(properties);
bool audioPropertiesChanged = _audioProperties.setProperties(properties);
_tonemappingPropertiesChanged |= _tonemappingProperties.setProperties(properties);
_ambientOcclusionPropertiesChanged |= _ambientOcclusionProperties.setProperties(properties);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
@ -104,9 +110,12 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(screenshare, setScreenshare);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(tonemappingMode, setTonemappingMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientOcclusionMode, setAmbientOcclusionMode);
somethingChanged |= _keyLightPropertiesChanged || _ambientLightPropertiesChanged || _skyboxPropertiesChanged ||
_hazePropertiesChanged || _bloomPropertiesChanged || audioPropertiesChanged;
_hazePropertiesChanged || _bloomPropertiesChanged || audioPropertiesChanged ||
_tonemappingPropertiesChanged || _ambientOcclusionPropertiesChanged;
return somethingChanged;
}
@ -177,6 +186,20 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
dataAt += bytesFromAudio;
}
{
int bytesFromTonemapping = _tonemappingProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, somethingChanged);
bytesRead += bytesFromTonemapping;
dataAt += bytesFromTonemapping;
}
{
int bytesFromAmbientOcclusion = _ambientOcclusionProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, somethingChanged);
bytesRead += bytesFromAmbientOcclusion;
dataAt += bytesFromAmbientOcclusion;
}
READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL);
@ -188,6 +211,8 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode);
READ_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, uint32_t, setAvatarPriority);
READ_ENTITY_PROPERTY(PROP_SCREENSHARE, uint32_t, setScreenshare);
READ_ENTITY_PROPERTY(PROP_TONEMAPPING_MODE, uint32_t, setTonemappingMode);
READ_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_MODE, uint32_t, setAmbientOcclusionMode);
return bytesRead;
}
@ -204,6 +229,8 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
requestedProperties += _hazeProperties.getEntityProperties(params);
requestedProperties += _bloomProperties.getEntityProperties(params);
requestedProperties += _audioProperties.getEntityProperties(params);
requestedProperties += _tonemappingProperties.getEntityProperties(params);
requestedProperties += _ambientOcclusionProperties.getEntityProperties(params);
requestedProperties += PROP_FLYING_ALLOWED;
requestedProperties += PROP_GHOSTING_ALLOWED;
@ -216,6 +243,8 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
requestedProperties += PROP_SKYBOX_MODE;
requestedProperties += PROP_HAZE_MODE;
requestedProperties += PROP_BLOOM_MODE;
requestedProperties += PROP_TONEMAPPING_MODE;
requestedProperties += PROP_AMBIENT_OCCLUSION_MODE;
return requestedProperties;
}
@ -247,32 +276,40 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_audioProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_tonemappingProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_ambientOcclusionProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL());
APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode());
APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode());
APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, getKeyLightMode());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, getAmbientLightMode());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, getSkyboxMode());
APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, getHazeMode());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, getBloomMode());
APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, getAvatarPriority());
APPEND_ENTITY_PROPERTY(PROP_SCREENSHARE, getScreenshare());
APPEND_ENTITY_PROPERTY(PROP_TONEMAPPING_MODE, getHazeMode());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_OCCLUSION_MODE, getBloomMode());
}
void ZoneEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeAsString(_hazeMode);
qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeAsString(_keyLightMode);
qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeAsString(_ambientLightMode);
qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeAsString(_skyboxMode);
qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeAsString(_bloomMode);
qCDebug(entities) << " _avatarPriority:" << getAvatarPriority();
qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeAsString(_hazeMode);
qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeAsString(_keyLightMode);
qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeAsString(_ambientLightMode);
qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeAsString(_skyboxMode);
qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeAsString(_bloomMode);
qCDebug(entities) << " _avatarPriority:" << getAvatarPriority();
qCDebug(entities) << " _tonemappingMode:" << EntityItemProperties::getComponentModeAsString(_tonemappingMode);
qCDebug(entities) << " _ambientOcclusionMode:" << EntityItemProperties::getComponentModeAsString(_ambientOcclusionMode);
_keyLightProperties.debugDump();
_ambientLightProperties.debugDump();
@ -280,6 +317,8 @@ void ZoneEntityItem::debugDump() const {
_hazeProperties.debugDump();
_bloomProperties.debugDump();
_audioProperties.debugDump();
_tonemappingProperties.debugDump();
_ambientOcclusionProperties.debugDump();
}
void ZoneEntityItem::setShapeType(ShapeType type) {
@ -408,53 +447,11 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() {
_skyboxPropertiesChanged = false;
_hazePropertiesChanged = false;
_bloomPropertiesChanged = false;
_tonemappingPropertiesChanged = false;
_ambientOcclusionPropertiesChanged = false;
});
}
void ZoneEntityItem::setHazeMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _hazeMode) {
_hazeMode = value;
_hazePropertiesChanged = true;
}
}
uint32_t ZoneEntityItem::getHazeMode() const {
return _hazeMode;
}
void ZoneEntityItem::setBloomMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) {
_bloomMode = value;
_bloomPropertiesChanged = true;
}
}
uint32_t ZoneEntityItem::getBloomMode() const {
return _bloomMode;
}
void ZoneEntityItem::setKeyLightMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) {
_keyLightMode = value;
_keyLightPropertiesChanged = true;
}
}
uint32_t ZoneEntityItem::getKeyLightMode() const {
return _keyLightMode;
}
void ZoneEntityItem::setAmbientLightMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _ambientLightMode) {
_ambientLightMode = value;
_ambientLightPropertiesChanged = true;
}
}
uint32_t ZoneEntityItem::getAmbientLightMode() const {
return _ambientLightMode;
}
void ZoneEntityItem::setSkyboxMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _skyboxMode) {
_skyboxMode = value;
@ -462,8 +459,46 @@ void ZoneEntityItem::setSkyboxMode(const uint32_t value) {
}
}
uint32_t ZoneEntityItem::getSkyboxMode() const {
return _skyboxMode;
void ZoneEntityItem::setKeyLightMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) {
_keyLightMode = value;
_keyLightPropertiesChanged = true;
}
}
void ZoneEntityItem::setAmbientLightMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _ambientLightMode) {
_ambientLightMode = value;
_ambientLightPropertiesChanged = true;
}
}
void ZoneEntityItem::setHazeMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _hazeMode) {
_hazeMode = value;
_hazePropertiesChanged = true;
}
}
void ZoneEntityItem::setBloomMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) {
_bloomMode = value;
_bloomPropertiesChanged = true;
}
}
void ZoneEntityItem::setTonemappingMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _tonemappingMode) {
_tonemappingMode = value;
_tonemappingPropertiesChanged = true;
}
}
void ZoneEntityItem::setAmbientOcclusionMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _ambientOcclusionMode) {
_ambientOcclusionMode = value;
_ambientOcclusionPropertiesChanged = true;
}
}
void ZoneEntityItem::setUserData(const QString& value) {

View file

@ -23,6 +23,8 @@
#include "HazePropertyGroup.h"
#include "BloomPropertyGroup.h"
#include "ZoneAudioPropertyGroup.h"
#include "TonemappingPropertyGroup.h"
#include "AmbientOcclusionPropertyGroup.h"
class ZoneEntityItem : public EntityItem {
public:
@ -68,36 +70,20 @@ public:
virtual bool matchesJSONFilters(const QJsonObject& jsonFilters) const override;
KeyLightPropertyGroup getKeyLightProperties() const { return resultWithReadLock<KeyLightPropertyGroup>([&] { return _keyLightProperties; }); }
AmbientLightPropertyGroup getAmbientLightProperties() const { return resultWithReadLock<AmbientLightPropertyGroup>([&] { return _ambientLightProperties; }); }
void setHazeMode(const uint32_t value);
uint32_t getHazeMode() const;
void setSkyboxMode(uint32_t value);
uint32_t getSkyboxMode() const { return _skyboxMode; }
void setKeyLightMode(uint32_t value);
uint32_t getKeyLightMode() const;
uint32_t getKeyLightMode() const { return _keyLightMode; }
void setAmbientLightMode(uint32_t value);
uint32_t getAmbientLightMode() const;
uint32_t getAmbientLightMode() const { return _ambientLightMode; }
void setSkyboxMode(uint32_t value);
uint32_t getSkyboxMode() const;
void setHazeMode(const uint32_t value);
uint32_t getHazeMode() const { return _hazeMode; }
void setBloomMode(const uint32_t value);
uint32_t getBloomMode() const;
SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock<SkyboxPropertyGroup>([&] { return _skyboxProperties; }); }
const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; }
const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; }
const ZoneAudioPropertyGroup& getAudioProperties() const { return _audioProperties; }
bool getFlyingAllowed() const { return _flyingAllowed; }
void setFlyingAllowed(bool value) { _flyingAllowed = value; }
bool getGhostingAllowed() const { return _ghostingAllowed; }
void setGhostingAllowed(bool value) { _ghostingAllowed = value; }
QString getFilterURL() const;
void setFilterURL(const QString url);
uint32_t getBloomMode() const { return _bloomMode; }
uint32_t getAvatarPriority() const { return _avatarPriority; }
void setAvatarPriority(uint32_t value) { _avatarPriority = value; }
@ -105,6 +91,28 @@ public:
uint32_t getScreenshare() const { return _screenshare; }
void setScreenshare(uint32_t value) { _screenshare = value; }
void setTonemappingMode(uint32_t value);
uint32_t getTonemappingMode() const { return _tonemappingMode; }
void setAmbientOcclusionMode(const uint32_t value);
uint32_t getAmbientOcclusionMode() const { return _ambientOcclusionMode; }
SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock<SkyboxPropertyGroup>([&] { return _skyboxProperties; }); }
KeyLightPropertyGroup getKeyLightProperties() const { return resultWithReadLock<KeyLightPropertyGroup>([&] { return _keyLightProperties; }); }
AmbientLightPropertyGroup getAmbientLightProperties() const { return resultWithReadLock<AmbientLightPropertyGroup>([&] { return _ambientLightProperties; }); }
const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; }
const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; }
const ZoneAudioPropertyGroup& getAudioProperties() const { return _audioProperties; }
const TonemappingPropertyGroup& getTonemappingProperties() const { return _tonemappingProperties; }
const AmbientOcclusionPropertyGroup& getAmbientOcclusionProperties() const { return _ambientOcclusionProperties; }
bool getFlyingAllowed() const { return _flyingAllowed; }
void setFlyingAllowed(bool value) { _flyingAllowed = value; }
bool getGhostingAllowed() const { return _ghostingAllowed; }
void setGhostingAllowed(bool value) { _ghostingAllowed = value; }
QString getFilterURL() const;
void setFilterURL(const QString url);
void setUserData(const QString& value) override;
bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
@ -112,6 +120,8 @@ public:
bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }
bool hazePropertiesChanged() const { return _hazePropertiesChanged; }
bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; }
bool tonemappingPropertiesChanged() const { return _tonemappingPropertiesChanged; }
bool ambientOcclusionPropertiesChanged() const { return _ambientOcclusionPropertiesChanged; }
void resetRenderingPropertiesChanged();
@ -142,35 +152,35 @@ protected:
ShapeType _shapeType { DEFAULT_SHAPE_TYPE };
QString _compoundShapeURL;
// The following 3 values are the defaults for zone creation
uint32_t _keyLightMode { COMPONENT_MODE_INHERIT };
uint32_t _skyboxMode { COMPONENT_MODE_INHERIT };
uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT };
uint32_t _hazeMode { COMPONENT_MODE_INHERIT };
uint32_t _bloomMode { COMPONENT_MODE_INHERIT };
uint32_t _avatarPriority { COMPONENT_MODE_INHERIT };
uint32_t _screenshare { COMPONENT_MODE_INHERIT };
uint32_t _tonemappingMode { COMPONENT_MODE_INHERIT };
uint32_t _ambientOcclusionMode { COMPONENT_MODE_INHERIT };
SkyboxPropertyGroup _skyboxProperties;
HazePropertyGroup _hazeProperties;
BloomPropertyGroup _bloomProperties;
ZoneAudioPropertyGroup _audioProperties;
TonemappingPropertyGroup _tonemappingProperties;
AmbientOcclusionPropertyGroup _ambientOcclusionProperties;
bool _flyingAllowed { DEFAULT_FLYING_ALLOWED };
bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
QString _filterURL { DEFAULT_FILTER_URL };
// Avatar-updates priority
uint32_t _avatarPriority { COMPONENT_MODE_INHERIT };
// Screen-sharing zone
uint32_t _screenshare { COMPONENT_MODE_INHERIT };
// Dirty flags turn true when either keylight properties is changing values.
bool _keyLightPropertiesChanged { false };
bool _ambientLightPropertiesChanged { false };
bool _skyboxPropertiesChanged { false };
bool _hazePropertiesChanged { false };
bool _bloomPropertiesChanged { false };
bool _tonemappingPropertiesChanged { false };
bool _ambientOcclusionPropertiesChanged { false };
static bool _drawZoneBoundaries;
static bool _zonesArePickable;

View file

@ -0,0 +1,59 @@
//
// AmbientOcclusion.h
// libraries/graphics/src/graphics
//
// Created by HifiExperiments 6/24/24
// Copyright 2024 Overte e.V.
//
// 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_model_AmbientOcclusion_h
#define hifi_model_AmbientOcclusion_h
#include <memory>
#include <AmbientOcclusionTechnique.h>
namespace graphics {
class AmbientOcclusion {
public:
AmbientOcclusion() {}
void setTechnique(const AmbientOcclusionTechnique technique) { _technique = technique; }
void setJitter(const bool jitter) { _jitter = jitter; }
void setResolutionLevel(const uint8_t resolutionLevel) { _resolutionLevel = resolutionLevel; }
void setEdgeSharpness(const float edgeSharpness) { _edgeSharpness = edgeSharpness; }
void setBlurRadius(const uint8_t blurRadius) { _blurRadius = blurRadius; }
void setAORadius(const float aoRadius) { _aoRadius = aoRadius; }
void setAOObscuranceLevel(const float aoObscuranceLevel) { _aoObscuranceLevel = aoObscuranceLevel; }
void setAOFalloffAngle(const float aoFalloffAngle) { _aoFalloffAngle = aoFalloffAngle; }
void setAONumSamples(const uint8_t aoNumSamples) { _aoNumSamples = aoNumSamples; }
void setSSAONumSpiralTurns(const float ssaoNumSpiralTurns) { _ssaoNumSpiralTurns = ssaoNumSpiralTurns; }
AmbientOcclusionTechnique getTechnique() const { return _technique; }
bool getJitter() const { return _jitter; }
uint8_t getResolutionLevel() const { return _resolutionLevel; }
float getEdgeSharpness() const { return _edgeSharpness; }
uint8_t getBlurRadius() const { return _blurRadius; }
float getAORadius() const { return _aoRadius; }
float getAOObscuranceLevel() const { return _aoObscuranceLevel; }
float getAOFalloffAngle() const { return _aoFalloffAngle; }
uint8_t getAONumSamples() const { return _aoNumSamples; }
float getSSAONumSpiralTurns() const { return _ssaoNumSpiralTurns; }
private:
AmbientOcclusionTechnique _technique { AmbientOcclusionTechnique::SSAO };
bool _jitter { false };
uint8_t _resolutionLevel { 2 };
float _edgeSharpness { 1.0f };
uint8_t _blurRadius { 4 };
float _aoRadius { 1.0f };
float _aoObscuranceLevel { 0.5f };
float _aoFalloffAngle { 0.25f };
uint8_t _aoNumSamples { 32 };
float _ssaoNumSpiralTurns { 7.0f };
};
using AmbientOcclusionPointer = std::shared_ptr<AmbientOcclusion>;
}
#endif // hifi_model_AmbientOcclusion_h

View file

@ -0,0 +1,35 @@
//
// Tonemapping.h
// libraries/graphics/src/graphics
//
// Created by HifiExperiments on 6/24/24
// Copyright 2024 Overte e.V.
//
// 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_model_Tonemapping_h
#define hifi_model_Tonemapping_h
#include <memory>
#include <TonemappingCurve.h>
namespace graphics {
class Tonemapping {
public:
Tonemapping() {}
void setCurve(const TonemappingCurve curve) { _curve = curve; }
void setExposure(const float exposure) { _exposure = exposure; }
TonemappingCurve getCurve() const { return _curve; }
float getExposure() const { return _exposure; }
private:
TonemappingCurve _curve { TonemappingCurve::SRGB };
float _exposure { 0.0f };
};
using TonemappingPointer = std::shared_ptr<Tonemapping>;
}
#endif // hifi_model_Tonemapping_h

View file

@ -298,6 +298,7 @@ enum class EntityVersion : PacketVersion {
ProceduralParticles,
ShapeUnlit,
AmbientColor,
TonemappingAndAmbientOcclusion,
// Add new versions above here
NUM_PACKET_TYPE,

View file

@ -43,6 +43,8 @@
#include "TextEffect.h"
#include "TextAlignment.h"
#include "MirrorMode.h"
#include "TonemappingCurve.h"
#include "AmbientOcclusionTechnique.h"
#include "OctreeConstants.h"
#include "OctreeElement.h"
@ -285,6 +287,8 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, TextEffect& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, TextAlignment& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, MirrorMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, TonemappingCurve& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, AmbientOcclusionTechnique& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result);

View file

@ -21,6 +21,7 @@
#include "DeferredFrameTransform.h"
#include "DeferredFramebuffer.h"
#include "SurfaceGeometryPass.h"
#include "AmbientOcclusionStage.h"
#include "ssao_shared.h"
@ -153,7 +154,8 @@ signals:
class AmbientOcclusionEffect {
public:
using Input = render::VaryingSet4<LightingModelPointer, DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer>;
using Input = render::VaryingSet5<LightingModelPointer, DeferredFrameTransformPointer, DeferredFramebufferPointer,
LinearDepthFramebufferPointer, AmbientOcclusionStage::FramePointer>;
using Output = render::VaryingSet2<AmbientOcclusionFramebufferPointer, gpu::BufferView>;
using Config = AmbientOcclusionEffectConfig;
using JobModel = render::Job::ModelIO<AmbientOcclusionEffect, Input, Output, Config>;

View file

@ -0,0 +1,56 @@
//
// AmbientOcclusionStage.cpp
//
// Created by HifiExperiments on 6/24/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AmbientOcclusionStage.h"
#include <gpu/Context.h>
std::string AmbientOcclusionStage::_stageName { "BLOOM_STAGE"};
const AmbientOcclusionStage::Index AmbientOcclusionStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
AmbientOcclusionStage::Index AmbientOcclusionStage::findAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) const {
auto found = _ambientOcclusionMap.find(ambientOcclusion);
if (found != _ambientOcclusionMap.end()) {
return INVALID_INDEX;
} else {
return (*found).second;
}
}
AmbientOcclusionStage::Index AmbientOcclusionStage::addAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) {
auto found = _ambientOcclusionMap.find(ambientOcclusion);
if (found == _ambientOcclusionMap.end()) {
auto ambientOcclusionId = _ambientOcclusions.newElement(ambientOcclusion);
// Avoid failing to allocate a ambientOcclusion, just pass
if (ambientOcclusionId != INVALID_INDEX) {
// Insert the ambientOcclusion and its index in the reverse map
_ambientOcclusionMap.insert(AmbientOcclusionMap::value_type(ambientOcclusion, ambientOcclusionId));
}
return ambientOcclusionId;
} else {
return (*found).second;
}
}
AmbientOcclusionStage::AmbientOcclusionPointer AmbientOcclusionStage::removeAmbientOcclusion(Index index) {
AmbientOcclusionPointer removed = _ambientOcclusions.freeElement(index);
if (removed) {
_ambientOcclusionMap.erase(removed);
}
return removed;
}
AmbientOcclusionStageSetup::AmbientOcclusionStageSetup() {}
void AmbientOcclusionStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(AmbientOcclusionStage::getName());
if (!stage) {
renderContext->_scene->resetStage(AmbientOcclusionStage::getName(), std::make_shared<AmbientOcclusionStage>());
}
}

View file

@ -0,0 +1,84 @@
//
// AmbientOcclusionStage.h
//
// Created by HifiExperiments on 6/24/24
// Copyright 2024 Overte e.V.
//
// 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_AmbientOcclusionStage_h
#define hifi_render_utils_AmbientOcclusionStage_h
#include <graphics/Stage.h>
#include <set>
#include <unordered_map>
#include <render/IndexedContainer.h>
#include <render/Stage.h>
#include <render/Forward.h>
#include <render/DrawTask.h>
#include <graphics/AmbientOcclusion.h>
// AmbientOcclusion stage to set up ambientOcclusion-related rendering tasks
class AmbientOcclusionStage : public render::Stage {
public:
static std::string _stageName;
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
static const Index INVALID_INDEX;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using AmbientOcclusionPointer = graphics::AmbientOcclusionPointer;
using AmbientOcclusions = render::indexed_container::IndexedPointerVector<graphics::AmbientOcclusion>;
using AmbientOcclusionMap = std::unordered_map<AmbientOcclusionPointer, Index>;
using AmbientOcclusionIndices = std::vector<Index>;
Index findAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) const;
Index addAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion);
AmbientOcclusionPointer removeAmbientOcclusion(Index index);
bool checkAmbientOcclusionId(Index index) const { return _ambientOcclusions.checkIndex(index); }
Index getNumAmbientOcclusions() const { return _ambientOcclusions.getNumElements(); }
Index getNumFreeAmbientOcclusions() const { return _ambientOcclusions.getNumFreeIndices(); }
Index getNumAllocatedAmbientOcclusions() const { return _ambientOcclusions.getNumAllocatedIndices(); }
AmbientOcclusionPointer getAmbientOcclusion(Index ambientOcclusionId) const {
return _ambientOcclusions.get(ambientOcclusionId);
}
AmbientOcclusions _ambientOcclusions;
AmbientOcclusionMap _ambientOcclusionMap;
class Frame {
public:
Frame() {}
void clear() { _ambientOcclusions.clear(); }
void pushAmbientOcclusion(AmbientOcclusionStage::Index index) { _ambientOcclusions.emplace_back(index); }
AmbientOcclusionStage::AmbientOcclusionIndices _ambientOcclusions;
};
using FramePointer = std::shared_ptr<Frame>;
Frame _currentFrame;
};
using AmbientOcclusionStagePointer = std::shared_ptr<AmbientOcclusionStage>;
class AmbientOcclusionStageSetup {
public:
using JobModel = render::Job::Model<AmbientOcclusionStageSetup>;
AmbientOcclusionStageSetup();
void run(const render::RenderContextPointer& renderContext);
protected:
};
#endif

View file

@ -25,6 +25,14 @@ void FetchCurrentFrames::run(const render::RenderContextPointer& renderContext,
auto bloomStage = renderContext->_scene->getStage<BloomStage>();
assert(bloomStage);
output.edit3() = std::make_shared<BloomStage::Frame>(bloomStage->_currentFrame);
auto tonemappingStage = renderContext->_scene->getStage<TonemappingStage>();
assert(tonemappingStage);
output.edit4() = std::make_shared<TonemappingStage::Frame>(tonemappingStage->_currentFrame);
auto ambientOcclusionStage = renderContext->_scene->getStage<AmbientOcclusionStage>();
assert(ambientOcclusionStage);
output.edit5() = std::make_shared<AmbientOcclusionStage::Frame>(ambientOcclusionStage->_currentFrame);
}
@ -47,4 +55,3 @@ void AssembleLightingStageTask::build(JobModel& task, const render::Varying& inp
output = Output(currentStageFrames, zones);
}

View file

@ -16,13 +16,16 @@
#include "BackgroundStage.h"
#include "HazeStage.h"
#include "BloomStage.h"
#include "TonemappingStage.h"
#include "AmbientOcclusionStage.h"
#include "ZoneRenderer.h"
class FetchCurrentFrames {
public:
using Output = render::VaryingSet4<LightStage::FramePointer, BackgroundStage::FramePointer, HazeStage::FramePointer, BloomStage::FramePointer>;
using Output = render::VaryingSet6<LightStage::FramePointer, BackgroundStage::FramePointer, HazeStage::FramePointer,
BloomStage::FramePointer, TonemappingStage::FramePointer, AmbientOcclusionStage::FramePointer>;
using JobModel = render::Job::ModelO<FetchCurrentFrames, Output>;
FetchCurrentFrames() {}

View file

@ -81,26 +81,4 @@ public:
protected:
};
class FetchBloomConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(float bloomIntensity MEMBER bloomIntensity WRITE setBloomIntensity NOTIFY dirty);
Q_PROPERTY(float bloomThreshold MEMBER bloomThreshold WRITE setBloomThreshold NOTIFY dirty);
Q_PROPERTY(float bloomSize MEMBER bloomSize WRITE setBloomSize NOTIFY dirty);
public:
FetchBloomConfig() : render::Job::Config() {}
float bloomIntensity { graphics::Bloom::INITIAL_BLOOM_INTENSITY };
float bloomThreshold { graphics::Bloom::INITIAL_BLOOM_THRESHOLD };
float bloomSize { graphics::Bloom::INITIAL_BLOOM_SIZE };
public slots:
void setBloomIntensity(const float value) { bloomIntensity = value; emit dirty(); }
void setBloomThreshold(const float value) { bloomThreshold = value; emit dirty(); }
void setBloomSize(const float value) { bloomSize = value; emit dirty(); }
signals:
void dirty();
};
#endif

View file

@ -662,5 +662,24 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) {
_defaultHazeID = hazeStage->addHaze(_defaultHaze);
}
}
}
if (!_defaultTonemapping) {
auto tonemappingStage = renderContext->_scene->getStage<TonemappingStage>();
if (tonemappingStage) {
auto tonemapping = std::make_shared<graphics::Tonemapping>();
_defaultTonemapping = tonemapping;
_defaultTonemappingID = tonemappingStage->addTonemapping(_defaultTonemapping);
}
}
if (!_defaultAmbientOcclusion) {
auto ambientOcclusionStage = renderContext->_scene->getStage<AmbientOcclusionStage>();
if (ambientOcclusionStage) {
auto ambientOcclusion = std::make_shared<graphics::AmbientOcclusion>();
_defaultAmbientOcclusion = ambientOcclusion;
_defaultAmbientOcclusionID = ambientOcclusionStage->addAmbientOcclusion(_defaultAmbientOcclusion);
}
}
}

View file

@ -32,6 +32,7 @@
#include "LightClusters.h"
#include "BackgroundStage.h"
#include "HazeStage.h"
#include "TonemappingStage.h"
#include "SurfaceGeometryPass.h"
#include "SubsurfaceScattering.h"
@ -162,11 +163,15 @@ public:
protected:
graphics::LightPointer _defaultLight;
LightStage::Index _defaultLightID{ LightStage::INVALID_INDEX };
LightStage::Index _defaultLightID { LightStage::INVALID_INDEX };
graphics::SunSkyStagePointer _defaultBackground;
BackgroundStage::Index _defaultBackgroundID{ BackgroundStage::INVALID_INDEX };
graphics::HazePointer _defaultHaze{ nullptr };
HazeStage::Index _defaultHazeID{ HazeStage::INVALID_INDEX };
BackgroundStage::Index _defaultBackgroundID { BackgroundStage::INVALID_INDEX };
graphics::HazePointer _defaultHaze { nullptr };
HazeStage::Index _defaultHazeID { HazeStage::INVALID_INDEX };
graphics::TonemappingPointer _defaultTonemapping { nullptr };
TonemappingStage::Index _defaultTonemappingID { TonemappingStage::INVALID_INDEX };
graphics::AmbientOcclusionPointer _defaultAmbientOcclusion { nullptr };
AmbientOcclusionStage::Index _defaultAmbientOcclusionID { AmbientOcclusionStage::INVALID_INDEX };
graphics::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
NetworkTexturePointer _defaultSkyboxNetworkTexture;
NetworkTexturePointer _defaultAmbientNetworkTexture;

View file

@ -137,6 +137,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto backgroundFrame = currentStageFrames[1];
const auto& hazeFrame = currentStageFrames[2];
const auto& bloomFrame = currentStageFrames[3];
const auto& tonemappingFrame = currentStageFrames[4];
const auto& ambientOcclusionFrame = currentStageFrames[5];
// Shadow Task Outputs
const auto& shadowTaskOutputs = inputs.get3();
@ -198,7 +200,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto scatteringResource = task.addJob<SubsurfaceScattering>("Scattering");
// AO job
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Input(lightingModel, deferredFrameTransform, deferredFramebuffer, linearDepthTarget).asVarying();
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Input(lightingModel, deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionFrame).asVarying();
const auto ambientOcclusionOutputs = task.addJob<AmbientOcclusionEffect>("AmbientOcclusion", ambientOcclusionInputs);
const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Output>(0);
const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Output>(1);
@ -250,8 +252,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto destFramebuffer = static_cast<gpu::FramebufferPointer>(nullptr);
// Lighting Buffer ready for tone mapping
const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying();
const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs, depth);
const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer, tonemappingFrame).asVarying();
const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs);
// Debugging task is happening in the "over" layer after tone mapping and just before HUD
{ // Debug the bounds of the rendered items, still look at the zbuffer

View file

@ -108,6 +108,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
const auto lightFrame = currentStageFrames[0];
const auto backgroundFrame = currentStageFrames[1];
const auto hazeFrame = currentStageFrames[2];
const auto tonemappingFrame = currentStageFrames[4];
const auto& zones = lightingStageInputs[1];
@ -178,8 +179,8 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
const auto destFramebuffer = static_cast<gpu::FramebufferPointer>(nullptr);
const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying();
const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs, depth);
const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer, tonemappingFrame).asVarying();
const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs);
// HUD Layer
const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying();
task.addJob<RenderHUDLayerTask>("RenderHUDLayer", renderHUDLayerInputs);

View file

@ -25,10 +25,9 @@ using namespace shader::render_utils::program;
gpu::PipelinePointer ToneMapAndResample::_pipeline;
gpu::PipelinePointer ToneMapAndResample::_mirrorPipeline;
ToneMapAndResample::ToneMapAndResample(size_t depth) {
ToneMapAndResample::ToneMapAndResample() {
Parameters parameters;
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
_depth = depth;
}
void ToneMapAndResample::init() {
@ -44,13 +43,13 @@ void ToneMapAndResample::init() {
void ToneMapAndResample::setExposure(float exposure) {
auto& params = _parametersBuffer.get<Parameters>();
if (params._exposure != exposure) {
_parametersBuffer.edit<Parameters>()._exposure = exposure;
if (_exposure != exposure) {
_exposure = exposure;
_parametersBuffer.edit<Parameters>()._twoPowExposure = pow(2.0, exposure);
}
}
void ToneMapAndResample::setToneCurve(ToneCurve curve) {
void ToneMapAndResample::setCurve(TonemappingCurve curve) {
auto& params = _parametersBuffer.get<Parameters>();
if (params._toneCurve != (int)curve) {
_parametersBuffer.edit<Parameters>()._toneCurve = (int)curve;
@ -58,8 +57,9 @@ void ToneMapAndResample::setToneCurve(ToneCurve curve) {
}
void ToneMapAndResample::configure(const Config& config) {
setExposure(config.exposure);
setToneCurve((ToneCurve)config.curve);
_debug = config.debug;
_debugExposure = config.exposure;
_debugCurve = (TonemappingCurve)config.curve;
}
void ToneMapAndResample::run(const RenderContextPointer& renderContext, const Input& input, Output& output) {
@ -70,6 +70,21 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In
auto lightingBuffer = input.get0()->getRenderBuffer(0);
auto destinationFramebuffer = input.get1();
const auto tonemappingFrame = input.get2();
const auto& tonemappingStage = renderContext->_scene->getStage<TonemappingStage>();
graphics::TonemappingPointer tonemapping;
if (tonemappingStage && tonemappingFrame->_tonemappings.size()) {
tonemapping = tonemappingStage->getTonemapping(tonemappingFrame->_tonemappings.front());
}
if (_debug) {
setCurve(_debugCurve);
setExposure(_debugExposure);
} else if (tonemapping) {
setCurve(tonemapping->getCurve());
setExposure(tonemapping->getExposure());
}
if (!destinationFramebuffer) {
destinationFramebuffer = args->_blitFramebuffer;

View file

@ -20,28 +20,24 @@
#include <render/Forward.h>
#include <render/DrawTask.h>
enum class ToneCurve {
// Different tone curve available
None,
Gamma22,
Reinhard,
Filmic,
};
#include "TonemappingStage.h"
class ToneMappingConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure);
Q_PROPERTY(int curve MEMBER curve WRITE setCurve);
Q_PROPERTY(bool debug MEMBER debug WRITE setDebug NOTIFY dirty);
Q_PROPERTY(int curve MEMBER curve WRITE setCurve NOTIFY dirty);
Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure NOTIFY dirty);
public:
ToneMappingConfig() : render::Job::Config(true) {}
void setDebug(bool newDebug) { debug = newDebug; emit dirty(); }
void setCurve(int newCurve) { curve = std::max(0, std::min((int)TonemappingCurve::FILMIC, newCurve)); emit dirty(); }
void setExposure(float newExposure) { exposure = newExposure; emit dirty(); }
void setCurve(int newCurve) { curve = std::max((int)ToneCurve::None, std::min((int)ToneCurve::Filmic, newCurve)); emit dirty(); }
float exposure{ 0.0f };
int curve{ (int)ToneCurve::Gamma22 };
bool debug { false };
int curve { (int)TonemappingCurve::SRGB };
float exposure { 0.0f };
signals:
void dirty();
@ -49,17 +45,14 @@ signals:
class ToneMapAndResample {
public:
ToneMapAndResample(size_t depth);
ToneMapAndResample();
virtual ~ToneMapAndResample() {}
void setCurve(TonemappingCurve curve);
void setExposure(float exposure);
float getExposure() const { return _parametersBuffer.get<Parameters>()._exposure; }
void setToneCurve(ToneCurve curve);
ToneCurve getToneCurve() const { return (ToneCurve)_parametersBuffer.get<Parameters>()._toneCurve; }
// Inputs: lightingFramebuffer, destinationFramebuffer
using Input = render::VaryingSet2<gpu::FramebufferPointer, gpu::FramebufferPointer>;
// Inputs: lightingFramebuffer, destinationFramebuffer, tonemappingFrame
using Input = render::VaryingSet3<gpu::FramebufferPointer, gpu::FramebufferPointer, TonemappingStage::FramePointer>;
using Output = gpu::FramebufferPointer;
using Config = ToneMappingConfig;
using JobModel = render::Job::ModelIO<ToneMapAndResample, Input, Output, Config>;
@ -73,22 +66,19 @@ protected:
gpu::FramebufferPointer _destinationFrameBuffer;
float _factor { 2.0f };
size_t _depth { 0 };
gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);
private:
gpu::PipelinePointer _blitLightBuffer;
float _exposure { 0.0f };
bool _debug { false };
TonemappingCurve _debugCurve { TonemappingCurve::SRGB };
float _debugExposure { 0.0f };
// Class describing the uniform buffer with all the parameters common to the tone mapping shaders
class Parameters {
public:
float _exposure = 0.0f;
float _twoPowExposure = 1.0f;
glm::vec2 spareA;
int _toneCurve = (int)ToneCurve::Gamma22;
glm::vec3 spareB;
int _toneCurve = (int)TonemappingCurve::SRGB;
Parameters() {}
};

View file

@ -0,0 +1,56 @@
//
// TonemappingStage.cpp
//
// Created by HifiExperiments on 6/24/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "TonemappingStage.h"
#include <gpu/Context.h>
std::string TonemappingStage::_stageName { "TONEMAPPING_STAGE"};
const TonemappingStage::Index TonemappingStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
TonemappingStage::Index TonemappingStage::findTonemapping(const TonemappingPointer& tonemapping) const {
auto found = _tonemappingMap.find(tonemapping);
if (found != _tonemappingMap.end()) {
return INVALID_INDEX;
} else {
return (*found).second;
}
}
TonemappingStage::Index TonemappingStage::addTonemapping(const TonemappingPointer& tonemapping) {
auto found = _tonemappingMap.find(tonemapping);
if (found == _tonemappingMap.end()) {
auto tonemappingId = _tonemappings.newElement(tonemapping);
// Avoid failing to allocate a tonemapping, just pass
if (tonemappingId != INVALID_INDEX) {
// Insert the tonemapping and its index in the reverse map
_tonemappingMap.insert(TonemappingMap::value_type(tonemapping, tonemappingId));
}
return tonemappingId;
} else {
return (*found).second;
}
}
TonemappingStage::TonemappingPointer TonemappingStage::removeTonemapping(Index index) {
TonemappingPointer removed = _tonemappings.freeElement(index);
if (removed) {
_tonemappingMap.erase(removed);
}
return removed;
}
TonemappingStageSetup::TonemappingStageSetup() {}
void TonemappingStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(TonemappingStage::getName());
if (!stage) {
renderContext->_scene->resetStage(TonemappingStage::getName(), std::make_shared<TonemappingStage>());
}
}

View file

@ -0,0 +1,84 @@
//
// TonemappingStage.h
//
// Created by HifiExperiments on 6/24/24
// Copyright 2024 Overte e.V.
//
// 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_TonemappingStage_h
#define hifi_render_utils_TonemappingStage_h
#include <graphics/Stage.h>
#include <set>
#include <unordered_map>
#include <render/IndexedContainer.h>
#include <render/Stage.h>
#include <render/Forward.h>
#include <render/DrawTask.h>
#include <graphics/Tonemapping.h>
// Tonemapping stage to set up tonemapping-related rendering tasks
class TonemappingStage : public render::Stage {
public:
static std::string _stageName;
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
static const Index INVALID_INDEX;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using TonemappingPointer = graphics::TonemappingPointer;
using Tonemappings = render::indexed_container::IndexedPointerVector<graphics::Tonemapping>;
using TonemappingMap = std::unordered_map<TonemappingPointer, Index>;
using TonemappingIndices = std::vector<Index>;
Index findTonemapping(const TonemappingPointer& tonemapping) const;
Index addTonemapping(const TonemappingPointer& tonemapping);
TonemappingPointer removeTonemapping(Index index);
bool checkTonemappingId(Index index) const { return _tonemappings.checkIndex(index); }
Index getNumTonemappings() const { return _tonemappings.getNumElements(); }
Index getNumFreeTonemappings() const { return _tonemappings.getNumFreeIndices(); }
Index getNumAllocatedTonemappings() const { return _tonemappings.getNumAllocatedIndices(); }
TonemappingPointer getTonemapping(Index tonemappingId) const {
return _tonemappings.get(tonemappingId);
}
Tonemappings _tonemappings;
TonemappingMap _tonemappingMap;
class Frame {
public:
Frame() {}
void clear() { _tonemappings.clear(); }
void pushTonemapping(TonemappingStage::Index index) { _tonemappings.emplace_back(index); }
TonemappingStage::TonemappingIndices _tonemappings;
};
using FramePointer = std::shared_ptr<Frame>;
Frame _currentFrame;
};
using TonemappingStagePointer = std::shared_ptr<TonemappingStage>;
class TonemappingStageSetup {
public:
using JobModel = render::Job::Model<TonemappingStageSetup>;
TonemappingStageSetup();
void run(const render::RenderContextPointer& renderContext);
protected:
};
#endif

View file

@ -15,6 +15,8 @@
#include "BackgroundStage.h"
#include "HazeStage.h"
#include "BloomStage.h"
#include "TonemappingStage.h"
#include "AmbientOcclusionStage.h"
#include <render/TransitionStage.h>
#include <render/HighlightStage.h>
#include "DeferredLightingEffect.h"
@ -24,6 +26,8 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render
task.addJob<BackgroundStageSetup>("BackgroundStageSetup");
task.addJob<HazeStageSetup>("HazeStageSetup");
task.addJob<BloomStageSetup>("BloomStageSetup");
task.addJob<TonemappingStageSetup>("TonemappingStageSetup");
task.addJob<AmbientOcclusionStageSetup>("AmbientOcclusionStageSetup");
task.addJob<render::TransitionStageSetup>("TransitionStageSetup");
task.addJob<render::HighlightStageSetup>("HighlightStageSetup");

View file

@ -26,6 +26,7 @@
#include "DeferredLightingEffect.h"
#include "BloomStage.h"
#include "TonemappingStage.h"
namespace ru {
using render_utils::slot::texture::Texture;
@ -71,6 +72,14 @@ void SetupZones::run(const RenderContextPointer& context, const Input& input) {
assert(bloomStage);
bloomStage->_currentFrame.clear();
auto tonemappingStage = context->_scene->getStage<TonemappingStage>();
assert(tonemappingStage);
tonemappingStage->_currentFrame.clear();
auto ambientOcclusionStage = context->_scene->getStage<AmbientOcclusionStage>();
assert(ambientOcclusionStage);
ambientOcclusionStage->_currentFrame.clear();
// call render over the zones to grab their components in the correct order first...
render::renderItems(context, input);
@ -80,6 +89,8 @@ void SetupZones::run(const RenderContextPointer& context, const Input& input) {
backgroundStage->_currentFrame.pushBackground(0);
hazeStage->_currentFrame.pushHaze(0);
bloomStage->_currentFrame.pushBloom(INVALID_INDEX);
tonemappingStage->_currentFrame.pushTonemapping(0);
ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(0);
}
const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {

View file

@ -16,8 +16,8 @@
<@include render-utils/ShaderConstants.h@>
struct ToneMappingParams {
vec4 _exp_2powExp_s0_s1;
ivec4 _toneCurve_s0_s1_s2;
float _2powExp;
int _toneCurve;
};
const float GAMMA_22 = 2.2;
@ -31,17 +31,17 @@ LAYOUT(binding=RENDER_UTILS_BUFFER_TM_PARAMS) uniform toneMappingParamsBuffer {
ToneMappingParams params;
};
float getTwoPowExposure() {
return params._exp_2powExp_s0_s1.y;
return params._2powExp;
}
int getToneCurve() {
return params._toneCurve_s0_s1_s2.x;
return params._toneCurve;
}
LAYOUT(binding=RENDER_UTILS_TEXTURE_TM_COLOR) uniform sampler2D colorMap;
layout(location=0) in vec2 varTexCoord0;
layout(location=0) out vec4 outFragColor;
void main(void) {
<@if HIFI_USE_MIRRORED@>
vec4 fragColorRaw = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y));

View file

@ -0,0 +1,24 @@
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AmbientOcclusionTechnique.h"
const char* ambientOcclusionTechniqueNames[] = {
"ssao",
"hbao"
};
static const size_t AO_TECHNIQUE_NAMES = (sizeof(ambientOcclusionTechniqueNames) / sizeof(ambientOcclusionTechniqueNames[0]));
QString AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(AmbientOcclusionTechnique technique) {
if (((int)technique <= 0) || ((int)technique >= (int)AO_TECHNIQUE_NAMES)) {
technique = (AmbientOcclusionTechnique)0;
}
return ambientOcclusionTechniqueNames[(int)technique];
}

View file

@ -0,0 +1,38 @@
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// 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_AmbientOcclusionTechnique_h
#define hifi_AmbientOcclusionTechnique_h
#include "QString"
/*@jsdoc
* <p>The technique used for calculating ambient occlusion. Different techniques have different tradeoffs.</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"ssao"</code></td><td>A basic screen-space AO effect.</td></tr>
* <tr><td><code>"hbao"</code></td><td>A form of SSAO that uses the depth buffer for better AO detail, sometimes at the expense of performance.</td></tr>
* </tbody>
* </table>
* @typedef {string} AmbientOcclusionTechnique
*/
enum class AmbientOcclusionTechnique {
SSAO = 0,
HBAO,
};
class AmbientOcclusionTechniqueHelpers {
public:
static QString getNameForAmbientOcclusionTechnique(AmbientOcclusionTechnique curve);
};
#endif // hifi_AmbientOcclusionTechnique_h

View file

@ -0,0 +1,26 @@
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "TonemappingCurve.h"
const char* tonemappingCurveNames[] = {
"rgb",
"srgb",
"reinhard",
"filmic"
};
static const size_t TONEMAPPING_CURVE_NAMES = (sizeof(tonemappingCurveNames) / sizeof(tonemappingCurveNames[0]));
QString TonemappingCurveHelpers::getNameForTonemappingCurve(TonemappingCurve curve) {
if (((int)curve <= 0) || ((int)curve >= (int)TONEMAPPING_CURVE_NAMES)) {
curve = (TonemappingCurve)0;
}
return tonemappingCurveNames[(int)curve];
}

View file

@ -0,0 +1,42 @@
//
// Created by HifiExperiments on 6/23/24
// Copyright 2024 Overte e.V.
//
// 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_TonemappingCurve_h
#define hifi_TonemappingCurve_h
#include "QString"
/*@jsdoc
* <p>The tonemapping curve applied to the final rendering.</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"rgb"</code></td><td>No tonemapping, colors are kept in RGB.</td></tr>
* <tr><td><code>"srgb"</code></td><td>Colors are converted to sRGB.</td></tr>
* <tr><td><code>"reinhard"</code></td><td>Reinhard tonemapping is applied.</td></tr>
* <tr><td><code>"filmic"</code></td><td>Filmic tonemapping is applied.</td></tr>
* </tbody>
* </table>
* @typedef {string} TonemappingCurve
*/
enum class TonemappingCurve {
RGB = 0,
SRGB,
REINHARD,
FILMIC
};
class TonemappingCurveHelpers {
public:
static QString getNameForTonemappingCurve(TonemappingCurve curve);
};
#endif // hifi_TonemappingCurve_h

View file

@ -14,15 +14,11 @@ import "../../lib/prop" as Prop
Column {
anchors.left: parent.left
anchors.right: parent.right
Prop.PropScalar {
label: "Exposure"
anchors.right: parent.right
Prop.PropBool {
label: "Debug"
object: Render.getConfig("RenderMainView.ToneMapping")
property: "exposure"
min: -4
max: 4
anchors.left: parent.left
anchors.right: parent.right
property: "debug"
}
Prop.PropEnum {
label: "Tone Curve"
@ -35,6 +31,15 @@ Column {
"Filmic",
]
anchors.left: parent.left
anchors.right: parent.right
}
anchors.right: parent.right
}
Prop.PropScalar {
label: "Exposure"
object: Render.getConfig("RenderMainView.ToneMapping")
property: "exposure"
min: -4
max: 4
anchors.left: parent.left
anchors.right: parent.right
}
}

View file

@ -165,6 +165,15 @@
"bloom.bloomSize": {
"tooltip": "The radius of bloom. The higher the value, the larger the bloom."
},
"tonemappingMode": {
"tooltip": "Configures the tonemapping applied to the final render."
},
"tonemapping.curve": {
"tooltip": "The tonemapping curve used."
},
"tonemapping.exposure": {
"tooltip": "The exposure used during tonemapping."
},
"audio.reverbEnabled": {
"tooltip": "If reverb should be enabled for listeners in this zone."
},

View file

@ -618,6 +618,54 @@ const GROUPS = [
}
]
},
{
id: "zone_tonemapping",
label: "ZONE TONEMAPPING",
properties: [
{
label: "Tonemapping",
type: "dropdown",
options: { inherit: "Inherit", disabled: "Off", enabled: "On" },
propertyID: "tonemappingMode",
},
{
label: "Curve",
type: "dropdown",
options: { rgb: "RGB", srgb: "sRGB", reinhard: "Reinhard", filmic: "Filmic" },
propertyID: "tonemapping.curve",
showPropertyRule: { "tonemappingMode": "enabled" },
},
{
label: "Exposure",
type: "number-draggable",
min: -4.0,
max: 4.0,
step: 0.1,
decimals: 1,
propertyID: "tonemapping.exposure",
showPropertyRule: { "tonemappingMode": "enabled" },
}
]
},
{
id: "zone_ambient_occlusion",
label: "ZONE AMBIENT OCCLUSION",
properties: [
{
label: "Ambient Occlusion",
type: "dropdown",
options: { inherit: "Inherit", disabled: "Off", enabled: "On" },
propertyID: "ambientOcclusionMode",
},
{
label: "Ambient Occlusion",
type: "dropdown",
options: { ssao: "SSAO", hbao: "HBAO" },
propertyID: "ambientOcclusion.technique",
showPropertyRule: { "tonemappingMode": "enabled" },
}
]
},
{
id: "zone_avatar_priority",
label: "ZONE AVATAR PRIORITY",
@ -1882,8 +1930,9 @@ const GROUPS_PER_TYPE = {
None: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Shape: [ 'base', 'shape', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Text: [ 'base', 'text', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Zone: [ 'base', 'zone', 'zone_key_light', 'zone_skybox', 'zone_ambient_light', 'zone_haze',
'zone_bloom', 'zone_avatar_priority', 'zone_audio', 'spatial', 'behavior', 'scripts', 'physics' ],
Zone: [ 'base', 'zone', 'zone_key_light', 'zone_skybox', 'zone_ambient_light', 'zone_haze',
'zone_bloom', 'zone_tonemapping', 'zone_ambient_occlusion', 'zone_avatar_priority',
'zone_audio', 'spatial', 'behavior', 'scripts', 'physics' ],
Model: [ 'base', 'model', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Image: [ 'base', 'image', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
Web: [ 'base', 'web', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],