From 89e6cbbfa4b05e16589f6034f8be32aa41a0bd0a Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Thu, 3 Mar 2022 22:28:05 -0800 Subject: [PATCH 01/18] mirrors wip --- interface/src/SecondaryCamera.cpp | 3 +- .../scripting/RenderScriptingInterface.cpp | 24 ++- .../src/RenderableEntityItem.cpp | 75 ++++++++++ .../src/RenderableEntityItem.h | 10 +- .../src/RenderableModelEntityItem.cpp | 20 +++ .../src/RenderableModelEntityItem.h | 2 + .../src/RenderableShapeEntityItem.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 36 +++++ libraries/entities/src/EntityItem.h | 9 ++ .../entities/src/EntityItemProperties.cpp | 44 ++++++ libraries/entities/src/EntityItemProperties.h | 3 + libraries/entities/src/EntityPropertyFlags.h | 2 + .../graphics/src/graphics/ShaderConstants.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/octree/src/OctreePacketData.h | 2 + .../render-utils/src/HighlightEffect.cpp | 7 +- .../render-utils/src/MeshPartPayload.cpp | 13 +- libraries/render-utils/src/MeshPartPayload.h | 7 + libraries/render-utils/src/Model.cpp | 45 +++++- libraries/render-utils/src/Model.h | 9 ++ .../render-utils/src/RenderCommonTask.cpp | 137 +++++++++++++++++- libraries/render-utils/src/RenderCommonTask.h | 17 ++- .../render-utils/src/RenderDeferredTask.cpp | 30 ++-- .../render-utils/src/RenderDeferredTask.h | 2 +- .../render-utils/src/RenderForwardTask.cpp | 24 ++- .../render-utils/src/RenderForwardTask.h | 2 +- .../render-utils/src/RenderPipelines.cpp | 40 +++++ .../render-utils/src/RenderShadowTask.cpp | 7 +- libraries/render-utils/src/RenderViewTask.cpp | 14 +- libraries/render-utils/src/RenderViewTask.h | 6 +- libraries/render-utils/src/model.slf | 22 ++- .../render-utils/src/render-utils/model.slp | 2 +- libraries/render/src/render/Item.cpp | 7 + libraries/render/src/render/Item.h | 23 ++- .../src/render/RenderFetchCullSortTask.cpp | 11 +- .../src/render/RenderFetchCullSortTask.h | 1 + libraries/shared/src/MirrorMode.cpp | 25 ++++ libraries/shared/src/MirrorMode.h | 40 +++++ .../create/assets/data/createAppTooltips.json | 12 +- .../html/js/entityProperties.js | 15 ++ 40 files changed, 699 insertions(+), 54 deletions(-) create mode 100644 libraries/shared/src/MirrorMode.cpp create mode 100644 libraries/shared/src/MirrorMode.h diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 704d7963e7..130b8c77ea 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -27,7 +27,7 @@ public: using Config = SecondaryCameraJobConfig; using JobModel = render::Job::ModelO; SecondaryCameraJob() { - _cachedArgsPointer = std::make_shared(_cachedArgs); + _cachedArgsPointer = std::make_shared(); _attachedEntityPropertyFlags += PROP_POSITION; _attachedEntityPropertyFlags += PROP_ROTATION; } @@ -203,7 +203,6 @@ public: } protected: - RenderArgs _cachedArgs; RenderArgsPointer _cachedArgsPointer; private: diff --git a/interface/src/scripting/RenderScriptingInterface.cpp b/interface/src/scripting/RenderScriptingInterface.cpp index 12814aa6b6..47f772b4bc 100644 --- a/interface/src/scripting/RenderScriptingInterface.cpp +++ b/interface/src/scripting/RenderScriptingInterface.cpp @@ -9,6 +9,7 @@ // #include "RenderScriptingInterface.h" +#include #include #include "LightingModel.h" @@ -79,14 +80,35 @@ void RenderScriptingInterface::setRenderMethod(RenderMethod renderMethod) { emit settingsChanged(); } } + +void recursivelyUpdateMirrorRenderMethods(const QString& parentTaskName, int renderMethod, int depth) { + if (depth == RenderMirrorTask::MAX_MIRROR_DEPTH) { + return; + } + + for (size_t mirrorIndex = 0; mirrorIndex < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; mirrorIndex++) { + std::string mirrorTaskString = parentTaskName.toStdString() + ".RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth) + ".DeferredForwardSwitch"; + auto mirrorConfig = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(QString::fromStdString(mirrorTaskString))); + if (mirrorConfig) { + mirrorConfig->setBranch((int)renderMethod); + recursivelyUpdateMirrorRenderMethods(QString::fromStdString(mirrorTaskString) + (renderMethod == 1 ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), + renderMethod, depth + 1); + } + } +} + void RenderScriptingInterface::forceRenderMethod(RenderMethod renderMethod) { _renderSettingLock.withWriteLock([&] { _renderMethod = (int)renderMethod; _renderMethodSetting.set((int)renderMethod); - auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch")); + QString configName = "RenderMainView.DeferredForwardSwitch"; + auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(configName)); if (config) { config->setBranch((int)renderMethod); + + recursivelyUpdateMirrorRenderMethods(configName + (renderMethod == RenderMethod::FORWARD ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), + (int)renderMethod, 0); } }); } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 212baa6634..108016a939 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -12,6 +12,7 @@ #include "RenderableEntityItem.h" +#include #include #include "RenderableShapeEntityItem.h" @@ -192,6 +193,10 @@ ItemKey EntityRenderer::getKey() { builder.withSubMetaCulled(); } + if (_mirrorMode != MirrorMode::NONE) { + builder.withMirror(); + } + if (!_visible) { builder.withInvisible(); } @@ -221,6 +226,70 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co return true; } +void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { + //glm::vec3 mirrorPosition; + //glm::quat mirrorRotation; + //withReadLock([&]{ + // mirrorPosition = _entity->getWorldPosition(); + // mirrorRotation = _entity->getWorldOrientation(); + //}); + + //glm::mat4 mirrorToWorld = glm::translate(mirrorPosition) * glm::mat4_cast(mirrorRotation); + //glm::mat4 worldToMirror = glm::inverse(mirrorToWorld); + + //// get mirror camera position by reflecting main camera position's z coordinate in mirror space + //glm::vec3 cameraPosition = viewFrustum.getPosition(); + //glm::quat cameraRotation = viewFrustum.getOrientation(); + //glm::vec3 localCameraPosition = glm::vec3(worldToMirror * glm::vec4(cameraPosition, 1.0f)); + //localCameraPosition.z *= -1.0f; + //glm::quat localCameraRotation = worldToMirror * glm::mat4_cast(cameraRotation); + //glm::vec3 localCameraRotationAngles = glm::eulerAngles(localCameraRotation); + //localCameraRotationAngles.y = M_PI - localCameraRotationAngles.y; + + //viewFrustum.setPosition(mirrorToWorld * glm::vec4(localCameraPosition, 1.0f)); + //viewFrustum.setOrientation(mirrorToWorld * glm::mat4_cast(glm::quat(localCameraRotationAngles))); + + glm::vec3 mirrorPropertiesPosition; + glm::quat mirrorPropertiesRotation; + glm::vec3 mirrorPropertiesDimensions; + withReadLock([&]{ + mirrorPropertiesPosition = _entity->getWorldPosition(); + mirrorPropertiesRotation = _entity->getWorldOrientation(); + mirrorPropertiesDimensions = _entity->getScaledDimensions(); + }); + + glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; + + glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); + glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); + glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; + glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + + // get mirror camera position by reflecting main camera position's z coordinate in mirror space + glm::vec3 mainCameraPositionWorld = viewFrustum.getPosition(); + glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, + -mainCameraPositionMirror.z); + glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + + // get mirror camera rotation by reflecting main camera rotation in mirror space + // TODO: we are assuming here that UP is world y-axis + glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); + glm::mat4 mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); + glm::mat4 mirrorCameraRotationMirror = mainCameraRotationMirror;// * glm::scale(vec3(-1.0f, 1.0f, -1.0f)); + glm::quat mirrorCameraRotationWorld = worldFromMirror * mirrorCameraRotationMirror; + + viewFrustum.setPosition(mirrorCameraPositionWorld); + viewFrustum.setOrientation(mirrorCameraRotationWorld); + + // build frustum using mirror space translation of mirrored camera + //float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; + //glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + //glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + //glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, viewFrustum.getFarClip()); + //viewFrustum.setProjection(frustum); +} + void EntityRenderer::render(RenderArgs* args) { if (!isValidRenderItem()) { return; @@ -454,6 +523,8 @@ void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) _canCastShadow = entity->getCanCastShadow(); setCullWithParent(entity->getCullWithParent()); _cauterized = entity->getCauterized(); + setMirrorMode(entity->getMirrorMode()); + setPortalExitID(entity->getPortalExitID()); if (entity->needsZoneOcclusionUpdate()) { entity->resetNeedsZoneOcclusionUpdate(); _renderWithZones = entity->getRenderWithZones(); @@ -505,6 +576,10 @@ graphics::MaterialPointer EntityRenderer::getTopMaterial() { } EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) { + if (_mirrorMode != MirrorMode::NONE) { + return Pipeline::MIRROR; + } + if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) { return Pipeline::PROCEDURAL; } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 3caeef0713..bfec4743f3 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -58,12 +58,13 @@ public: enum class Pipeline { SIMPLE, MATERIAL, - PROCEDURAL + PROCEDURAL, + MIRROR }; virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); virtual graphics::MaterialPointer getTopMaterial(); - static Pipeline getPipelineType(const graphics::MultiMaterial& materials); + Pipeline getPipelineType(const graphics::MultiMaterial& materials); virtual gpu::TexturePointer getTexture() { return nullptr; } virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); } @@ -74,6 +75,7 @@ public: virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override; virtual Item::Bound getBound(RenderArgs* args) override; bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override; + void computeMirrorView(ViewFrustum& viewFrustum) const override; protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } @@ -116,6 +118,8 @@ protected: virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; } virtual void setCullWithParent(bool value) { _cullWithParent = value; } + virtual void setMirrorMode(MirrorMode value) { _mirrorMode = value; } + virtual void setPortalExitID(const QUuid& value) { _portalExitID = value; } template std::shared_ptr asTypedEntity() { return std::static_pointer_cast(_entity); } @@ -151,6 +155,8 @@ protected: BillboardMode _billboardMode { BillboardMode::NONE }; bool _cauterized { false }; bool _moving { false }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; Transform _renderTransform; MaterialMap _materials; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8ed3f84609..aa84280c74 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1085,6 +1085,10 @@ void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const Mod builder.withSubMetaCulled(); } + if (_mirrorMode != MirrorMode::NONE) { + builder.withMirror(); + } + if (didVisualGeometryRequestSucceed) { _itemKey = builder.build(); } else { @@ -1274,6 +1278,8 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint _model->setBillboardMode(_billboardMode, scene); _model->setCullWithParent(_cullWithParent, scene); _model->setRenderWithZones(_renderWithZones, scene); + _model->setMirrorMode(_mirrorMode, scene); + _model->setPortalExitID(_portalExitID, scene); }); if (didVisualGeometryRequestSucceed) { emit DependencyManager::get()-> @@ -1353,6 +1359,8 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint model->setBillboardMode(_billboardMode, scene); model->setCullWithParent(_cullWithParent, scene); model->setRenderWithZones(_renderWithZones, scene); + model->setMirrorMode(_mirrorMode, scene); + model->setPortalExitID(_portalExitID, scene); }); if (entity->blendshapesChanged()) { @@ -1466,6 +1474,18 @@ void ModelEntityRenderer::setCullWithParent(bool value) { setKey(_didLastVisualGeometryRequestSucceed, _model); } +void ModelEntityRenderer::setMirrorMode(MirrorMode value) { + Parent::setMirrorMode(value); + // called within a lock so no need to lock for _model + setKey(_didLastVisualGeometryRequestSucceed, _model); +} + +void ModelEntityRenderer::setPortalExitID(const QUuid& value) { + Parent::setPortalExitID(value); + // called within a lock so no need to lock for _model + setKey(_didLastVisualGeometryRequestSucceed, _model); +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index f394d389f5..425d082f01 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -170,6 +170,8 @@ protected: void setIsVisibleInSecondaryCamera(bool value) override; void setRenderLayer(RenderLayer value) override; void setCullWithParent(bool value) override; + void setMirrorMode(MirrorMode value) override; + void setPortalExitID(const QUuid& value) override; private: void animate(const TypedEntityPointer& entity, const ModelPointer& model); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index a6fee03311..b8954f2ced 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -157,7 +157,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } } } else { - if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { + if (pipelineType == Pipeline::MATERIAL && RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b63f0d91ab..34217d5bdf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -105,6 +105,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_RENDER_WITH_ZONES; requestedProperties += PROP_BILLBOARD_MODE; requestedProperties += _grabProperties.getEntityProperties(params); + requestedProperties += PROP_MIRROR_MODE; + requestedProperties += PROP_PORTAL_EXIT_ID; // Physics requestedProperties += PROP_DENSITY; @@ -305,6 +307,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); }); + APPEND_ENTITY_PROPERTY(PROP_MIRROR_MODE, (uint32_t)getMirrorMode()); + APPEND_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, getPortalExitID()); // Physics APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); @@ -881,6 +885,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += bytesFromGrab; dataAt += bytesFromGrab; }); + READ_ENTITY_PROPERTY(PROP_MIRROR_MODE, MirrorMode, setMirrorMode); + READ_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, QUuid, setPortalExitID); READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); { @@ -1361,6 +1367,8 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire withReadLock([&] { _grabProperties.getProperties(properties); }); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(mirrorMode, getMirrorMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(portalExitID, getPortalExitID); // Physics COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); @@ -1499,6 +1507,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { bool grabPropertiesChanged = _grabProperties.setProperties(properties); somethingChanged |= grabPropertiesChanged; }); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(mirrorMode, setMirrorMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(portalExitID, setPortalExitID); // Physics SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, setDensity); @@ -3553,3 +3563,29 @@ void EntityItem::setBillboardMode(BillboardMode value) { _billboardMode = value; }); } + +MirrorMode EntityItem::getMirrorMode() const { + return resultWithReadLock([&] { + return _mirrorMode; + }); +} + +void EntityItem::setMirrorMode(MirrorMode value) { + withWriteLock([&] { + _needsRenderUpdate |= _mirrorMode != value; + _mirrorMode = value; + }); +} + +QUuid EntityItem::getPortalExitID() const { + return resultWithReadLock([&] { + return _portalExitID; + }); +} + +void EntityItem::setPortalExitID(const QUuid& value) { + withWriteLock([&] { + _needsRenderUpdate |= _portalExitID != value; + _portalExitID = value; + }); +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ec84b0ccb2..32f6dccf37 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -559,6 +559,12 @@ public: BillboardMode getBillboardMode() const; virtual bool getRotateForPicking() const { return false; } + MirrorMode getMirrorMode() const; + void setMirrorMode(MirrorMode value); + + QUuid getPortalExitID() const; + void setPortalExitID(const QUuid& value); + signals: void spaceUpdate(std::pair data); @@ -740,6 +746,9 @@ protected: bool _cullWithParent { false }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; + mutable bool _needsRenderUpdate { false }; }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f543169401..4d21e040f5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -424,6 +424,23 @@ void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHost } } +inline void addMirrorMode(QHash& lookup, MirrorMode mirrorMode) { lookup[MirrorModeHelpers::getNameForMirrorMode(mirrorMode)] = mirrorMode; } +const QHash stringToMirrorModeLookup = [] { + QHash toReturn; + addMirrorMode(toReturn, MirrorMode::NONE); + addMirrorMode(toReturn, MirrorMode::MIRROR); + addMirrorMode(toReturn, MirrorMode::PORTAL); + return toReturn; +}(); +QString EntityItemProperties::getMirrorModeAsString() const { return MirrorModeHelpers::getNameForMirrorMode(_mirrorMode); } +void EntityItemProperties::setMirrorModeFromString(const QString& mirrorMode) { + auto mirrorModeItr = stringToMirrorModeLookup.find(mirrorMode.toLower()); + if (mirrorModeItr != stringToMirrorModeLookup.end()) { + _mirrorMode = mirrorModeItr.value(); + _mirrorModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -455,6 +472,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones); CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode); changedProperties += _grab.getChangedProperties(); + CHECK_PROPERTY_CHANGE(PROP_MIRROR_MODE, mirrorMode); + CHECK_PROPERTY_CHANGE(PROP_PORTAL_EXIT_ID, portalExitID); // Physics CHECK_PROPERTY_CHANGE(PROP_DENSITY, density); @@ -825,6 +844,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * * @property {Entities.Grab} grab - The entity's grab-related properties. * + * @property {MirrorMode} mirrorMode="none" - If this entity should render as a mirror (reflecting the view of the camera), + * a portal (reflecting the view through its portalExitID), or normally. + * @property {Uuid} portalExitID=Uuid.NULL - The ID of the entity that should act as the portal exit if the mirrorMode + * is set to portal. + * * @comment The different entity types have additional properties as follows: * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} * @see {@link Entities.EntityProperties-Gizmo|EntityProperties-Gizmo} @@ -1616,6 +1640,8 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MIRROR_MODE, mirrorMode, getMirrorModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PORTAL_EXIT_ID, portalExitID); // Physics COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density); @@ -2032,6 +2058,8 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode); _grab.copyFromScriptValue(object, namesSet, _defaultSettings); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(mirrorMode, MirrorMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE(portalExitID, QUuid, setPortalExitID); // Physics COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity); @@ -2318,6 +2346,8 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(renderWithZones); COPY_PROPERTY_IF_CHANGED(billboardMode); _grab.merge(other._grab); + COPY_PROPERTY_IF_CHANGED(mirrorMode); + COPY_PROPERTY_IF_CHANGED(portalExitID); // Physics COPY_PROPERTY_IF_CHANGED(density); @@ -2627,6 +2657,8 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, EquippableIndicatorOffset, equippableIndicatorOffset); } + ADD_PROPERTY_TO_MAP(PROP_MIRROR_MODE, MirrorMode, mirrorMode, MirrorMode); + ADD_PROPERTY_TO_MAP(PROP_PORTAL_EXIT_ID, PortalExitID, portalExitID, QUuid); // Physics ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_DENSITY, Density, density, float, @@ -3090,6 +3122,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticGrab.setProperties(properties); _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_MIRROR_MODE, (uint32_t)properties.getMirrorMode()); + APPEND_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, properties.getPortalExitID()); // Physics APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity()); @@ -3568,6 +3602,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MIRROR_MODE, MirrorMode, setMirrorMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PORTAL_EXIT_ID, QUuid, setPortalExitID); // Physics READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity); @@ -3960,6 +3996,8 @@ void EntityItemProperties::markAllChanged() { _renderWithZonesChanged = true; _billboardModeChanged = true; _grab.markAllChanged(); + _mirrorModeChanged = true; + _portalExitIDChanged = true; // Physics _densityChanged = true; @@ -4359,6 +4397,12 @@ QList EntityItemProperties::listChangedProperties() { out += "billboardMode"; } getGrab().listChangedProperties(out); + if (mirrorModeChanged()) { + out += "mirrorMode"; + } + if (portalExitIDChanged()) { + out += "portalExitID"; + } // Physics if (densityChanged()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 283d14c4cc..3e07a75616 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -70,6 +70,7 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" +#include "MirrorMode.h" class ScriptEngine; @@ -204,6 +205,8 @@ public: DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector, QVector()); DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE); DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); + DEFINE_PROPERTY_REF_ENUM(PROP_MIRROR_MODE, MirrorMode, mirrorMode, MirrorMode, MirrorMode::NONE); + DEFINE_PROPERTY_REF(PROP_PORTAL_EXIT_ID, PortalExitID, portalExitID, QUuid, UNKNOWN_ENTITY_ID); // Physics DEFINE_PROPERTY(PROP_DENSITY, Density, density, float, ENTITY_ITEM_DEFAULT_DENSITY); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index e0b5a04094..c0cbb3f9a1 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -60,6 +60,8 @@ enum EntityPropertyList { PROP_GRAB_EQUIPPABLE_INDICATOR_URL, PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, + PROP_MIRROR_MODE, + PROP_PORTAL_EXIT_ID, // Physics PROP_DENSITY, diff --git a/libraries/graphics/src/graphics/ShaderConstants.h b/libraries/graphics/src/graphics/ShaderConstants.h index 3a614d26cd..8fd0df31f0 100644 --- a/libraries/graphics/src/graphics/ShaderConstants.h +++ b/libraries/graphics/src/graphics/ShaderConstants.h @@ -27,6 +27,7 @@ #define GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS 4 #define GRAPHICS_TEXTURE_MATERIAL_OCCLUSION 5 #define GRAPHICS_TEXTURE_MATERIAL_SCATTERING 6 +#define GRAPHICS_TEXTURE_MATERIAL_MIRROR 1 // Mirrors use albedo textures, but nothing else // Make sure these match the ones in render-utils/ShaderConstants.h #define GRAPHICS_TEXTURE_SKYBOX 11 @@ -59,6 +60,7 @@ enum Texture { MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS, MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION, MaterialScattering = GRAPHICS_TEXTURE_MATERIAL_SCATTERING, + MaterialMirror = GRAPHICS_TEXTURE_MATERIAL_MIRROR, Skybox = GRAPHICS_TEXTURE_SKYBOX }; } // namespace texture diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3badfdf418..51739e0f77 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -290,6 +290,7 @@ enum class EntityVersion : PacketVersion { UserAgent, AllBillboardMode, TextAlignment, + Mirror, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 583f090942..30b826aaec 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -42,6 +42,7 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" +#include "MirrorMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -280,6 +281,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, GizmoType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } 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, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 5a8b09b018..b4aced626d 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -506,8 +506,9 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren const auto jitter = inputs.getN(4); // Prepare the ShapePipeline - auto shapePlumber = std::make_shared(); - { + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); @@ -515,7 +516,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - } + }); auto sharedParameters = std::make_shared(); const auto highlightSelectionNames = task.addJob("SelectionToHighlight", sharedParameters); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8ba5be54e6..8d9d31390d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -12,6 +12,7 @@ #include "MeshPartPayload.h" #include +#include #include #include #include @@ -216,7 +217,7 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withTransparent(); } - if (_cullWithParent) { + if (_cullWithParent || _mirrorMode != MirrorMode::NONE) { builder.withSubMetaCulled(); } @@ -377,6 +378,10 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set& blendshapeBuffers, const QVector& blendedMeshSizes) { if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); @@ -426,4 +431,10 @@ template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin } return false; } + +template <> void payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum) { + if (payload) { + payload->computeMirrorView(viewFrustum); + } +} } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 1a3a898582..3084d8ae01 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -58,7 +58,10 @@ public: void setCullWithParent(bool value) { _cullWithParent = value; } void setRenderWithZones(const QVector& renderWithZones) { _renderWithZones = renderWithZones; } void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; } + void setMirrorMode(MirrorMode mirrorMode) { _mirrorMode = mirrorMode; } + void setPortalExitID(const QUuid& portalExitID) { _portalExitID = portalExitID; } bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; + void computeMirrorView(ViewFrustum& viewFrustum) const; void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } @@ -93,6 +96,8 @@ private: bool _cullWithParent { false }; QVector _renderWithZones; BillboardMode _billboardMode { BillboardMode::NONE }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; uint64_t _created; Transform _localTransform; @@ -107,6 +112,8 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set& containingZones); + template <> void payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum); + } #endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index eabcabc7e5..9be811a7a9 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -232,6 +232,8 @@ void Model::updateRenderItems() { auto renderWithZones = self->getRenderWithZones(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool cauterized = self->isCauterized(); + auto mirrorMode = self->getMirrorMode(); + const QUuid& portalExitID = self->getPortalExitID(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -246,7 +248,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags, - cauterized, renderWithZones](ModelMeshPartPayload& data) { + cauterized, renderWithZones, mirrorMode, portalExitID](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); @@ -260,6 +262,8 @@ void Model::updateRenderItems() { data.setCauterized(cauterized); data.setRenderWithZones(renderWithZones); data.setBillboardMode(billboardMode); + data.setMirrorMode(mirrorMode); + data.setPortalExitID(portalExitID); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); @@ -1065,6 +1069,45 @@ void Model::setRenderWithZones(const QVector& renderWithZones, const rend } } +void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene) { + if (_mirrorMode != mirrorMode) { + _mirrorMode = mirrorMode; + if (!scene) { + _needsFixupInScene = true; + return; + } + + render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; + for (auto item : _modelMeshRenderItemIDs) { + transaction.updateItem(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) { + data.setMirrorMode(mirrorMode); + data.updateKey(renderItemsKey); + }); + } + scene->enqueueTransaction(transaction); + } +} + +void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene) { + if (_portalExitID != portalExitID) { + _portalExitID = portalExitID; + if (!scene) { + _needsFixupInScene = true; + return; + } + + render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; + for (auto item : _modelMeshRenderItemIDs) { + transaction.updateItem(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) { + data.setPortalExitID(portalExitID); + }); + } + scene->enqueueTransaction(transaction); + } +} + const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { return _renderItemKeyGlobalFlags; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 17b7df9b23..63a96f7253 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -41,6 +41,7 @@ #include "Rig.h" #include "PrimitiveMode.h" #include "BillboardMode.h" +#include "MirrorMode.h" // Use dual quaternion skinning! // Must match define in Skinning.slh @@ -131,6 +132,12 @@ public: void setRenderWithZones(const QVector& renderWithZones, const render::ScenePointer& scene = nullptr); const QVector& getRenderWithZones() const { return _renderWithZones; } + void setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene = nullptr); + MirrorMode getMirrorMode() const { return _mirrorMode; } + + void setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene = nullptr); + const QUuid& getPortalExitID() const { return _portalExitID; } + // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; @@ -503,6 +510,8 @@ protected: bool _cauterized { false }; bool _cullWithParent { false }; QVector _renderWithZones; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; bool shouldInvalidatePayloadShapeKey(int meshIndex); diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 7cf7f1129f..f41ed6b21f 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -13,7 +13,10 @@ #include "render-utils/ShaderConstants.h" #include "DeferredLightingEffect.h" +#include "FadeEffect.h" #include "RenderUtilsLogging.h" +#include "RenderViewTask.h" +#include "StencilMaskPass.h" namespace ru { using render_utils::slot::texture::Texture; @@ -25,9 +28,11 @@ namespace gr { using graphics::slot::buffer::Buffer; } +using RenderArgsPointer = std::shared_ptr; using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); +extern void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void BeginGPURangeTimer::run(const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) { timer = _gpuTimer; @@ -45,10 +50,14 @@ void EndGPURangeTimer::run(const render::RenderContextPointer& renderContext, co config->setGPUBatchRunTime(timer->getGPUAverage(), timer->getBatchAverage()); } +render::ShapePlumberPointer DrawLayered3D::_shapePlumber = std::make_shared(); + DrawLayered3D::DrawLayered3D(bool opaque) : - _shapePlumber(std::make_shared()), _opaquePass(opaque) { - initForwardPipelines(*_shapePlumber); + static std::once_flag once; + std::call_once(once, [] { + initForwardPipelines(*_shapePlumber); + }); } void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& inputs) { @@ -262,3 +271,127 @@ void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, } } +class SetupMirrorTask { +public: + using Input = RenderMirrorTask::Inputs; + using Outputs = render::VaryingSet4; + using JobModel = render::Job::ModelIO; + + SetupMirrorTask(size_t mirrorIndex) : _mirrorIndex(mirrorIndex) {} + + void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) { + auto args = renderContext->args; + auto items = inputs.get0(); + + if (items.empty() || _mirrorIndex > items.size() - 1) { + renderContext->taskFlow.abortTask(); + return; + } + + auto inputFramebuffer = inputs.get1(); + if (!_mirrorFramebuffer || _mirrorFramebuffer->getWidth() != inputFramebuffer->getWidth() || _mirrorFramebuffer->getHeight() != inputFramebuffer->getHeight()) { + _mirrorFramebuffer.reset(gpu::Framebuffer::create("mirror" + _mirrorIndex, gpu::Element::COLOR_SRGBA_32, inputFramebuffer->getWidth(), inputFramebuffer->getHeight())); + } + + _cachedArgsPointer->_renderMode = args->_renderMode; + _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; + args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE; + args->_blitFramebuffer = _mirrorFramebuffer; + + render::ItemBound mirror = items[_mirrorIndex]; + ViewFrustum srcViewFrustum = args->getViewFrustum(); + args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); + + // Without calculating the bound planes, the mirror will use the same culling frustum as the main camera, + // which is not what we want here. + srcViewFrustum.calculate(); + args->pushViewFrustum(srcViewFrustum); + + outputs.edit0() = mirror; + outputs.edit1() = inputFramebuffer; + outputs.edit2() = _cachedArgsPointer; + outputs.edit3() = inputs.get2(); + } + +protected: + gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; + RenderArgsPointer _cachedArgsPointer { std::make_shared() }; + size_t _mirrorIndex; + +}; + +class DrawMirrorTask { +public: + using Inputs = SetupMirrorTask::Outputs; + using JobModel = render::Job::ModelI; + + DrawMirrorTask() { + static std::once_flag once; + std::call_once(once, [this] { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + PrepareStencil::testMaskDrawShape(*state); + + auto fadeEffect = DependencyManager::get(); + initMirrorPipelines(*_forwardPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), true); + initMirrorPipelines(*_deferredPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), false); + }); + } + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto args = renderContext->args; + auto mirror = inputs.get0(); + auto framebuffer = inputs.get1(); + auto cachedArgs = inputs.get2(); + auto jitter = inputs.get3(); + + if (cachedArgs) { + args->_renderMode = cachedArgs->_renderMode; + } + args->popViewFrustum(); + + gpu::doInBatch("DrawMirrorTask::run", args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + batch.setFramebuffer(framebuffer); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setProjectionJitter(jitter.x, jitter.y); + batch.setViewTransform(viewMat); + + batch.setResourceTexture(gr::Texture::MaterialMirror, args->_blitFramebuffer->getRenderBuffer(0)); + + renderShapes(renderContext, args->_renderMethod == render::Args::RenderMethod::FORWARD ? _forwardPipelines : _deferredPipelines, { mirror }); + + args->_batch = nullptr; + }); + + // Restore the blit framebuffer after we've sampled from it + if (cachedArgs) { + args->_blitFramebuffer = cachedArgs->_blitFramebuffer; + } + } + +private: + static ShapePlumberPointer _forwardPipelines; + static ShapePlumberPointer _deferredPipelines; +}; + +ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared(); +ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared(); + + void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { + const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex); + + task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, depth + 1); + + task.addJob("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); + } diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index 15d6ff9895..cada3cb6ea 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -10,6 +10,8 @@ #define hifi_RenderCommonTask_h #include +#include + #include "LightStage.h" #include "HazeStage.h" #include "LightingModel.h" @@ -71,7 +73,7 @@ public: void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: - render::ShapePlumberPointer _shapePlumber; + static render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config bool _opaquePass { true }; }; @@ -152,4 +154,17 @@ protected: render::Args::RenderMethod _method; }; +class RenderMirrorTask { +public: + using Inputs = render::VaryingSet3; + using JobModel = render::Task::ModelI; + + RenderMirrorTask() {} + + void build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth); + + static const size_t MAX_MIRROR_DEPTH { 3 }; + static const size_t MAX_MIRRORS_PER_LEVEL { 3 }; +}; + #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c506f22bc7..80157f9a42 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -100,11 +100,14 @@ void RenderDeferredTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { - auto fadeEffect = DependencyManager::get(); +void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { + static auto fadeEffect = DependencyManager::get(); // Prepare the ShapePipelines - ShapePlumberPointer shapePlumber = std::make_shared(); - initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { + initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + }); const auto& inputs = input.get(); @@ -116,6 +119,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Extract opaques / transparents / lights / metas / layered / background const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -139,7 +143,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Shadow Stage Frame const auto shadowFrame = shadowTaskOutputs[1]; - fadeEffect->build(task, opaques); const auto jitter = task.addJob("JitterCam"); @@ -162,6 +165,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); + if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, scaledPrimaryFramebuffer, jitter).asVarying(); + for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { + task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); + } + } + // Opaque all rendered // Linear Depth Pass @@ -398,8 +408,12 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatusJob - auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; - auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); + static gpu::TexturePointer statusIconMap; + static std::once_flag once; + std::call_once(once, [] { + auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; + statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); + }); const auto drawStatusInputs = DrawStatus::Input(opaques, jitter).asVarying(); task.addJob("DrawStatus", drawStatusInputs, DrawStatus(statusIconMap)); } @@ -407,8 +421,6 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input const auto debugZoneInputs = DebugZoneLighting::Inputs(deferredFrameTransform, lightFrame, backgroundFrame).asVarying(); task.addJob("DrawZoneStack", debugZoneInputs); } - - } gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 969094488e..5fc9580981 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -144,7 +144,7 @@ public: RenderDeferredTask(); void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output); + void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); private: }; diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index e34db755b7..12af18e44b 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -34,6 +34,8 @@ #include "RenderCommonTask.h" #include "RenderHUDLayerTask.h" +#include "RenderViewTask.h" + namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; @@ -66,13 +68,16 @@ void RenderForwardTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { +void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { task.addJob("SetRenderMethodTask", render::Args::FORWARD); // Prepare the ShapePipelines auto fadeEffect = DependencyManager::get(); - ShapePlumberPointer shapePlumber = std::make_shared(); - initForwardPipelines(*shapePlumber); + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { + initForwardPipelines(*shapePlumber); + }); // Unpack inputs const auto& inputs = input.get(); @@ -86,6 +91,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; const auto& metas = items[RenderFetchCullSortTask::META]; + const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -107,7 +113,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // First job, alter faded fadeEffect->build(task, opaques); - // GPU jobs: Start preparing the main framebuffer const auto scaledPrimaryFramebuffer = task.addJob("PreparePrimaryBufferForward"); @@ -125,6 +130,16 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel, hazeFrame).asVarying(); task.addJob("DrawOpaques", opaqueInputs, shapePlumber, true); + const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); +#ifndef Q_OS_ANDROID + if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, scaledPrimaryFramebuffer, nullJitter).asVarying(); + for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { + task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); + } + } +#endif + // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job const auto backgroundInputs = DrawBackgroundStage::Inputs(lightingModel, backgroundFrame, hazeFrame).asVarying(); task.addJob("DrawBackgroundForward", backgroundInputs); @@ -134,7 +149,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("DrawTransparents", transparentInputs, shapePlumber, false); // Layered - const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, hazeFrame, nullJitter).asVarying(); const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, hazeFrame, nullJitter).asVarying(); task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 6833e42449..de3a6dd205 100644 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -36,7 +36,7 @@ public: RenderForwardTask() {} void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output); + void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index ed9fb326c4..b5a88b0ba9 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -42,6 +42,7 @@ namespace gr { void initDeferredPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); void initForwardPipelines(ShapePlumber& plumber); void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); +void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void addPlumberPipeline(ShapePlumber& plumber, const ShapeKey& key, int programId, @@ -368,6 +369,45 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, con gpu::Shader::createProgram(model_shadow_fade_deformeddq), state, extraBatchSetter, itemSetter); } +void initMirrorPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& extraBatchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward) { + using namespace shader::render_utils::program; + + if (forward) { + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward), state); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward_deformed), state); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward_deformeddq), state); + } else { + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade), state, extraBatchSetter, itemSetter); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_deformed), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade_deformed), state, extraBatchSetter, itemSetter); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_deformeddq), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade_deformeddq), state, extraBatchSetter, itemSetter); + } +} + bool RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures) { graphics::MultiMaterial multiMaterial; multiMaterial.push(graphics::MaterialLayer(material, 0)); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index dbfa23a143..9fabad5fd0 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -46,15 +46,16 @@ void RenderShadowTask::configure(const Config& configuration) { void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cameraCullFunctor, uint8_t tagBits, uint8_t tagMask) { // Prepare the ShapePipeline - ShapePlumberPointer shapePlumber = std::make_shared(); - { + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - } + }); const auto setupOutput = task.addJob("ShadowSetup", input); const auto queryResolution = setupOutput.getN(1); const auto shadowFrame = setupOutput.getN(3); diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index 93a3ff2d67..b9320b6ad3 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -15,7 +15,7 @@ #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { +void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { task.addJob("SetRenderMethodTask", render::Args::DEFERRED); const auto items = input.getN(0); @@ -28,16 +28,16 @@ void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& const auto shadowTaskOut = task.addJob("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask); const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); - task.addJob("RenderDeferredTask", renderDeferredInput); + task.addJob("RenderDeferredTask", renderDeferredInput, cullFunctor, depth); } -void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { - task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask); +void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { + task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask, depth); - task.addBranch("RenderForwardTask", 1, input); + task.addBranch("RenderForwardTask", 1, input, cullFunctor, depth); } -void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { +void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); // Issue the lighting model, aka the big global settings for the view @@ -48,7 +48,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: #ifndef Q_OS_ANDROID const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); - task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask); + task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask, depth); #else const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("RenderForwardTask", renderInput); diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index cdb56a2189..139d00125e 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -24,7 +24,7 @@ public: RenderShadowsAndDeferredTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); }; @@ -36,7 +36,7 @@ public: DeferredForwardSwitchJob() {} void configure(const render::SwitchConfig& config) {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); }; @@ -47,7 +47,7 @@ public: RenderViewTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00, size_t depth = 0); }; diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index 98abc29d8c..2f80fbde99 100644 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -36,7 +36,15 @@ <@include DeferredBufferWrite.slh@> <@endif@> <@else@> - layout(location=0) out vec4 _fragColor0; + <@if HIFI_USE_MIRROR@> + <@if HIFI_USE_FORWARD@> + layout(location=0) out vec4 _fragColor0; + <@else@> + <@include DeferredBufferWrite.slh@> + <@endif@> + <@else@> + layout(location=0) out vec4 _fragColor0; + <@endif@> <@endif@> <@if HIFI_USE_UNLIT@> @@ -45,6 +53,9 @@ <@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@> <$declareMaterialTextures(ALBEDO)$> + <@if HIFI_USE_MIRROR@> + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; + <@endif@> <@else@> <@if not HIFI_USE_LIGHTMAP@> <@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@> @@ -124,7 +135,14 @@ void main(void) { <@endif@> <@endif@> - <@if HIFI_USE_SHADOW@> + <@if HIFI_USE_MIRROR@> + vec3 mirrorColor = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; + <@if HIFI_USE_FORWARD@> + _fragColor0 = vec4(mirrorColor, 1.0); + <@else@> + packDeferredFragmentUnlit(vec3(1.0, 0.0, 0.0), 1.0, mirrorColor); + <@endif@> + <@elif HIFI_USE_SHADOW@> _fragColor0 = vec4(1.0); <@elif HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(albedo * isUnlitEnabled(), opacity); diff --git a/libraries/render-utils/src/render-utils/model.slp b/libraries/render-utils/src/render-utils/model.slp index b63ec898eb..a3c28631e9 100644 --- a/libraries/render-utils/src/render-utils/model.slp +++ b/libraries/render-utils/src/render-utils/model.slp @@ -1 +1 @@ -DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file +DEFINES (normalmap translucent:f unlit:f/lightmap:f)/(shadow mirror:f) fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 369f227566..23e5570736 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -160,4 +160,11 @@ namespace render { } return payload->passesZoneOcclusionTest(containingZones); } + + template <> void payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum) { + if (!payload) { + return; + } + payload->computeMirrorView(viewFrustum); + } } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 5952be8a84..c2f03b4e05 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -110,6 +110,8 @@ public: FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, + MIRROR, + __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag @@ -162,6 +164,7 @@ public: Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } + Builder& withMirror() { _flags.set(MIRROR); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -205,6 +208,9 @@ public: bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } + bool isNotMirror() const { return !_flags[MIRROR]; } + bool isMirror() const { return _flags[MIRROR]; } + bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } @@ -274,7 +280,10 @@ public: Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } - Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + + Builder& withoutMirror() { _value.reset(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } + Builder& withMirror() { _value.set(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } @@ -292,6 +301,7 @@ public: static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } + static Builder mirror() { return Builder().withMirror(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; @@ -440,6 +450,8 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; + virtual void computeMirrorView(ViewFrustum& viewFrustum) const = 0; + ~PayloadInterface() {} // Status interface is local to the base class @@ -493,6 +505,8 @@ public: bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); } + void computeMirrorView(ViewFrustum& viewFrustum) const { _payload->computeMirrorView(viewFrustum); } + // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -547,6 +561,9 @@ template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payl // Allows payloads to determine if they should render or not, based on the zones that contain the current camera template bool payloadPassesZoneOcclusionTest(const std::shared_ptr& payloadData, const std::unordered_set& containingZones) { return true; } +// Mirror Interface +template void payloadComputeMirrorView(const std::shared_ptr& payloadData, ViewFrustum& viewFrustum) { return; } + // THe Payload class is the real Payload to be used // THis allow anything to be turned into a Payload as long as the required interface functions are available // When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" @@ -573,6 +590,8 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override { return payloadPassesZoneOcclusionTest(_data, containingZones); } + virtual void computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView(_data, viewFrustum); } + protected: DataPointer _data; @@ -628,6 +647,7 @@ public: virtual void render(RenderArgs* args) = 0; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; + virtual void computeMirrorView(ViewFrustum& viewFrustum) const = 0; // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface virtual void handleBlendedVertices(int blendshapeNumber, const QVector& blendshapeOffsets, @@ -640,6 +660,7 @@ template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, Re template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems); template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload); template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set& containingZones); +template <> void payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum); typedef Item::PayloadPointer PayloadPointer; typedef std::vector Payloads; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index b2656a597f..3bdaee25c6 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -35,18 +35,20 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto nonspatialSelection = task.addJob("FetchLayeredSelection", nonspatialFilter); // Multi filter visible items into different buckets - const int NUM_SPATIAL_FILTERS = 4; + const int NUM_SPATIAL_FILTERS = 5; const int NUM_NON_SPATIAL_FILTERS = 3; const int OPAQUE_SHAPE_BUCKET = 0; const int TRANSPARENT_SHAPE_BUCKET = 1; const int LIGHT_BUCKET = 2; const int META_BUCKET = 3; + const int MIRROR_BUCKET = 4; const int BACKGROUND_BUCKET = 2; MultiFilterItems::ItemFilterArray spatialFilters = { { - ItemFilter::Builder::opaqueShape(), + ItemFilter::Builder::opaqueShape().withoutMirror(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::light(), - ItemFilter::Builder::meta() + ItemFilter::Builder::meta().withoutMirror(), + ItemFilter::Builder::mirror() } }; MultiFilterItems::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), @@ -65,6 +67,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto transparents = task.addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; const auto metas = filteredSpatialBuckets[META_BUCKET]; + const auto mirrors = task.addJob("DepthSortMirrors", filteredSpatialBuckets[MIRROR_BUCKET]); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; @@ -76,7 +79,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin task.addJob("ClearContainingZones"); - output = Output(BucketList{ opaques, transparents, lights, metas, + output = Output(BucketList{ opaques, transparents, lights, metas, mirrors, filteredLayeredOpaque.getN(0), filteredLayeredTransparent.getN(0), filteredLayeredOpaque.getN(1), filteredLayeredTransparent.getN(1), background }, spatialSelection); diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index 0b475614a1..9823c2acdf 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -23,6 +23,7 @@ public: TRANSPARENT_SHAPE, LIGHT, META, + MIRROR, LAYER_FRONT_OPAQUE_SHAPE, LAYER_FRONT_TRANSPARENT_SHAPE, LAYER_HUD_OPAQUE_SHAPE, diff --git a/libraries/shared/src/MirrorMode.cpp b/libraries/shared/src/MirrorMode.cpp new file mode 100644 index 0000000000..53a51b1c1c --- /dev/null +++ b/libraries/shared/src/MirrorMode.cpp @@ -0,0 +1,25 @@ +// +// Created by HifiExperiments on 3/14/22. +// Copyright 2022 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 "MirrorMode.h" + +const char* MirrorModeNames[] = { + "none", + "mirror", + "portal" +}; + +static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0])); + +QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) { + mode = (MirrorMode)0; + } + + return MirrorModeNames[(int)mode]; +} diff --git a/libraries/shared/src/MirrorMode.h b/libraries/shared/src/MirrorMode.h new file mode 100644 index 0000000000..38af190070 --- /dev/null +++ b/libraries/shared/src/MirrorMode.h @@ -0,0 +1,40 @@ +// +// Created by HifiExperiments on 3/14/22. +// Copyright 2022 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_MirrorMode_h +#define hifi_MirrorMode_h + +#include "QString" + +/*@jsdoc + *

If an entity is rendered as a mirror, a portal, or normally.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
"none"The entity will render normally.
"mirror"The entity will render as a mirror.
"portal"The entity will render as a portal.
+ * @typedef {string} MirrorMode + */ + +enum class MirrorMode { + NONE = 0, + MIRROR, + PORTAL +}; + +class MirrorModeHelpers { +public: + static QString getNameForMirrorMode(MirrorMode mode); +}; + +#endif // hifi_MirrorMode_h diff --git a/scripts/system/create/assets/data/createAppTooltips.json b/scripts/system/create/assets/data/createAppTooltips.json index 9f6c3ef278..57cb3d1bc8 100644 --- a/scripts/system/create/assets/data/createAppTooltips.json +++ b/scripts/system/create/assets/data/createAppTooltips.json @@ -215,7 +215,7 @@ }, "imageAlpha": { "tooltip": "The opacity of the image between 0.0 fully transparent and 1.0 completely opaque." - }, + }, "emissive": { "tooltip": "If enabled, the image will display at full brightness." }, @@ -236,7 +236,7 @@ }, "showKeyboardFocusHighlight": { "tooltip": "If enabled, highlights when it has keyboard focus." - }, + }, "isEmitting": { "tooltip": "If enabled, then particles are emitted." }, @@ -503,6 +503,12 @@ "grab.triggerable": { "tooltip": "If enabled, the collider on this entity is used for triggering events." }, + "mirrorMode": { + "tooltip": "If this entity should render normally, or as a \"Mirror\" or \"Portal\"" + }, + "portalExitID": { + "tooltip": "If this entity is a portal, what entity it should use as its exit." + }, "cloneable": { "tooltip": "If enabled, this entity can be duplicated." }, @@ -606,7 +612,7 @@ }, "useBackground": { "tooltip": "If disabled, this web entity will support a transparent background for the webpage and its elements if the CSS property of 'background-color' on the 'body' is set with transparency." - }, + }, "maxFPS": { "tooltip": "The FPS at which to render the web entity. Higher values will have a performance impact." }, diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index e16b6ca653..ff28925b96 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -131,6 +131,21 @@ const GROUPS = [ label: "Render With Zones", type: "multipleZonesSelection", propertyID: "renderWithZones", + }, + { + label: "Mirror Mode", + type: "dropdown", + options: { + none: "None", + mirror: "Mirror", + portal: "Portal" + }, + propertyID: "mirrorMode", + }, + { + label: "Portal Exit", + type: "string", + propertyID: "portalExitID", } ] }, From 10de1288c2690baa5d1472695085bf3d305c0694 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sun, 12 Nov 2023 23:04:18 -0800 Subject: [PATCH 02/18] fix view + projection, texture flipping, billboarding --- interface/src/avatar/MyAvatar.cpp | 3 +- .../src/RenderableEntityItem.cpp | 74 ++++++++++--------- .../src/RenderableGizmoEntityItem.cpp | 3 +- .../src/RenderableGridEntityItem.cpp | 3 +- .../src/RenderableImageEntityItem.cpp | 3 +- .../src/RenderableLineEntityItem.cpp | 3 +- .../src/RenderableMaterialEntityItem.cpp | 3 +- .../src/RenderablePolyLineEntityItem.cpp | 3 +- .../src/RenderablePolyVoxEntityItem.cpp | 3 +- .../src/RenderableShapeEntityItem.cpp | 3 +- .../src/RenderableTextEntityItem.cpp | 6 +- .../src/RenderableWebEntityItem.cpp | 3 +- .../src/CauterizedMeshPartPayload.cpp | 7 +- .../src/CauterizedMeshPartPayload.h | 2 +- .../render-utils/src/MeshPartPayload.cpp | 12 +-- libraries/render-utils/src/MeshPartPayload.h | 2 +- .../render-utils/src/RenderCommonTask.cpp | 21 ++++-- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderForwardTask.cpp | 2 +- .../render-utils/src/RenderHUDLayerTask.cpp | 4 +- .../src/ToneMapAndResampleTask.cpp | 6 +- .../render-utils/src/ToneMapAndResampleTask.h | 7 +- libraries/render/src/render/Args.h | 3 + libraries/render/src/render/CullTask.cpp | 18 ++--- libraries/render/src/render/ResampleTask.cpp | 3 +- libraries/render/src/render/ResampleTask.h | 4 +- 26 files changed, 118 insertions(+), 85 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 58c86e5e8a..32116343bf 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3530,8 +3530,9 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false; + bool isInMirror = renderArgs->_mirrorDepth > 0; bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); - return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); + return !defaultMode || isInMirror || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); } void MyAvatar::setRotationRecenterFilterLength(float length) { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 108016a939..1fc9ed791f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -227,39 +227,13 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co } void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { - //glm::vec3 mirrorPosition; - //glm::quat mirrorRotation; - //withReadLock([&]{ - // mirrorPosition = _entity->getWorldPosition(); - // mirrorRotation = _entity->getWorldOrientation(); - //}); - - //glm::mat4 mirrorToWorld = glm::translate(mirrorPosition) * glm::mat4_cast(mirrorRotation); - //glm::mat4 worldToMirror = glm::inverse(mirrorToWorld); - - //// get mirror camera position by reflecting main camera position's z coordinate in mirror space - //glm::vec3 cameraPosition = viewFrustum.getPosition(); - //glm::quat cameraRotation = viewFrustum.getOrientation(); - //glm::vec3 localCameraPosition = glm::vec3(worldToMirror * glm::vec4(cameraPosition, 1.0f)); - //localCameraPosition.z *= -1.0f; - //glm::quat localCameraRotation = worldToMirror * glm::mat4_cast(cameraRotation); - //glm::vec3 localCameraRotationAngles = glm::eulerAngles(localCameraRotation); - //localCameraRotationAngles.y = M_PI - localCameraRotationAngles.y; - - //viewFrustum.setPosition(mirrorToWorld * glm::vec4(localCameraPosition, 1.0f)); - //viewFrustum.setOrientation(mirrorToWorld * glm::mat4_cast(glm::quat(localCameraRotationAngles))); - glm::vec3 mirrorPropertiesPosition; glm::quat mirrorPropertiesRotation; - glm::vec3 mirrorPropertiesDimensions; withReadLock([&]{ mirrorPropertiesPosition = _entity->getWorldPosition(); mirrorPropertiesRotation = _entity->getWorldOrientation(); - mirrorPropertiesDimensions = _entity->getScaledDimensions(); }); - glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; - glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; @@ -275,19 +249,47 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { // get mirror camera rotation by reflecting main camera rotation in mirror space // TODO: we are assuming here that UP is world y-axis glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); - glm::mat4 mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); - glm::mat4 mirrorCameraRotationMirror = mainCameraRotationMirror;// * glm::scale(vec3(-1.0f, 1.0f, -1.0f)); - glm::quat mirrorCameraRotationWorld = worldFromMirror * mirrorCameraRotationMirror; + glm::quat mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); + glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * + glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); + glm::quat mirrorCameraRotationWorld = worldFromMirror * glm::mat4_cast(mirrorCameraRotationMirror); viewFrustum.setPosition(mirrorCameraPositionWorld); viewFrustum.setOrientation(mirrorCameraRotationWorld); - // build frustum using mirror space translation of mirrored camera - //float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; - //glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - //glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - //glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, viewFrustum.getFarClip()); - //viewFrustum.setProjection(frustum); + // modify the near clip plane to be the XY plane of the mirror + // from: https://terathon.com/lengyel/Lengyel-Oblique.pdf + glm::mat4 view = viewFrustum.getView(); + glm::mat4 projection = viewFrustum.getProjection(); + + //Find the camera-space 4D reflection plane vector + glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(mirrorPropertiesPosition, 1.0f); + glm::vec3 cameraSpaceNormal = glm::transpose(view) * (worldFromMirrorRotation * glm::vec4(0, 0, -1, 0)); + glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); + if (clipPlane.w > 0.0f) { + clipPlane *= -1.0f; + } + + // Calculate the clip-space corner point opposite the clipping plane + // as (sign(clipPlane.x), sign(clipPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + glm::vec4 q; + q.x = (glm::sign(clipPlane.x) + projection[0][2]) / projection[0][0]; + q.y = (glm::sign(clipPlane.y) + projection[1][2]) / projection[1][1]; + q.z = -1.0f; + q.w = (1.0f + projection[2][2]) / projection[2][3]; + + // Calculate the scaled plane vector + glm::vec4 c = (2.0f / glm::dot(clipPlane, q)) * clipPlane; + + // Replace the third row of the projection matrix + projection[0][2] = c.x; + projection[1][2] = c.y; + projection[2][2] = c.z + 1.0f; + projection[3][2] = c.w; + + viewFrustum.setProjection(projection); } void EntityRenderer::render(RenderArgs* args) { @@ -295,7 +297,7 @@ void EntityRenderer::render(RenderArgs* args) { return; } - if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { + if (_visible && (!_cauterized || args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || args->_mirrorDepth > 0)) { doRender(args); } } diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp index 42df1e2888..10ae144334 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp @@ -263,8 +263,9 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index e374fe29c0..3f40218d46 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -103,8 +103,9 @@ void GridEntityRenderer::doRender(RenderArgs* args) { } else { transform.setTranslation(renderTransform.getTranslation()); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch->setModelTransform(transform); auto minCorner = glm::vec2(-0.5f, -0.5f); diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 9592a3e57f..4c18653d4f 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -147,8 +147,9 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { gpu::Batch* batch = args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float imageWidth = _texture->getWidth(); float imageHeight = _texture->getHeight(); diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index a36cdde212..1117c97c75 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -47,8 +47,9 @@ void LineEntityRenderer::doRender(RenderArgs* args) { const auto& modelTransform = getModelTransform(); Transform transform = Transform(); transform.setTranslation(modelTransform.getTranslation()); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch, false, false, false, false, true, diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index b8f829f4ba..fe44c41094 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -303,8 +303,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { proceduralRender = true; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (!proceduralRender) { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index aca501985a..81f4c5fcb4 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -325,8 +325,9 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { buildPipelines(); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 8331e016fd..26091a1ed4 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1860,8 +1860,9 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); gpu::Batch& batch = *args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index b8954f2ced..82350f54bf 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -118,8 +118,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron)); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 2858e12afd..a3ccf78593 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -164,8 +164,9 @@ void TextEntityRenderer::doRender(RenderArgs* args) { transform = _renderTransform; }); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); @@ -352,8 +353,9 @@ void entities::TextPayload::render(RenderArgs* args) { return; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float scale = textRenderable->_lineHeight / textRenderer->getFontSize(); transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z)); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index c98bfe7f63..77f6fe99f6 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -320,8 +320,9 @@ void WebEntityRenderer::doRender(RenderArgs* args) { batch.setResourceTexture(0, _texture); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); // Turn off jitter for these entities diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index dc1ffb7b67..78652bfb09 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -71,14 +71,15 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { + bool useCauterizedMesh = _enableCauterization && (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && + mirrorDepth == 0; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer); } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, transform, renderMode); + ModelMeshPartPayload::bindTransform(batch, transform, renderMode, mirrorDepth); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 430f41fc08..cef7b6d9b5 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ public: void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning); - void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8d9d31390d..ad749b6d10 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -189,7 +189,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { if (_clusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); } @@ -300,8 +300,9 @@ Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const { auto worldBound = _adjustedLocalBound; auto parentTransform = _parentTransform; if (args) { + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); } worldBound.transform(parentTransform); return worldBound; @@ -314,18 +315,19 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) { + if (!args || (_cauterized && args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && args->_mirrorDepth == 0)) { return; } gpu::Batch& batch = *(args->_batch); Transform transform = _parentTransform; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform modelTransform = transform.worldTransform(_localTransform); - bindTransform(batch, modelTransform, args->_renderMode); + bindTransform(batch, modelTransform, args->_renderMode, args->_mirrorDepth); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 3084d8ae01..6e0bb91a30 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -37,7 +37,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch); - virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const; + virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const; void drawCall(gpu::Batch& batch) const; void updateKey(const render::ItemKey& key); diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index f41ed6b21f..a3355ea805 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -277,7 +277,7 @@ public: using Outputs = render::VaryingSet4; using JobModel = render::Job::ModelIO; - SetupMirrorTask(size_t mirrorIndex) : _mirrorIndex(mirrorIndex) {} + SetupMirrorTask(size_t mirrorIndex, size_t depth) : _mirrorIndex(mirrorIndex), _depth(depth) {} void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) { auto args = renderContext->args; @@ -293,12 +293,17 @@ public: _mirrorFramebuffer.reset(gpu::Framebuffer::create("mirror" + _mirrorIndex, gpu::Element::COLOR_SRGBA_32, inputFramebuffer->getWidth(), inputFramebuffer->getHeight())); } + render::ItemBound mirror = items[_mirrorIndex]; + _cachedArgsPointer->_renderMode = args->_renderMode; _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; - args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE; - args->_blitFramebuffer = _mirrorFramebuffer; + _cachedArgsPointer->_ignoreItem = args->_ignoreItem; + _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; + + args->_blitFramebuffer = _mirrorFramebuffer; + args->_ignoreItem = mirror.id; + args->_mirrorDepth = _depth; - render::ItemBound mirror = items[_mirrorIndex]; ViewFrustum srcViewFrustum = args->getViewFrustum(); args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); @@ -317,6 +322,7 @@ protected: gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; RenderArgsPointer _cachedArgsPointer { std::make_shared() }; size_t _mirrorIndex; + size_t _depth; }; @@ -377,6 +383,8 @@ public: // Restore the blit framebuffer after we've sampled from it if (cachedArgs) { args->_blitFramebuffer = cachedArgs->_blitFramebuffer; + args->_ignoreItem = cachedArgs->_ignoreItem; + args->_mirrorDepth = cachedArgs->_mirrorDepth; } } @@ -389,9 +397,10 @@ ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared(); void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { - const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex); + size_t nextDepth = depth + 1; + const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex, nextDepth); - task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, depth + 1); + task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, nextDepth); task.addJob("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 80157f9a42..92208450ef 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -244,7 +244,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); // 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 diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 12af18e44b..722ba2248c 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -173,7 +173,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto destFramebuffer = static_cast(nullptr); const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); // HUD Layer const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying(); task.addJob("RenderHUDLayer", renderHUDLayerInputs); diff --git a/libraries/render-utils/src/RenderHUDLayerTask.cpp b/libraries/render-utils/src/RenderHUDLayerTask.cpp index 743e59eebc..8fee3d57bc 100644 --- a/libraries/render-utils/src/RenderHUDLayerTask.cpp +++ b/libraries/render-utils/src/RenderHUDLayerTask.cpp @@ -16,8 +16,8 @@ void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::Fra assert(renderContext->args); assert(renderContext->args->_context); - // We do not want to render HUD elements in secondary camera - if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { + // We do not want to render HUD elements in secondary camera or mirrors + if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE || renderContext->args->_mirrorDepth > 0) { return; } diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 10312f7f2e..6ac5142e45 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -25,9 +25,10 @@ using namespace shader::render_utils::program; gpu::PipelinePointer ToneMapAndResample::_pipeline; gpu::PipelinePointer ToneMapAndResample::_mirrorPipeline; -ToneMapAndResample::ToneMapAndResample() { +ToneMapAndResample::ToneMapAndResample(size_t depth) { Parameters parameters; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); + _depth = depth; } void ToneMapAndResample::init() { @@ -95,7 +96,8 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.h b/libraries/render-utils/src/ToneMapAndResampleTask.h index 1c7ef2cf48..3a812cf445 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.h +++ b/libraries/render-utils/src/ToneMapAndResampleTask.h @@ -49,11 +49,9 @@ signals: class ToneMapAndResample { public: - ToneMapAndResample(); + ToneMapAndResample(size_t depth); virtual ~ToneMapAndResample() {} - void render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, gpu::FramebufferPointer& destinationBuffer); - void setExposure(float exposure); float getExposure() const { return _parametersBuffer.get()._exposure; } @@ -75,7 +73,8 @@ protected: gpu::FramebufferPointer _destinationFrameBuffer; - float _factor{ 2.0f }; + float _factor { 2.0f }; + size_t _depth { 0 }; gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index d09b0d2f2f..60daa35729 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -159,6 +159,9 @@ namespace render { bool _takingSnapshot { false }; StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE }; std::function _stencilMaskOperator; + + ItemID _ignoreItem { 0 }; + size_t _mirrorDepth { 0 }; }; } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 039cf01c86..aeb7572746 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -82,7 +82,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const outItems.reserve(items.size()); for (auto& id : items) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args))); } } @@ -190,7 +190,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -205,7 +205,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -220,7 +220,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -235,7 +235,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -252,7 +252,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -267,7 +267,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -284,7 +284,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -301,7 +301,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index b868c53542..5206767bd2 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,7 +167,8 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index 92f720c843..bf1e535949 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -73,7 +73,7 @@ namespace render { using Input = gpu::FramebufferPointer; using JobModel = Job::ModelIO; - UpsampleToBlitFramebuffer() {} + UpsampleToBlitFramebuffer(size_t depth) : _depth(depth) {} void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); @@ -81,6 +81,8 @@ namespace render { static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _mirrorPipeline; + + size_t _depth; }; } From 97c4184db1620a06dbb46b6dcc0468ca5612885b Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Mon, 13 Nov 2023 00:13:35 -0800 Subject: [PATCH 03/18] wip portals --- .../src/RenderableEntityItem.cpp | 54 ++++++++++++------- .../src/RenderableModelEntityItem.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 2 +- libraries/render-utils/src/Model.cpp | 7 +-- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 1fc9ed791f..b80b39c08c 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -193,7 +193,7 @@ ItemKey EntityRenderer::getKey() { builder.withSubMetaCulled(); } - if (_mirrorMode != MirrorMode::NONE) { + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { builder.withMirror(); } @@ -227,32 +227,50 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co } void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { - glm::vec3 mirrorPropertiesPosition; - glm::quat mirrorPropertiesRotation; + glm::vec3 inPropertiesPosition; + glm::quat inPropertiesRotation; + MirrorMode mirrorMode; + QUuid portalExitID; withReadLock([&]{ - mirrorPropertiesPosition = _entity->getWorldPosition(); - mirrorPropertiesRotation = _entity->getWorldOrientation(); + inPropertiesPosition = _entity->getWorldPosition(); + inPropertiesRotation = _entity->getWorldOrientation(); + mirrorMode = _mirrorMode; + portalExitID = _portalExitID; }); - glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); - glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); - glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; - glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation); + glm::mat4 worldToIn = glm::inverse(inToWorld); + + glm::vec3 outPropertiesPosition = inPropertiesPosition; + glm::quat outPropertiesRotation = inPropertiesRotation; + glm::mat4 outToWorld = inToWorld; + if (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) { + auto renderer = DependencyManager::get(); + if (renderer) { + if (auto renderable = renderer->renderableForEntityId(portalExitID)) { + renderable->withReadLock([&] { + outPropertiesPosition = renderable->_entity->getWorldPosition(); + outPropertiesRotation = renderable->_entity->getWorldOrientation(); + }); + + outToWorld = glm::translate(outPropertiesPosition) * glm::mat4_cast(outPropertiesRotation); + } + } + } // get mirror camera position by reflecting main camera position's z coordinate in mirror space - glm::vec3 mainCameraPositionWorld = viewFrustum.getPosition(); - glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); - glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, - -mainCameraPositionMirror.z); - glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + glm::vec3 cameraPositionWorld = viewFrustum.getPosition(); + glm::vec3 cameraPositionIn = vec3(worldToIn * vec4(cameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionIn = vec3(cameraPositionIn.x, cameraPositionIn.y, -cameraPositionIn.z); + glm::vec3 mirrorCameraPositionWorld = vec3(outToWorld * vec4(mirrorCameraPositionIn, 1.0f)); // get mirror camera rotation by reflecting main camera rotation in mirror space // TODO: we are assuming here that UP is world y-axis glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); - glm::quat mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); + glm::quat mainCameraRotationMirror = worldToIn * glm::mat4_cast(mainCameraRotationWorld); glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); - glm::quat mirrorCameraRotationWorld = worldFromMirror * glm::mat4_cast(mirrorCameraRotationMirror); + glm::quat mirrorCameraRotationWorld = outToWorld * glm::mat4_cast(mirrorCameraRotationMirror); viewFrustum.setPosition(mirrorCameraPositionWorld); viewFrustum.setOrientation(mirrorCameraRotationWorld); @@ -263,8 +281,8 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { glm::mat4 projection = viewFrustum.getProjection(); //Find the camera-space 4D reflection plane vector - glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(mirrorPropertiesPosition, 1.0f); - glm::vec3 cameraSpaceNormal = glm::transpose(view) * (worldFromMirrorRotation * glm::vec4(0, 0, -1, 0)); + glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(outPropertiesPosition, 1.0f); + glm::vec3 cameraSpaceNormal = glm::transpose(view) * (outPropertiesRotation * glm::vec4(0, 0, -1, 0)); glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); if (clipPlane.w > 0.0f) { clipPlane *= -1.0f; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index aa84280c74..ae3f261d48 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1085,7 +1085,7 @@ void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const Mod builder.withSubMetaCulled(); } - if (_mirrorMode != MirrorMode::NONE) { + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { builder.withMirror(); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index ad749b6d10..de88381468 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -217,7 +217,7 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withTransparent(); } - if (_cullWithParent || _mirrorMode != MirrorMode::NONE) { + if (_cullWithParent) { builder.withSubMetaCulled(); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9be811a7a9..066e8cb1d8 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1078,11 +1078,9 @@ void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& sce } render::Transaction transaction; - auto renderItemsKey = _renderItemKeyGlobalFlags; for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) { + transaction.updateItem(item, [mirrorMode](ModelMeshPartPayload& data) { data.setMirrorMode(mirrorMode); - data.updateKey(renderItemsKey); }); } scene->enqueueTransaction(transaction); @@ -1098,9 +1096,8 @@ void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointe } render::Transaction transaction; - auto renderItemsKey = _renderItemKeyGlobalFlags; for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) { + transaction.updateItem(item, [portalExitID](ModelMeshPartPayload& data) { data.setPortalExitID(portalExitID); }); } From 4806f901b4a5be00bba601d11c57774aa78b1fe7 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Thu, 16 Nov 2023 22:24:13 -0800 Subject: [PATCH 04/18] wip --- .../src/RenderableEntityItem.cpp | 3 +- libraries/render/src/render/CullTask.cpp | 67 ------------------- libraries/render/src/render/CullTask.h | 23 ------- libraries/shared/src/ViewFrustum.cpp | 5 ++ libraries/shared/src/ViewFrustum.h | 4 +- 5 files changed, 10 insertions(+), 92 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index b80b39c08c..d0891d16b1 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -308,6 +308,7 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { projection[3][2] = c.w; viewFrustum.setProjection(projection); + viewFrustum.setIsOblique(true); } void EntityRenderer::render(RenderArgs* args) { @@ -596,7 +597,7 @@ graphics::MaterialPointer EntityRenderer::getTopMaterial() { } EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) { - if (_mirrorMode != MirrorMode::NONE) { + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { return Pipeline::MIRROR; } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index aeb7572746..cd69114bbf 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -325,73 +325,6 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, std::static_pointer_cast(renderContext->jobConfig)->numItems = (int)outItems.size(); } -void CullShapeBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { - assert(renderContext->args); - assert(renderContext->args->hasViewFrustum()); - RenderArgs* args = renderContext->args; - - const auto& inShapes = inputs.get0(); - const auto& cullFilter = inputs.get1(); - const auto& boundsFilter = inputs.get2(); - ViewFrustumPointer antiFrustum; - auto& outShapes = outputs.edit0(); - auto& outBounds = outputs.edit1(); - - if (!inputs[3].isNull()) { - antiFrustum = inputs.get3(); - } - outShapes.clear(); - outBounds = AABox(); - - if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { - auto& details = args->_details.edit(_detailType); - CullTest test(_cullFunctor, args, details, antiFrustum); - auto scene = args->_scene; - - for (auto& inItems : inShapes) { - auto key = inItems.first; - auto outItems = outShapes.find(key); - if (outItems == outShapes.end()) { - outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first; - outItems->second.reserve(inItems.second.size()); - } - - details._considered += (int)inItems.second.size(); - - if (antiFrustum == nullptr) { - for (auto& item : inItems.second) { - if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } - } - } else { - for (auto& item : inItems.second) { - if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } - } - } - details._rendered += (int)outItems->second.size(); - } - - for (auto& items : outShapes) { - items.second.shrink_to_fit(); - } - } -} - void ApplyCullFunctorOnItemBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 9a7466223d..9e214fd988 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -121,29 +121,6 @@ namespace render { void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; - class CullShapeBounds { - public: - using Inputs = render::VaryingSet4; - using Outputs = render::VaryingSet2; - using JobModel = Job::ModelIO; - - CullShapeBounds(CullFunctor cullFunctor, RenderDetails::Type type) : - _cullFunctor{ cullFunctor }, - _detailType(type) {} - - CullShapeBounds(CullFunctor cullFunctor) : - _cullFunctor{ cullFunctor } { - } - - void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); - - private: - - CullFunctor _cullFunctor; - RenderDetails::Type _detailType{ RenderDetails::OTHER }; - - }; - class ApplyCullFunctorOnItemBounds { public: using Inputs = render::VaryingSet2; diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index e925ef960d..3ed42df59b 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -208,6 +208,11 @@ bool ViewFrustum::sphereIntersectsFrustum(const glm::vec3& center, float radius) } bool ViewFrustum::boxIntersectsFrustum(const AABox& box) const { + // FIXME: remove once we fix culling + if (_isOblique) { + return true; + } + // only check against frustum for(int i = 0; i < NUM_FRUSTUM_PLANES; i++) { const glm::vec3& normal = _planes[i].getNormal(); diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 9c80538e60..a81c646673 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -51,6 +51,7 @@ public: void setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip); void setFocalLength(float focalLength) { _focalLength = focalLength; } bool isPerspective() const; + void setIsOblique(bool isOblique) { _isOblique = isOblique; } // getters for lens attributes const glm::mat4& getProjection() const { return _projection; } @@ -103,7 +104,6 @@ public: bool pointIntersectsFrustum(const glm::vec3& point) const; bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const; - bool cubeIntersectsFrustum(const AACube& box) const; bool boxIntersectsFrustum(const AABox& box) const; bool boxInsideFrustum(const AABox& box) const; @@ -175,6 +175,8 @@ private: float _nearClip { DEFAULT_NEAR_CLIP }; float _farClip { DEFAULT_FAR_CLIP }; + bool _isOblique { false }; + const char* debugPlaneName (int plane) const; // Used to project points From 56860bea993af6251e84f23842aa5da6c120f519 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 18 Nov 2023 00:25:09 -0800 Subject: [PATCH 05/18] fix cpu frustum culling (hacky?) --- .../src/RenderableEntityItem.cpp | 3 +- libraries/shared/src/ViewFrustum.cpp | 56 +++++++++++-------- libraries/shared/src/ViewFrustum.h | 3 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index d0891d16b1..1fef0debdb 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -307,8 +307,7 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { projection[2][2] = c.z + 1.0f; projection[3][2] = c.w; - viewFrustum.setProjection(projection); - viewFrustum.setIsOblique(true); + viewFrustum.setProjection(projection, true); } void EntityRenderer::render(RenderArgs* args) { diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 3ed42df59b..daa08b5dbc 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -53,7 +53,7 @@ static const glm::vec4 NDC_VALUES[NUM_FRUSTUM_CORNERS] = { glm::vec4(-1.0f, 1.0f, 1.0f, 1.0f), }; -void ViewFrustum::setProjection(const glm::mat4& projection) { +void ViewFrustum::setProjection(const glm::mat4& projection, bool isOblique) { _projection = projection; glm::mat4 inverseProjection = glm::inverse(projection); @@ -63,16 +63,21 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { _corners[i] /= _corners[i].w; } - // compute frustum properties - _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; - _farClip = -_corners[BOTTOM_LEFT_FAR].z; - _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / - (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); - glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); - top /= top.w; - _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); - _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; - _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; + // HACK: these calculations aren't correct for our oblique mirror frustums, but we can just reuse the values from the original + // frustum since these values are only used on the CPU. + if (!isOblique) { + // compute frustum properties + _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; + _farClip = -_corners[BOTTOM_LEFT_FAR].z; + _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / + (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); + glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); + top /= top.w; + _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); + _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; + _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; + } + _isOblique = isOblique; } void ViewFrustum::setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip) { @@ -109,12 +114,24 @@ void ViewFrustum::calculate() { // the function set3Points assumes that the points are given in counter clockwise order, assume you // are inside the frustum, facing the plane. Start with any point, and go counter clockwise for // three consecutive points - _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); - _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); - _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); - _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); + if (!_isOblique) { + _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); + _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); + _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); + _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); + } else { + Corners near = getCorners(_nearClip); + Corners far = getCorners(_farClip); + + _planes[TOP_PLANE].set3Points(near.topRight, near.topLeft, far.topLeft); + _planes[BOTTOM_PLANE].set3Points(near.bottomLeft, near.bottomRight, far.bottomRight); + _planes[LEFT_PLANE].set3Points(near.bottomLeft, far.bottomLeft, far.topLeft); + _planes[RIGHT_PLANE].set3Points(far.bottomRight, near.bottomRight, far.topRight); + _planes[NEAR_PLANE].set3Points(near.bottomRight, near.bottomLeft, near.topLeft); + _planes[FAR_PLANE].set3Points(far.bottomLeft, far.bottomRight, far.topRight); + } // Also calculate our projection matrix in case people want to project points... // Projection matrix : Field of View, ratio, display range : near to far @@ -208,11 +225,6 @@ bool ViewFrustum::sphereIntersectsFrustum(const glm::vec3& center, float radius) } bool ViewFrustum::boxIntersectsFrustum(const AABox& box) const { - // FIXME: remove once we fix culling - if (_isOblique) { - return true; - } - // only check against frustum for(int i = 0; i < NUM_FRUSTUM_PLANES; i++) { const glm::vec3& normal = _planes[i].getNormal(); diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index a81c646673..fa66a0a87e 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -47,11 +47,10 @@ public: const glm::vec3& getRight() const { return _right; } // setters for lens attributes - void setProjection(const glm::mat4 & projection); + void setProjection(const glm::mat4& projection, bool isOblique = false); void setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip); void setFocalLength(float focalLength) { _focalLength = focalLength; } bool isPerspective() const; - void setIsOblique(bool isOblique) { _isOblique = isOblique; } // getters for lens attributes const glm::mat4& getProjection() const { return _projection; } From 093cf2977802394f6f4ffb7ad1ba6bc40ac5e55a Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 18 Nov 2023 18:41:08 -0800 Subject: [PATCH 06/18] fix mirrors in deferred --- libraries/render-utils/src/DeferredLightingEffect.cpp | 1 + libraries/render-utils/src/DeferredLightingEffect.h | 4 ++-- libraries/render-utils/src/RenderDeferredTask.cpp | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 8d7fc345ac..3eb5924d19 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -286,6 +286,7 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); + outputs.edit2() = _deferredFramebuffer->getDeferredFramebuffer(); gpu::doInBatch("PrepareDeferred::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 4779376410..058e0a4cbf 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -78,8 +78,8 @@ class PrepareDeferred { public: // Inputs: primaryFramebuffer and lightingModel using Inputs = render::VaryingSet2 ; - // Output: DeferredFramebuffer, LightingFramebuffer - using Outputs = render::VaryingSet2; + // Output: DeferredFramebuffer, LightingFramebuffer, the framebuffer to be used for mirrors (same as DeferredFramebuffer) + using Outputs = render::VaryingSet3; using JobModel = render::Job::ModelIO; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 92208450ef..fd10452dfa 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -157,6 +157,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); + const auto mirrorTargetFramebuffer = prepareDeferredOutputs.getN(2); // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", scaledPrimaryFramebuffer); @@ -166,7 +167,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { - const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, scaledPrimaryFramebuffer, jitter).asVarying(); + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, mirrorTargetFramebuffer, jitter).asVarying(); for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); } From a630a6f9c905de7144c577bccf11e4067e40f8c3 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 18 Nov 2023 23:04:17 -0800 Subject: [PATCH 07/18] mirrors on models + text --- interface/src/Application.cpp | 1 + .../src/avatars-renderer/Avatar.cpp | 2 +- .../src/RenderableEntityItem.cpp | 5 ++ .../src/RenderableEntityItem.h | 2 + .../src/RenderableModelEntityItem.cpp | 4 -- .../src/RenderableTextEntityItem.cpp | 30 ++++++++++-- .../src/RenderableTextEntityItem.h | 2 + .../render-utils/src/MeshPartPayload.cpp | 10 +++- libraries/render-utils/src/Model.cpp | 8 +++- libraries/render-utils/src/TextRenderer3D.cpp | 11 ++--- libraries/render-utils/src/TextRenderer3D.h | 9 ++-- .../src/render-utils/sdf_text3D.slp | 2 +- libraries/render-utils/src/sdf_text3D.slf | 14 +++++- libraries/render-utils/src/text/Font.cpp | 46 ++++++++++--------- libraries/render-utils/src/text/Font.h | 28 +++++++++-- libraries/shared/src/MirrorMode.cpp | 11 +++++ libraries/shared/src/MirrorMode.h | 11 +++++ 17 files changed, 142 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 37204b0f9b..3e8e811c32 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2479,6 +2479,7 @@ Application::Application( copyViewFrustum(viewFrustum); return viewFrustum.getPosition(); }); + MirrorModeHelpers::setComputeMirrorViewOperator(EntityRenderer::computeMirrorViewOperator); DependencyManager::get()->setKickConfirmationOperator([this] (const QUuid& nodeID, unsigned int banFlags) { userKickConfirmation(nodeID, banFlags); }); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index b2d6a6260b..790b45843c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1120,7 +1120,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - displayNameRenderer->draw(batch, text_x, -text_y, glm::vec2(-1.0f), nameUTF8.data(), textColor, true, forward); + displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), forward }); } } } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 1fef0debdb..aec9f092b9 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -237,7 +237,11 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { mirrorMode = _mirrorMode; portalExitID = _portalExitID; }); + computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +} +void EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation); glm::mat4 worldToIn = glm::inverse(inToWorld); @@ -284,6 +288,7 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(outPropertiesPosition, 1.0f); glm::vec3 cameraSpaceNormal = glm::transpose(view) * (outPropertiesRotation * glm::vec4(0, 0, -1, 0)); glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); + // Make sure we pick the direction facing away from us if (clipPlane.w > 0.0f) { clipPlane *= -1.0f; } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index bfec4743f3..fceba6f0e6 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -76,6 +76,8 @@ public: virtual Item::Bound getBound(RenderArgs* args) override; bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override; void computeMirrorView(ViewFrustum& viewFrustum) const override; + static void computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ae3f261d48..6b83d87732 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1085,10 +1085,6 @@ void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const Mod builder.withSubMetaCulled(); } - if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { - builder.withMirror(); - } - if (didVisualGeometryRequestSucceed) { _itemKey = builder.build(); } else { diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index a3ccf78593..6fd99a69fd 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -181,7 +181,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { } auto geometryCache = DependencyManager::get(); - if (pipelineType == Pipeline::SIMPLE) { + if (pipelineType == Pipeline::SIMPLE || pipelineType == Pipeline::MIRROR) { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), backgroundColor, _geometryID); } else { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), glm::vec2(0.0f), glm::vec2(1.0f), backgroundColor, _geometryID); @@ -261,6 +261,10 @@ ItemKey entities::TextPayload::getKey() const { builder.withInvisible(); } + if (textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull())) { + builder.withMirror(); + } + return builder; } } @@ -312,6 +316,16 @@ bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set(); + if (entityTreeRenderer) { + auto renderable = entityTreeRenderer->renderableForEntityId(_entityID); + if (renderable) { + return renderable->computeMirrorView(viewFrustum); + } + } +} + void entities::TextPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("TextPayload::render"); Q_ASSERT(args->_batch); @@ -336,12 +350,15 @@ void entities::TextPayload::render(RenderArgs* args) { glm::vec3 dimensions; glm::vec4 textColor; + bool mirror; textRenderable->withReadLock([&] { transform = textRenderable->_renderTransform; dimensions = textRenderable->_dimensions; float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f; textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha); + + mirror = textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull()); }); bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD; @@ -363,9 +380,8 @@ void entities::TextPayload::render(RenderArgs* args) { batch.setModelTransform(transform); glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin)); - textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale, - textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect, - textRenderable->_alignment, textRenderable->_unlit, forward); + textRenderer->draw(batch, textRenderable->_font, { textRenderable->_text, textColor, effectColor, { textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale }, + bounds / scale, scale, textRenderable->_effectThickness, textRenderable->_effect, textRenderable->_alignment, textRenderable->_unlit, forward, mirror }); } namespace render { @@ -401,4 +417,10 @@ template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Poi return false; } +template <> void payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) { + if (payload) { + payload->computeMirrorView(viewFrustum); + } +} + } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index 8a18554dea..00b9a1ec19 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -101,6 +101,7 @@ public: ShapeKey getShapeKey() const; void render(RenderArgs* args); bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; + void computeMirrorView(ViewFrustum& viewFrustum) const; protected: QUuid _entityID; @@ -117,6 +118,7 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload); template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set& containingZones); + template <> void payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum); } #endif // hifi_RenderableTextEntityItem_h diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index de88381468..43d0f379bf 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -221,6 +221,10 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withSubMetaCulled(); } + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + builder.withMirror(); + } + _itemKey = builder.build(); } @@ -349,7 +353,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned())); batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); - } else { + } else if (!_itemKey.isMirror()) { // apply material properties if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; @@ -381,7 +385,9 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set& blendshapeBuffers, const QVector& blendedMeshSizes) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 066e8cb1d8..7d622ab489 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1078,9 +1078,11 @@ void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& sce } render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [mirrorMode](ModelMeshPartPayload& data) { + transaction.updateItem(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) { data.setMirrorMode(mirrorMode); + data.updateKey(renderItemsKey); }); } scene->enqueueTransaction(transaction); @@ -1096,9 +1098,11 @@ void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointe } render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [portalExitID](ModelMeshPartPayload& data) { + transaction.updateItem(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) { data.setPortalExitID(portalExitID); + data.updateKey(renderItemsKey); }); } scene->enqueueTransaction(transaction); diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 76d8374fb7..8ab1b8e0e9 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -40,21 +40,18 @@ float TextRenderer3D::getFontSize() const { return 0.0f; } -void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, - const QString& str, const glm::vec4& color, bool unlit, bool forward) { +void TextRenderer3D::draw(gpu::Batch& batch, const Font::DrawProps& props) { if (_font) { - _font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, TextAlignment::LEFT, { x, y }, bounds, 1.0f, unlit, forward); + _font->drawString(batch, _drawInfo, props); } } -void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, - const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, - float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward) { +void TextRenderer3D::draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props) { if (font != _family) { _family = font; _font = Font::load(_family); } if (_font) { - _font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, alignment, { x, y }, bounds, scale, unlit, forward); + _font->drawString(batch, _drawInfo, props); } } \ No newline at end of file diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index edccf1429c..9db93e9dcc 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -26,12 +26,9 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const; // Pixel size - - void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, - const QString& str, const glm::vec4& color, bool unlit, bool forward); - void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, - const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, - float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward); + + void draw(gpu::Batch& batch, const Font::DrawProps& props); + void draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props); private: TextRenderer3D(const char* family); diff --git a/libraries/render-utils/src/render-utils/sdf_text3D.slp b/libraries/render-utils/src/render-utils/sdf_text3D.slp index 118135d099..f3f9af59aa 100644 --- a/libraries/render-utils/src/render-utils/sdf_text3D.slp +++ b/libraries/render-utils/src/render-utils/sdf_text3D.slp @@ -1 +1 @@ -DEFINES (translucent unlit:f)/forward \ No newline at end of file +DEFINES (translucent unlit:f)/forward mirror:f \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index c5bed1ecab..ebcfe52f4d 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -41,6 +41,12 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; #define _texCoord1 _texCoord01.zw layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reusing the fade texcoord locations here +<@if HIFI_USE_MIRROR@> + <@include graphics/ShaderConstants.h@> + + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; +<@endif@> + void main() { vec4 color = evalSDFSuperSampled(_texCoord0, _glyphBounds); @@ -51,13 +57,17 @@ void main() { } <@endif@> +<@if HIFI_USE_MIRROR@> + color.rgb = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; +<@endif@> + <@if HIFI_USE_UNLIT@> <@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> - _fragColor0 = vec4(color.rgb * isUnlitEnabled(), color.a); + _fragColor0 = vec4(color.rgb * isUnlitEnabled(), 1.0); <@else@> packDeferredFragmentUnlit( normalize(_normalWS), - color.a, + 1.0, color.rgb); <@endif@> <@else@> diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 1a31e80d7d..95a3d895e8 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -29,7 +29,7 @@ static std::mutex fontMutex; -std::map, gpu::PipelinePointer> Font::_pipelines; +std::map, gpu::PipelinePointer> Font::_pipelines; gpu::Stream::FormatPointer Font::_format; struct TextureVertex { @@ -277,6 +277,7 @@ void Font::setupGPU() { if (_pipelines.empty()) { using namespace shader::render_utils::program; + // transparent, unlit, forward static const std::vector> keys = { std::make_tuple(false, false, false, sdf_text3D), std::make_tuple(true, false, false, sdf_text3D_translucent), std::make_tuple(false, true, false, sdf_text3D_unlit), std::make_tuple(true, true, false, sdf_text3D_translucent_unlit), @@ -284,18 +285,23 @@ void Font::setupGPU() { std::make_tuple(false, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_unlit_forward*/), std::make_tuple(true, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_translucent_unlit_forward*/) }; for (auto& key : keys) { + bool transparent = std::get<0>(key); + bool unlit = std::get<1>(key); + bool forward = std::get<2>(key); + auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, !std::get<0>(key), gpu::LESS_EQUAL); - state->setBlendFunction(std::get<0>(key), + state->setDepthTest(true, !transparent, gpu::LESS_EQUAL); + state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - if (std::get<0>(key)) { + if (transparent) { PrepareStencil::testMask(*state); } else { PrepareStencil::testMaskDrawShape(*state); } - _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key))] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + _pipelines[std::make_tuple(transparent, unlit, forward, false)] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + _pipelines[std::make_tuple(transparent, unlit, forward, true)] = gpu::Pipeline::create(gpu::Shader::createProgram(forward ? sdf_text3D_forward_mirror : sdf_text3D_mirror), state); } // Sanity checks @@ -444,32 +450,30 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm } } -void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, - const glm::vec2& origin, const glm::vec2& bounds, float scale, bool unlit, bool forward) { - if (!_loaded || str == "") { +void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const DrawProps& props) { + if (!_loaded || props.str == "") { return; } - int textEffect = (int)effect; + int textEffect = (int)props.effect; const int SHADOW_EFFECT = (int)TextEffect::SHADOW_EFFECT; // If we're switching to or from shadow effect mode, we need to rebuild the vertices - if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin || alignment != _alignment || + if (props.str != drawInfo.string || props.bounds != drawInfo.bounds || props.origin != drawInfo.origin || props.alignment != _alignment || (drawInfo.params.effect != textEffect && (textEffect == SHADOW_EFFECT || drawInfo.params.effect == SHADOW_EFFECT)) || - (textEffect == SHADOW_EFFECT && scale != _scale)) { - _scale = scale; - _alignment = alignment; - buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT, alignment); + (textEffect == SHADOW_EFFECT && props.scale != _scale)) { + _scale = props.scale; + _alignment = props.alignment; + buildVertices(drawInfo, props.str, props.origin, props.bounds, props.scale, textEffect == SHADOW_EFFECT, props.alignment); } setupGPU(); - if (!drawInfo.paramsBuffer || drawInfo.params.color != color || drawInfo.params.effectColor != effectColor || - drawInfo.params.effectThickness != effectThickness || drawInfo.params.effect != textEffect) { - drawInfo.params.color = color; - drawInfo.params.effectColor = effectColor; - drawInfo.params.effectThickness = effectThickness; + if (!drawInfo.paramsBuffer || drawInfo.params.color != props.color || drawInfo.params.effectColor != props.effectColor || + drawInfo.params.effectThickness != props.effectThickness || drawInfo.params.effect != textEffect) { + drawInfo.params.color = props.color; + drawInfo.params.effectColor = props.effectColor; + drawInfo.params.effectThickness = props.effectThickness; drawInfo.params.effect = textEffect; // need the gamma corrected color here @@ -484,7 +488,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString drawInfo.paramsBuffer->setSubData(0, sizeof(DrawParams), (const gpu::Byte*)&gpuDrawParams); } - batch.setPipeline(_pipelines[std::make_tuple(color.a < 1.0f, unlit, forward)]); + batch.setPipeline(_pipelines[std::make_tuple(props.color.a < 1.0f, props.unlit, props.forward, props.mirror)]); batch.setInputFormat(_format); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 322e96439e..e8a353a686 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -57,10 +57,30 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const { return _fontSize; } + struct DrawProps { + DrawProps(const QString& str, const glm::vec4& color, const glm::vec3& effectColor, const glm::vec2& origin, const glm::vec2& bounds, + float scale, float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward, bool mirror) : + str(str), color(color), effectColor(effectColor), origin(origin), bounds(bounds), scale(scale), effectThickness(effectThickness), + effect(effect), alignment(alignment), unlit(unlit), forward(forward), mirror(mirror) {} + DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, bool forward) : + str(str), color(color), origin(origin), bounds(bounds), forward(forward) {} + + const QString& str; + const glm::vec4& color; + const glm::vec3& effectColor { glm::vec3(0.0f) }; + const glm::vec2& origin; + const glm::vec2& bounds; + float scale { 1.0f }; + float effectThickness { 0.0f }; + TextEffect effect { TextEffect::NO_EFFECT }; + TextAlignment alignment { TextAlignment::LEFT }; + bool unlit = true; + bool forward; + bool mirror = false; + }; + // Render string to batch - void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, - const glm::vec2& origin, const glm::vec2& bound, float scale, bool unlit, bool forward); + void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const DrawProps& props); static Pointer load(const QString& family); @@ -105,7 +125,7 @@ private: gpu::TexturePointer _texture; gpu::BufferStreamPointer _stream; - static std::map, gpu::PipelinePointer> _pipelines; + static std::map, gpu::PipelinePointer> _pipelines; static gpu::Stream::FormatPointer _format; }; diff --git a/libraries/shared/src/MirrorMode.cpp b/libraries/shared/src/MirrorMode.cpp index 53a51b1c1c..f84948c6e4 100644 --- a/libraries/shared/src/MirrorMode.cpp +++ b/libraries/shared/src/MirrorMode.cpp @@ -15,6 +15,8 @@ const char* MirrorModeNames[] = { }; static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0])); +std::function MirrorModeHelpers::_computeMirrorViewOperator = + [](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return; }; QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) { @@ -23,3 +25,12 @@ QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { return MirrorModeNames[(int)mode]; } + +void MirrorModeHelpers::setComputeMirrorViewOperator(std::function computeMirrorViewOperator) { + _computeMirrorViewOperator = computeMirrorViewOperator; +} + +void MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { + _computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +} \ No newline at end of file diff --git a/libraries/shared/src/MirrorMode.h b/libraries/shared/src/MirrorMode.h index 38af190070..2b2fa1d62e 100644 --- a/libraries/shared/src/MirrorMode.h +++ b/libraries/shared/src/MirrorMode.h @@ -9,8 +9,12 @@ #ifndef hifi_MirrorMode_h #define hifi_MirrorMode_h +#include + #include "QString" +#include "ViewFrustum.h" + /*@jsdoc *

If an entity is rendered as a mirror, a portal, or normally.

* @@ -35,6 +39,13 @@ enum class MirrorMode { class MirrorModeHelpers { public: static QString getNameForMirrorMode(MirrorMode mode); + + static void setComputeMirrorViewOperator(std::function computeMirrorViewOperator); + static void computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); + +private: + static std::function _computeMirrorViewOperator; }; #endif // hifi_MirrorMode_h From 3336efb6ee3a231caff58adcf9417eb8ad4a3041 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sun, 19 Nov 2023 14:54:31 -0800 Subject: [PATCH 08/18] portals use exit as ignoreItem --- .../entities-renderer/src/RenderableEntityItem.cpp | 10 ++++++---- .../entities-renderer/src/RenderableEntityItem.h | 6 +++--- .../src/RenderableImageEntityItem.cpp | 6 ++++-- .../src/RenderableTextEntityItem.cpp | 8 +++++--- .../entities-renderer/src/RenderableTextEntityItem.h | 4 ++-- libraries/render-utils/src/MeshPartPayload.cpp | 9 +++++---- libraries/render-utils/src/MeshPartPayload.h | 4 ++-- libraries/render-utils/src/RenderCommonTask.cpp | 10 +++++----- libraries/render/src/render/Item.cpp | 6 +++--- libraries/render/src/render/Item.h | 12 ++++++------ libraries/shared/src/MirrorMode.cpp | 12 ++++++------ libraries/shared/src/MirrorMode.h | 8 ++++---- 12 files changed, 51 insertions(+), 44 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index aec9f092b9..0c93a795ed 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -226,7 +226,7 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co return true; } -void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { +ItemID EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { glm::vec3 inPropertiesPosition; glm::quat inPropertiesRotation; MirrorMode mirrorMode; @@ -237,11 +237,11 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { mirrorMode = _mirrorMode; portalExitID = _portalExitID; }); - computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); + return computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); } -void EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID) { +ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation); glm::mat4 worldToIn = glm::inverse(inToWorld); @@ -313,6 +313,8 @@ void EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const g projection[3][2] = c.w; viewFrustum.setProjection(projection, true); + + return (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID; } void EntityRenderer::render(RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index fceba6f0e6..99dbffbc72 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -75,9 +75,9 @@ public: virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override; virtual Item::Bound getBound(RenderArgs* args) override; bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override; - void computeMirrorView(ViewFrustum& viewFrustum) const override; - static void computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID); + ItemID computeMirrorView(ViewFrustum& viewFrustum) const override; + static ItemID computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 4c18653d4f..66a5d0d609 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -199,8 +199,10 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent)); } else if (pipelineType == Pipeline::SIMPLE) { batch->setResourceTexture(0, _texture->getGPUTexture()); - } else if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; + } else if (pipelineType == Pipeline::MATERIAL) { + if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; + } } DependencyManager::get()->renderQuad( diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 6fd99a69fd..a15e2839a4 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -316,7 +316,7 @@ bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set(); if (entityTreeRenderer) { auto renderable = entityTreeRenderer->renderableForEntityId(_entityID); @@ -324,6 +324,7 @@ void entities::TextPayload::computeMirrorView(ViewFrustum& viewFrustum) const { return renderable->computeMirrorView(viewFrustum); } } + return Item::INVALID_ITEM_ID; } void entities::TextPayload::render(RenderArgs* args) { @@ -417,10 +418,11 @@ template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Poi return false; } -template <> void payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) { +template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) { if (payload) { - payload->computeMirrorView(viewFrustum); + return payload->computeMirrorView(viewFrustum); } + return Item::INVALID_ITEM_ID; } } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index 00b9a1ec19..f48bb8085f 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -101,7 +101,7 @@ public: ShapeKey getShapeKey() const; void render(RenderArgs* args); bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; - void computeMirrorView(ViewFrustum& viewFrustum) const; + ItemID computeMirrorView(ViewFrustum& viewFrustum) const; protected: QUuid _entityID; @@ -118,7 +118,7 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload); template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set& containingZones); - template <> void payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum); + template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum); } #endif // hifi_RenderableTextEntityItem_h diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 43d0f379bf..9adeb39e7c 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -384,10 +384,10 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set& blendshapeBuffers, const QVector& blendedMeshSizes) { @@ -440,9 +440,10 @@ template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin return false; } -template <> void payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum) { +template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum) { if (payload) { - payload->computeMirrorView(viewFrustum); + return payload->computeMirrorView(viewFrustum); } + return Item::INVALID_ITEM_ID; } } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 6e0bb91a30..7e331a9497 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -61,7 +61,7 @@ public: void setMirrorMode(MirrorMode mirrorMode) { _mirrorMode = mirrorMode; } void setPortalExitID(const QUuid& portalExitID) { _portalExitID = portalExitID; } bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; - void computeMirrorView(ViewFrustum& viewFrustum) const; + render::ItemID computeMirrorView(ViewFrustum& viewFrustum) const; void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } @@ -112,7 +112,7 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set& containingZones); - template <> void payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum); + template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum); } diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index a3355ea805..7647a1b8d2 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -300,12 +300,12 @@ public: _cachedArgsPointer->_ignoreItem = args->_ignoreItem; _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; - args->_blitFramebuffer = _mirrorFramebuffer; - args->_ignoreItem = mirror.id; - args->_mirrorDepth = _depth; - ViewFrustum srcViewFrustum = args->getViewFrustum(); - args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); + ItemID portalExitID = args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); + + args->_blitFramebuffer = _mirrorFramebuffer; + args->_ignoreItem = portalExitID != Item::INVALID_ITEM_ID ? portalExitID : mirror.id; + args->_mirrorDepth = _depth; // Without calculating the bound planes, the mirror will use the same culling frustum as the main camera, // which is not what we want here. diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 23e5570736..1633523267 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -161,10 +161,10 @@ namespace render { return payload->passesZoneOcclusionTest(containingZones); } - template <> void payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum) { + template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum) { if (!payload) { - return; + return Item::INVALID_ITEM_ID; } - payload->computeMirrorView(viewFrustum); + return payload->computeMirrorView(viewFrustum); } } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index c2f03b4e05..f91b887fcb 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -450,7 +450,7 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; - virtual void computeMirrorView(ViewFrustum& viewFrustum) const = 0; + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; ~PayloadInterface() {} @@ -505,7 +505,7 @@ public: bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); } - void computeMirrorView(ViewFrustum& viewFrustum) const { _payload->computeMirrorView(viewFrustum); } + ItemID computeMirrorView(ViewFrustum& viewFrustum) const { return _payload->computeMirrorView(viewFrustum); } // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -562,7 +562,7 @@ template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payl template bool payloadPassesZoneOcclusionTest(const std::shared_ptr& payloadData, const std::unordered_set& containingZones) { return true; } // Mirror Interface -template void payloadComputeMirrorView(const std::shared_ptr& payloadData, ViewFrustum& viewFrustum) { return; } +template ItemID payloadComputeMirrorView(const std::shared_ptr& payloadData, ViewFrustum& viewFrustum) { return Item::INVALID_ITEM_ID; } // THe Payload class is the real Payload to be used // THis allow anything to be turned into a Payload as long as the required interface functions are available @@ -590,7 +590,7 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override { return payloadPassesZoneOcclusionTest(_data, containingZones); } - virtual void computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView(_data, viewFrustum); } + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView(_data, viewFrustum); } protected: DataPointer _data; @@ -647,7 +647,7 @@ public: virtual void render(RenderArgs* args) = 0; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; - virtual void computeMirrorView(ViewFrustum& viewFrustum) const = 0; + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface virtual void handleBlendedVertices(int blendshapeNumber, const QVector& blendshapeOffsets, @@ -660,7 +660,7 @@ template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, Re template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems); template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload); template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set& containingZones); -template <> void payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum); +template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum); typedef Item::PayloadPointer PayloadPointer; typedef std::vector Payloads; diff --git a/libraries/shared/src/MirrorMode.cpp b/libraries/shared/src/MirrorMode.cpp index f84948c6e4..272eb5d7c0 100644 --- a/libraries/shared/src/MirrorMode.cpp +++ b/libraries/shared/src/MirrorMode.cpp @@ -15,8 +15,8 @@ const char* MirrorModeNames[] = { }; static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0])); -std::function MirrorModeHelpers::_computeMirrorViewOperator = - [](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return; }; +std::function MirrorModeHelpers::_computeMirrorViewOperator = + [](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return 0; }; QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) { @@ -26,11 +26,11 @@ QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { return MirrorModeNames[(int)mode]; } -void MirrorModeHelpers::setComputeMirrorViewOperator(std::function computeMirrorViewOperator) { +void MirrorModeHelpers::setComputeMirrorViewOperator(std::function computeMirrorViewOperator) { _computeMirrorViewOperator = computeMirrorViewOperator; } -void MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID) { - _computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +uint32_t MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { + return _computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); } \ No newline at end of file diff --git a/libraries/shared/src/MirrorMode.h b/libraries/shared/src/MirrorMode.h index 2b2fa1d62e..e48e564df0 100644 --- a/libraries/shared/src/MirrorMode.h +++ b/libraries/shared/src/MirrorMode.h @@ -40,12 +40,12 @@ class MirrorModeHelpers { public: static QString getNameForMirrorMode(MirrorMode mode); - static void setComputeMirrorViewOperator(std::function computeMirrorViewOperator); - static void computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID); + static void setComputeMirrorViewOperator(std::function computeMirrorViewOperator); + static uint32_t computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); private: - static std::function _computeMirrorViewOperator; + static std::function _computeMirrorViewOperator; }; #endif // hifi_MirrorMode_h From 6af7b9f77214790cf0d8425720f508d0d6322c33 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sun, 19 Nov 2023 15:17:18 -0800 Subject: [PATCH 09/18] cleanup --- libraries/entities-renderer/src/RenderableEntityItem.cpp | 4 +++- libraries/render-utils/src/sdf_text3D.slf | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 0c93a795ed..ef91c1f034 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -248,6 +248,7 @@ ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3 outPropertiesPosition = inPropertiesPosition; glm::quat outPropertiesRotation = inPropertiesRotation; glm::mat4 outToWorld = inToWorld; + bool foundPortalExit = false; if (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) { auto renderer = DependencyManager::get(); if (renderer) { @@ -258,6 +259,7 @@ ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const }); outToWorld = glm::translate(outPropertiesPosition) * glm::mat4_cast(outPropertiesRotation); + foundPortalExit = true; } } } @@ -314,7 +316,7 @@ ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const viewFrustum.setProjection(projection, true); - return (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID; + return foundPortalExit ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID; } void EntityRenderer::render(RenderArgs* args) { diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index ebcfe52f4d..bf9bb0babd 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -59,15 +59,16 @@ void main() { <@if HIFI_USE_MIRROR@> color.rgb = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; + color.a = 1.0; <@endif@> <@if HIFI_USE_UNLIT@> <@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> - _fragColor0 = vec4(color.rgb * isUnlitEnabled(), 1.0); + _fragColor0 = vec4(color.rgb * isUnlitEnabled(), color.a); <@else@> packDeferredFragmentUnlit( normalize(_normalWS), - 1.0, + color.a, color.rgb); <@endif@> <@else@> From 3e0c50e077c6c1c87a878cf4d5cb1afd0e3564cc Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Mon, 4 Dec 2023 14:44:28 -0800 Subject: [PATCH 10/18] wild guess to handle view correction, hide portalExitID in create when mirrorMode != portal --- libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp | 5 +++++ libraries/gpu-gl-common/src/gpu/gl/GLBackend.h | 2 ++ .../gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp | 6 +++++- libraries/gpu/src/gpu/Batch.cpp | 6 ++++++ libraries/gpu/src/gpu/Batch.h | 2 ++ libraries/gpu/src/gpu/FrameIOKeys.h | 1 + libraries/render-utils/src/RenderCommonTask.cpp | 10 ++++++++++ .../entityProperties/html/js/entityProperties.js | 1 + 8 files changed, 32 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index af39458f17..421fef4334 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -81,6 +81,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_disableContextViewCorrection), (&::gpu::gl::GLBackend::do_restoreContextViewCorrection), + (&::gpu::gl::GLBackend::do_setContextMirrorViewCorrection), (&::gpu::gl::GLBackend::do_disableContextStereo), (&::gpu::gl::GLBackend::do_restoreContextStereo), @@ -619,6 +620,10 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param _transform._viewCorrectionEnabled = true; } +void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { + _transform._mirrorViewCorrection = batch._params[paramOffset + 1]._uint != 0; +} + void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 2947649ce7..6e8af35037 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -211,6 +211,7 @@ public: virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final; + virtual void do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final; @@ -433,6 +434,7 @@ protected: Transform _view; CameraCorrection _correction; bool _viewCorrectionEnabled{ true }; + bool _mirrorViewCorrection{ false }; Mat4 _projection; Vec4i _viewport{ 0, 0, 1, 1 }; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp index 67ab502b6b..03c2b17a0e 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp @@ -111,7 +111,11 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) { // FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out? Transform result; - _view.mult(result, _view, _correction.correctionInverse); + glm::mat4 correction = _correction.correctionInverse; + if (_mirrorViewCorrection) { + correction = glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)) * correction; + } + _view.mult(result, _view, correction); if (_skybox) { result.setTranslation(vec3()); } diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index e6217cc600..a41f586d74 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -464,6 +464,12 @@ void Batch::restoreContextViewCorrection() { ADD_COMMAND(restoreContextViewCorrection); } +void Batch::setContextMirrorViewCorrection(bool shouldMirror) { + ADD_COMMAND(setContextMirrorViewCorrection); + uint mirrorFlag = shouldMirror ? 1 : 0; + _params.emplace_back(mirrorFlag); +} + void Batch::disableContextStereo() { ADD_COMMAND(disableContextStereo); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 0a438ea148..f89dd3ea90 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -239,6 +239,7 @@ public: void disableContextViewCorrection(); void restoreContextViewCorrection(); + void setContextMirrorViewCorrection(bool shouldMirror); void disableContextStereo(); void restoreContextStereo(); @@ -340,6 +341,7 @@ public: COMMAND_disableContextViewCorrection, COMMAND_restoreContextViewCorrection, + COMMAND_setContextMirrorViewCorrection, COMMAND_disableContextStereo, COMMAND_restoreContextStereo, diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index 1a98d0decd..2d88158afb 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -181,6 +181,7 @@ constexpr const char* COMMAND_NAMES[] = { "disableContextViewCorrection", "restoreContextViewCorrection", + "setContextMirrorViewCorrection", "disableContextStereo", "restoreContextStereo", diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 7647a1b8d2..263af717f5 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -307,6 +307,11 @@ public: args->_ignoreItem = portalExitID != Item::INVALID_ITEM_ID ? portalExitID : mirror.id; args->_mirrorDepth = _depth; + gpu::doInBatch("SetupMirrorTask::run", args->_context, [&](gpu::Batch& batch) { + bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setContextMirrorViewCorrection(shouldMirror); + }); + // Without calculating the bound planes, the mirror will use the same culling frustum as the main camera, // which is not what we want here. srcViewFrustum.calculate(); @@ -360,6 +365,11 @@ public: gpu::doInBatch("DrawMirrorTask::run", args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; + if (cachedArgs) { + bool shouldMirror = cachedArgs->_mirrorDepth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setContextMirrorViewCorrection(shouldMirror); + } + batch.setFramebuffer(framebuffer); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index ff28925b96..77e43fe829 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -146,6 +146,7 @@ const GROUPS = [ label: "Portal Exit", type: "string", propertyID: "portalExitID", + showPropertyRule: { "mirrorMode": "portal" }, } ] }, From 16341312faaf2367613b7b6753da996b04dc912e Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Wed, 6 Dec 2023 15:59:36 -0800 Subject: [PATCH 11/18] let's try this?? --- .../gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp | 2 +- .../entityProperties/html/js/entityProperties.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp index 03c2b17a0e..b27175a545 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp @@ -113,7 +113,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo Transform result; glm::mat4 correction = _correction.correctionInverse; if (_mirrorViewCorrection) { - correction = glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)) * correction; + correction = correction * glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)); } _view.mult(result, _view, correction); if (_skybox) { diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index 77e43fe829..b509168262 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -127,11 +127,6 @@ const GROUPS = [ }, propertyID: "billboardMode", }, - { - label: "Render With Zones", - type: "multipleZonesSelection", - propertyID: "renderWithZones", - }, { label: "Mirror Mode", type: "dropdown", @@ -147,6 +142,11 @@ const GROUPS = [ type: "string", propertyID: "portalExitID", showPropertyRule: { "mirrorMode": "portal" }, + }, + { + label: "Render With Zones", + type: "multipleZonesSelection", + propertyID: "renderWithZones", } ] }, From 4e5ded0ba963d4cfcbec6c7a73f7038c0bb35b57 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Tue, 12 Dec 2023 15:18:04 -0800 Subject: [PATCH 12/18] plz --- libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp | 5 +++++ .../gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp | 9 +++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 421fef4334..bb79c9073f 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -621,7 +621,12 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param } void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { + bool prevMirrorViewCorrection = _transform._mirrorViewCorrection; _transform._mirrorViewCorrection = batch._params[paramOffset + 1]._uint != 0; + if (prevMirrorViewCorrection != _transform._mirrorViewCorrection) { + static const mat4 flipXScale = glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)); + setCameraCorrection(_transform._correction.correction * flipXScale, _transform._correction.prevView); + } } void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp index b27175a545..d6ccdb52c9 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp @@ -108,14 +108,11 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo if (_invalidView) { // Apply the correction - if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) { + static const mat4 flipXScale = glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)); + if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != (_mirrorViewCorrection ? flipXScale : glm::mat4()))) { // FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out? Transform result; - glm::mat4 correction = _correction.correctionInverse; - if (_mirrorViewCorrection) { - correction = correction * glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)); - } - _view.mult(result, _view, correction); + _view.mult(result, _view, _correction.correctionInverse); if (_skybox) { result.setTranslation(vec3()); } From e0f3657032c77386582fbb24580116d7736562a4 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Wed, 13 Dec 2023 21:58:48 -0800 Subject: [PATCH 13/18] promising --- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 23 ++++++++++++++++--- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 2 ++ .../src/gpu/gl/GLBackendTransform.cpp | 3 +-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index bb79c9073f..f4af949558 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -349,6 +349,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) { case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: case Batch::COMMAND_setProjectionJitter: + case Batch::COMMAND_setContextMirrorViewCorrection: { CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); @@ -386,6 +387,7 @@ void GLBackend::renderPassDraw(const Batch& batch) { case Batch::COMMAND_setModelTransform: case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: + case Batch::COMMAND_setContextMirrorViewCorrection: break; case Batch::COMMAND_draw: @@ -411,6 +413,7 @@ void GLBackend::renderPassDraw(const Batch& batch) { //case Batch::COMMAND_setModelTransform: //case Batch::COMMAND_setViewTransform: //case Batch::COMMAND_setProjectionTransform: + //case Batch::COMMAND_setContextMirrorViewCorrection: case Batch::COMMAND_setProjectionJitter: case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setDepthRangeTransform: @@ -623,9 +626,23 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { bool prevMirrorViewCorrection = _transform._mirrorViewCorrection; _transform._mirrorViewCorrection = batch._params[paramOffset + 1]._uint != 0; - if (prevMirrorViewCorrection != _transform._mirrorViewCorrection) { - static const mat4 flipXScale = glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)); - setCameraCorrection(_transform._correction.correction * flipXScale, _transform._correction.prevView); + + if (_transform._correction.correction != glm::mat4()) { + // If we were previously not flipped, take this opportunity to save our flipped and unflipped matrices. + if (!prevMirrorViewCorrection) { + _transform._unflippedCorrection = _transform._correction.correction; + quat flippedRotation = glm::quat_cast(_transform._unflippedCorrection); + flippedRotation.y *= -1.0f; + flippedRotation.z *= -1.0f; + vec3 flippedTranslation = _transform._unflippedCorrection[3]; + flippedTranslation.x *= -1.0f; + _transform._flippedCorrection = glm::translate(glm::mat4_cast(flippedRotation), flippedTranslation); + } + + if (prevMirrorViewCorrection != _transform._mirrorViewCorrection) { + setCameraCorrection(_transform._mirrorViewCorrection ? _transform._flippedCorrection : _transform._unflippedCorrection, _transform._correction.prevView); + _transform._invalidView = true; + } } } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 6e8af35037..fdc0bf983c 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -434,6 +434,8 @@ protected: Transform _view; CameraCorrection _correction; bool _viewCorrectionEnabled{ true }; + mat4 _unflippedCorrection; + mat4 _flippedCorrection; bool _mirrorViewCorrection{ false }; Mat4 _projection; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp index d6ccdb52c9..67ab502b6b 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTransform.cpp @@ -108,8 +108,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo if (_invalidView) { // Apply the correction - static const mat4 flipXScale = glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, 1.0f)); - if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != (_mirrorViewCorrection ? flipXScale : glm::mat4()))) { + if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) { // FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out? Transform result; _view.mult(result, _view, _correction.correctionInverse); From 5159367b4c29713d3b3cdad83ec2718c3cc110b0 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Mon, 18 Dec 2023 15:42:17 -0800 Subject: [PATCH 14/18] fix paramsOffset and view flipping --- .../display-plugins/OpenGLDisplayPlugin.cpp | 4 +- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 42 +++++++++---------- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 2 +- libraries/gpu/src/gpu/Context.h | 2 +- .../src/ToneMapAndResampleTask.cpp | 2 +- libraries/render/src/render/ResampleTask.cpp | 2 +- tools/gpu-frame-player/src/RenderThread.cpp | 2 +- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 03a463c82a..47f22dfaee 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -357,7 +357,7 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - getGLBackend()->setCameraCorrection(mat4(), mat4(), true); + getGLBackend()->setCameraCorrection(mat4(), mat4(), true, true); for (auto& cursorValue : _cursorsData) { auto& cursorData = cursorValue.second; @@ -701,7 +701,7 @@ void OpenGLDisplayPlugin::present(const std::shared_ptr& if (_currentFrame) { auto correction = getViewCorrection(); - getGLBackend()->setCameraCorrection(correction, _prevRenderView); + getGLBackend()->setCameraCorrection(correction, _prevRenderView, true); _prevRenderView = correction * _currentFrame->view; { withPresentThreadLock([&] { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index f4af949558..c0116274ee 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -387,7 +387,6 @@ void GLBackend::renderPassDraw(const Batch& batch) { case Batch::COMMAND_setModelTransform: case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: - case Batch::COMMAND_setContextMirrorViewCorrection: break; case Batch::COMMAND_draw: @@ -413,10 +412,10 @@ void GLBackend::renderPassDraw(const Batch& batch) { //case Batch::COMMAND_setModelTransform: //case Batch::COMMAND_setViewTransform: //case Batch::COMMAND_setProjectionTransform: - //case Batch::COMMAND_setContextMirrorViewCorrection: case Batch::COMMAND_setProjectionJitter: case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setDepthRangeTransform: + case Batch::COMMAND_setContextMirrorViewCorrection: { PROFILE_RANGE(render_gpu_gl_detail, "transform"); CommandCall call = _commandCalls[(*command)]; @@ -625,24 +624,11 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { bool prevMirrorViewCorrection = _transform._mirrorViewCorrection; - _transform._mirrorViewCorrection = batch._params[paramOffset + 1]._uint != 0; + _transform._mirrorViewCorrection = batch._params[paramOffset]._uint != 0; if (_transform._correction.correction != glm::mat4()) { - // If we were previously not flipped, take this opportunity to save our flipped and unflipped matrices. - if (!prevMirrorViewCorrection) { - _transform._unflippedCorrection = _transform._correction.correction; - quat flippedRotation = glm::quat_cast(_transform._unflippedCorrection); - flippedRotation.y *= -1.0f; - flippedRotation.z *= -1.0f; - vec3 flippedTranslation = _transform._unflippedCorrection[3]; - flippedTranslation.x *= -1.0f; - _transform._flippedCorrection = glm::translate(glm::mat4_cast(flippedRotation), flippedTranslation); - } - - if (prevMirrorViewCorrection != _transform._mirrorViewCorrection) { - setCameraCorrection(_transform._mirrorViewCorrection ? _transform._flippedCorrection : _transform._unflippedCorrection, _transform._correction.prevView); - _transform._invalidView = true; - } + setCameraCorrection(_transform._mirrorViewCorrection ? _transform._flippedCorrection : _transform._unflippedCorrection, _transform._correction.prevView, false); + _transform._invalidView = true; } } @@ -1024,15 +1010,29 @@ void GLBackend::recycle() const { _textureManagement._transferEngine->manageMemory(); } -void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) { +void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset) { auto invCorrection = glm::inverse(correction); auto invPrevView = glm::inverse(prevRenderView); _transform._correction.prevView = (reset ? Mat4() : prevRenderView); _transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView); _transform._correction.correction = correction; _transform._correction.correctionInverse = invCorrection; - _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); - _pipeline._cameraCorrectionBuffer._buffer->flush(); + + if (!_inRenderTransferPass) { + _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); + _pipeline._cameraCorrectionBuffer._buffer->flush(); + } + + if (primary) { + _transform._unflippedCorrection = _transform._correction.correction; + quat flippedRotation = glm::quat_cast(_transform._unflippedCorrection); + flippedRotation.y *= -1.0f; + flippedRotation.z *= -1.0f; + vec3 flippedTranslation = _transform._unflippedCorrection[3]; + flippedTranslation.x *= -1.0f; + _transform._flippedCorrection = glm::translate(glm::mat4_cast(flippedRotation), flippedTranslation); + _transform._mirrorViewCorrection = false; + } } void GLBackend::syncProgram(const gpu::ShaderPointer& program) { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index fdc0bf983c..5545858877 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -121,7 +121,7 @@ public: // Shutdown rendering and persist any required resources void shutdown() override; - void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) override; + void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) override; void render(const Batch& batch) final override; // This call synchronize the Full Backend cache with the current GLState diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 1946f447f8..ebc81f14e9 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -66,7 +66,7 @@ public: virtual void syncProgram(const gpu::ShaderPointer& program) = 0; virtual void recycle() const = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) {} + virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) {} virtual bool supportedTextureFormat(const gpu::Element& format) = 0; diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 6ac5142e45..36a08427cb 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -96,7 +96,7 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + bool shouldMirror = _depth >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index 5206767bd2..af82d249cf 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,7 +167,7 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + bool shouldMirror = _depth >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); diff --git a/tools/gpu-frame-player/src/RenderThread.cpp b/tools/gpu-frame-player/src/RenderThread.cpp index 0089c1577b..de39dacdea 100644 --- a/tools/gpu-frame-player/src/RenderThread.cpp +++ b/tools/gpu-frame-player/src/RenderThread.cpp @@ -122,7 +122,7 @@ void RenderThread::renderFrame(gpu::FramePointer& frame) { if (_correction != glm::mat4()) { std::unique_lock lock(_frameLock); if (_correction != glm::mat4()) { - _backend->setCameraCorrection(_correction, _activeFrame->view); + _backend->setCameraCorrection(_correction, _activeFrame->view, true); //_prevRenderView = _correction * _activeFrame->view; } } From c608e82f22a5b147ef30f469fc874ced8d8ce859 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Thu, 21 Dec 2023 15:41:16 -0800 Subject: [PATCH 15/18] portals shouldn't flip --- libraries/render-utils/src/RenderCommonTask.cpp | 9 ++++++--- libraries/render-utils/src/ToneMapAndResampleTask.cpp | 2 +- libraries/render/src/render/Args.h | 1 + libraries/render/src/render/ResampleTask.cpp | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 263af717f5..a509ede437 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -299,6 +299,7 @@ public: _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_ignoreItem = args->_ignoreItem; _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; + _cachedArgsPointer->_numMirrorFlips = args->_numMirrorFlips; ViewFrustum srcViewFrustum = args->getViewFrustum(); ItemID portalExitID = args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); @@ -306,9 +307,10 @@ public: args->_blitFramebuffer = _mirrorFramebuffer; args->_ignoreItem = portalExitID != Item::INVALID_ITEM_ID ? portalExitID : mirror.id; args->_mirrorDepth = _depth; + args->_numMirrorFlips += portalExitID != Item::INVALID_ITEM_ID ? 0 : 1; gpu::doInBatch("SetupMirrorTask::run", args->_context, [&](gpu::Batch& batch) { - bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + bool shouldMirror = args->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); batch.setContextMirrorViewCorrection(shouldMirror); }); @@ -366,7 +368,7 @@ public: args->_batch = &batch; if (cachedArgs) { - bool shouldMirror = cachedArgs->_mirrorDepth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + bool shouldMirror = cachedArgs->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); batch.setContextMirrorViewCorrection(shouldMirror); } @@ -390,11 +392,12 @@ public: args->_batch = nullptr; }); - // Restore the blit framebuffer after we've sampled from it if (cachedArgs) { + // Restore the blit framebuffer after we've sampled from it args->_blitFramebuffer = cachedArgs->_blitFramebuffer; args->_ignoreItem = cachedArgs->_ignoreItem; args->_mirrorDepth = cachedArgs->_mirrorDepth; + args->_numMirrorFlips = cachedArgs->_numMirrorFlips; } } diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 36a08427cb..1ea9deb1fa 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -96,7 +96,7 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - bool shouldMirror = _depth >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index 60daa35729..fb7d698672 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -162,6 +162,7 @@ namespace render { ItemID _ignoreItem { 0 }; size_t _mirrorDepth { 0 }; + size_t _numMirrorFlips { 0 }; }; } diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index af82d249cf..e77dda600c 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,7 +167,7 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - bool shouldMirror = _depth >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); From 446207a4b4303858eae8287f0b2690c210667c13 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Wed, 3 Jan 2024 16:33:45 -0800 Subject: [PATCH 16/18] fix portal view calculation --- libraries/entities-renderer/src/RenderableEntityItem.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index ef91c1f034..09bbfb9284 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -268,6 +268,10 @@ ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3 cameraPositionWorld = viewFrustum.getPosition(); glm::vec3 cameraPositionIn = vec3(worldToIn * vec4(cameraPositionWorld, 1.0f)); glm::vec3 mirrorCameraPositionIn = vec3(cameraPositionIn.x, cameraPositionIn.y, -cameraPositionIn.z); + if (foundPortalExit) { + // portals also flip over x + mirrorCameraPositionIn.x *= -1.0f; + } glm::vec3 mirrorCameraPositionWorld = vec3(outToWorld * vec4(mirrorCameraPositionIn, 1.0f)); // get mirror camera rotation by reflecting main camera rotation in mirror space @@ -276,6 +280,10 @@ ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::quat mainCameraRotationMirror = worldToIn * glm::mat4_cast(mainCameraRotationWorld); glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); + if (foundPortalExit) { + // portals also flip over x + mirrorCameraRotationMirror = glm::quat(mirrorCameraRotationMirror.w, mirrorCameraRotationMirror.x, -mirrorCameraRotationMirror.y, -mirrorCameraRotationMirror.z); + } glm::quat mirrorCameraRotationWorld = outToWorld * glm::mat4_cast(mirrorCameraRotationMirror); viewFrustum.setPosition(mirrorCameraPositionWorld); From c6e4e5de37ce4190d3212bb133ec1bb5b9b1adef Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Sat, 13 Jan 2024 11:18:08 +0100 Subject: [PATCH 17/18] Revert "Mirrors + Portals" --- interface/src/Application.cpp | 1 - interface/src/SecondaryCamera.cpp | 3 +- interface/src/avatar/MyAvatar.cpp | 3 +- .../scripting/RenderScriptingInterface.cpp | 24 +-- .../src/avatars-renderer/Avatar.cpp | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 4 +- .../src/RenderableEntityItem.cpp | 114 +------------ .../src/RenderableEntityItem.h | 12 +- .../src/RenderableGizmoEntityItem.cpp | 3 +- .../src/RenderableGridEntityItem.cpp | 3 +- .../src/RenderableImageEntityItem.cpp | 9 +- .../src/RenderableLineEntityItem.cpp | 3 +- .../src/RenderableMaterialEntityItem.cpp | 3 +- .../src/RenderableModelEntityItem.cpp | 16 -- .../src/RenderableModelEntityItem.h | 2 - .../src/RenderablePolyLineEntityItem.cpp | 3 +- .../src/RenderablePolyVoxEntityItem.cpp | 3 +- .../src/RenderableShapeEntityItem.cpp | 5 +- .../src/RenderableTextEntityItem.cpp | 38 +---- .../src/RenderableTextEntityItem.h | 2 - .../src/RenderableWebEntityItem.cpp | 3 +- libraries/entities/src/EntityItem.cpp | 36 ---- libraries/entities/src/EntityItem.h | 9 - .../entities/src/EntityItemProperties.cpp | 44 ----- libraries/entities/src/EntityItemProperties.h | 3 - libraries/entities/src/EntityPropertyFlags.h | 2 - .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 33 +--- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 6 +- libraries/gpu/src/gpu/Batch.cpp | 6 - libraries/gpu/src/gpu/Batch.h | 2 - libraries/gpu/src/gpu/Context.h | 2 +- libraries/gpu/src/gpu/FrameIOKeys.h | 1 - .../graphics/src/graphics/ShaderConstants.h | 2 - libraries/networking/src/udt/PacketHeaders.h | 1 - libraries/octree/src/OctreePacketData.h | 2 - .../src/CauterizedMeshPartPayload.cpp | 7 +- .../src/CauterizedMeshPartPayload.h | 2 +- .../src/DeferredLightingEffect.cpp | 1 - .../render-utils/src/DeferredLightingEffect.h | 4 +- .../render-utils/src/HighlightEffect.cpp | 7 +- .../render-utils/src/MeshPartPayload.cpp | 32 +--- libraries/render-utils/src/MeshPartPayload.h | 9 +- libraries/render-utils/src/Model.cpp | 46 +---- libraries/render-utils/src/Model.h | 9 - .../render-utils/src/RenderCommonTask.cpp | 159 +----------------- libraries/render-utils/src/RenderCommonTask.h | 17 +- .../render-utils/src/RenderDeferredTask.cpp | 33 ++-- .../render-utils/src/RenderDeferredTask.h | 2 +- .../render-utils/src/RenderForwardTask.cpp | 26 +-- .../render-utils/src/RenderForwardTask.h | 2 +- .../render-utils/src/RenderHUDLayerTask.cpp | 4 +- .../render-utils/src/RenderPipelines.cpp | 40 ----- .../render-utils/src/RenderShadowTask.cpp | 7 +- libraries/render-utils/src/RenderViewTask.cpp | 14 +- libraries/render-utils/src/RenderViewTask.h | 6 +- libraries/render-utils/src/TextRenderer3D.cpp | 11 +- libraries/render-utils/src/TextRenderer3D.h | 9 +- .../src/ToneMapAndResampleTask.cpp | 6 +- .../render-utils/src/ToneMapAndResampleTask.h | 7 +- libraries/render-utils/src/model.slf | 22 +-- .../render-utils/src/render-utils/model.slp | 2 +- .../src/render-utils/sdf_text3D.slp | 2 +- libraries/render-utils/src/sdf_text3D.slf | 11 -- libraries/render-utils/src/text/Font.cpp | 46 +++-- libraries/render-utils/src/text/Font.h | 28 +-- libraries/render/src/render/Args.h | 4 - libraries/render/src/render/CullTask.cpp | 85 +++++++++- libraries/render/src/render/CullTask.h | 23 +++ libraries/render/src/render/Item.cpp | 7 - libraries/render/src/render/Item.h | 23 +-- .../src/render/RenderFetchCullSortTask.cpp | 11 +- .../src/render/RenderFetchCullSortTask.h | 1 - libraries/render/src/render/ResampleTask.cpp | 3 +- libraries/render/src/render/ResampleTask.h | 4 +- libraries/shared/src/MirrorMode.cpp | 36 ---- libraries/shared/src/MirrorMode.h | 51 ------ libraries/shared/src/ViewFrustum.cpp | 51 ++---- libraries/shared/src/ViewFrustum.h | 5 +- .../create/assets/data/createAppTooltips.json | 12 +- .../html/js/entityProperties.js | 16 -- tools/gpu-frame-player/src/RenderThread.cpp | 2 +- 81 files changed, 263 insertions(+), 1047 deletions(-) delete mode 100644 libraries/shared/src/MirrorMode.cpp delete mode 100644 libraries/shared/src/MirrorMode.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 931c41703b..a9e4bedbbd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2479,7 +2479,6 @@ Application::Application( copyViewFrustum(viewFrustum); return viewFrustum.getPosition(); }); - MirrorModeHelpers::setComputeMirrorViewOperator(EntityRenderer::computeMirrorViewOperator); DependencyManager::get()->setKickConfirmationOperator([this] (const QUuid& nodeID, unsigned int banFlags) { userKickConfirmation(nodeID, banFlags); }); diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 130b8c77ea..704d7963e7 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -27,7 +27,7 @@ public: using Config = SecondaryCameraJobConfig; using JobModel = render::Job::ModelO; SecondaryCameraJob() { - _cachedArgsPointer = std::make_shared(); + _cachedArgsPointer = std::make_shared(_cachedArgs); _attachedEntityPropertyFlags += PROP_POSITION; _attachedEntityPropertyFlags += PROP_ROTATION; } @@ -203,6 +203,7 @@ public: } protected: + RenderArgs _cachedArgs; RenderArgsPointer _cachedArgsPointer; private: diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bb6fbcd899..827388aa1c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3530,9 +3530,8 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false; - bool isInMirror = renderArgs->_mirrorDepth > 0; bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); - return !defaultMode || isInMirror || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); + return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); } void MyAvatar::setRotationRecenterFilterLength(float length) { diff --git a/interface/src/scripting/RenderScriptingInterface.cpp b/interface/src/scripting/RenderScriptingInterface.cpp index 47f772b4bc..12814aa6b6 100644 --- a/interface/src/scripting/RenderScriptingInterface.cpp +++ b/interface/src/scripting/RenderScriptingInterface.cpp @@ -9,7 +9,6 @@ // #include "RenderScriptingInterface.h" -#include #include #include "LightingModel.h" @@ -80,35 +79,14 @@ void RenderScriptingInterface::setRenderMethod(RenderMethod renderMethod) { emit settingsChanged(); } } - -void recursivelyUpdateMirrorRenderMethods(const QString& parentTaskName, int renderMethod, int depth) { - if (depth == RenderMirrorTask::MAX_MIRROR_DEPTH) { - return; - } - - for (size_t mirrorIndex = 0; mirrorIndex < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; mirrorIndex++) { - std::string mirrorTaskString = parentTaskName.toStdString() + ".RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth) + ".DeferredForwardSwitch"; - auto mirrorConfig = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(QString::fromStdString(mirrorTaskString))); - if (mirrorConfig) { - mirrorConfig->setBranch((int)renderMethod); - recursivelyUpdateMirrorRenderMethods(QString::fromStdString(mirrorTaskString) + (renderMethod == 1 ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), - renderMethod, depth + 1); - } - } -} - void RenderScriptingInterface::forceRenderMethod(RenderMethod renderMethod) { _renderSettingLock.withWriteLock([&] { _renderMethod = (int)renderMethod; _renderMethodSetting.set((int)renderMethod); - QString configName = "RenderMainView.DeferredForwardSwitch"; - auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(configName)); + auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch")); if (config) { config->setBranch((int)renderMethod); - - recursivelyUpdateMirrorRenderMethods(configName + (renderMethod == RenderMethod::FORWARD ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), - (int)renderMethod, 0); } }); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 790b45843c..b2d6a6260b 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1120,7 +1120,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), forward }); + displayNameRenderer->draw(batch, text_x, -text_y, glm::vec2(-1.0f), nameUTF8.data(), textColor, true, forward); } } } diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 47f22dfaee..03a463c82a 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -357,7 +357,7 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - getGLBackend()->setCameraCorrection(mat4(), mat4(), true, true); + getGLBackend()->setCameraCorrection(mat4(), mat4(), true); for (auto& cursorValue : _cursorsData) { auto& cursorData = cursorValue.second; @@ -701,7 +701,7 @@ void OpenGLDisplayPlugin::present(const std::shared_ptr& if (_currentFrame) { auto correction = getViewCorrection(); - getGLBackend()->setCameraCorrection(correction, _prevRenderView, true); + getGLBackend()->setCameraCorrection(correction, _prevRenderView); _prevRenderView = correction * _currentFrame->view; { withPresentThreadLock([&] { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 09bbfb9284..212baa6634 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -12,7 +12,6 @@ #include "RenderableEntityItem.h" -#include #include #include "RenderableShapeEntityItem.h" @@ -193,10 +192,6 @@ ItemKey EntityRenderer::getKey() { builder.withSubMetaCulled(); } - if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { - builder.withMirror(); - } - if (!_visible) { builder.withInvisible(); } @@ -226,113 +221,12 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co return true; } -ItemID EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { - glm::vec3 inPropertiesPosition; - glm::quat inPropertiesRotation; - MirrorMode mirrorMode; - QUuid portalExitID; - withReadLock([&]{ - inPropertiesPosition = _entity->getWorldPosition(); - inPropertiesRotation = _entity->getWorldOrientation(); - mirrorMode = _mirrorMode; - portalExitID = _portalExitID; - }); - return computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); -} - -ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID) { - glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation); - glm::mat4 worldToIn = glm::inverse(inToWorld); - - glm::vec3 outPropertiesPosition = inPropertiesPosition; - glm::quat outPropertiesRotation = inPropertiesRotation; - glm::mat4 outToWorld = inToWorld; - bool foundPortalExit = false; - if (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) { - auto renderer = DependencyManager::get(); - if (renderer) { - if (auto renderable = renderer->renderableForEntityId(portalExitID)) { - renderable->withReadLock([&] { - outPropertiesPosition = renderable->_entity->getWorldPosition(); - outPropertiesRotation = renderable->_entity->getWorldOrientation(); - }); - - outToWorld = glm::translate(outPropertiesPosition) * glm::mat4_cast(outPropertiesRotation); - foundPortalExit = true; - } - } - } - - // get mirror camera position by reflecting main camera position's z coordinate in mirror space - glm::vec3 cameraPositionWorld = viewFrustum.getPosition(); - glm::vec3 cameraPositionIn = vec3(worldToIn * vec4(cameraPositionWorld, 1.0f)); - glm::vec3 mirrorCameraPositionIn = vec3(cameraPositionIn.x, cameraPositionIn.y, -cameraPositionIn.z); - if (foundPortalExit) { - // portals also flip over x - mirrorCameraPositionIn.x *= -1.0f; - } - glm::vec3 mirrorCameraPositionWorld = vec3(outToWorld * vec4(mirrorCameraPositionIn, 1.0f)); - - // get mirror camera rotation by reflecting main camera rotation in mirror space - // TODO: we are assuming here that UP is world y-axis - glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); - glm::quat mainCameraRotationMirror = worldToIn * glm::mat4_cast(mainCameraRotationWorld); - glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * - glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); - if (foundPortalExit) { - // portals also flip over x - mirrorCameraRotationMirror = glm::quat(mirrorCameraRotationMirror.w, mirrorCameraRotationMirror.x, -mirrorCameraRotationMirror.y, -mirrorCameraRotationMirror.z); - } - glm::quat mirrorCameraRotationWorld = outToWorld * glm::mat4_cast(mirrorCameraRotationMirror); - - viewFrustum.setPosition(mirrorCameraPositionWorld); - viewFrustum.setOrientation(mirrorCameraRotationWorld); - - // modify the near clip plane to be the XY plane of the mirror - // from: https://terathon.com/lengyel/Lengyel-Oblique.pdf - glm::mat4 view = viewFrustum.getView(); - glm::mat4 projection = viewFrustum.getProjection(); - - //Find the camera-space 4D reflection plane vector - glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(outPropertiesPosition, 1.0f); - glm::vec3 cameraSpaceNormal = glm::transpose(view) * (outPropertiesRotation * glm::vec4(0, 0, -1, 0)); - glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); - // Make sure we pick the direction facing away from us - if (clipPlane.w > 0.0f) { - clipPlane *= -1.0f; - } - - // Calculate the clip-space corner point opposite the clipping plane - // as (sign(clipPlane.x), sign(clipPlane.y), 1, 1) and - // transform it into camera space by multiplying it - // by the inverse of the projection matrix - glm::vec4 q; - q.x = (glm::sign(clipPlane.x) + projection[0][2]) / projection[0][0]; - q.y = (glm::sign(clipPlane.y) + projection[1][2]) / projection[1][1]; - q.z = -1.0f; - q.w = (1.0f + projection[2][2]) / projection[2][3]; - - // Calculate the scaled plane vector - glm::vec4 c = (2.0f / glm::dot(clipPlane, q)) * clipPlane; - - // Replace the third row of the projection matrix - projection[0][2] = c.x; - projection[1][2] = c.y; - projection[2][2] = c.z + 1.0f; - projection[3][2] = c.w; - - viewFrustum.setProjection(projection, true); - - return foundPortalExit ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID; -} - void EntityRenderer::render(RenderArgs* args) { if (!isValidRenderItem()) { return; } - if (_visible && (!_cauterized || args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || args->_mirrorDepth > 0)) { + if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { doRender(args); } } @@ -560,8 +454,6 @@ void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) _canCastShadow = entity->getCanCastShadow(); setCullWithParent(entity->getCullWithParent()); _cauterized = entity->getCauterized(); - setMirrorMode(entity->getMirrorMode()); - setPortalExitID(entity->getPortalExitID()); if (entity->needsZoneOcclusionUpdate()) { entity->resetNeedsZoneOcclusionUpdate(); _renderWithZones = entity->getRenderWithZones(); @@ -613,10 +505,6 @@ graphics::MaterialPointer EntityRenderer::getTopMaterial() { } EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) { - if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { - return Pipeline::MIRROR; - } - if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) { return Pipeline::PROCEDURAL; } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 99dbffbc72..3caeef0713 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -58,13 +58,12 @@ public: enum class Pipeline { SIMPLE, MATERIAL, - PROCEDURAL, - MIRROR + PROCEDURAL }; virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); virtual graphics::MaterialPointer getTopMaterial(); - Pipeline getPipelineType(const graphics::MultiMaterial& materials); + static Pipeline getPipelineType(const graphics::MultiMaterial& materials); virtual gpu::TexturePointer getTexture() { return nullptr; } virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); } @@ -75,9 +74,6 @@ public: virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override; virtual Item::Bound getBound(RenderArgs* args) override; bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override; - ItemID computeMirrorView(ViewFrustum& viewFrustum) const override; - static ItemID computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID); protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } @@ -120,8 +116,6 @@ protected: virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; } virtual void setCullWithParent(bool value) { _cullWithParent = value; } - virtual void setMirrorMode(MirrorMode value) { _mirrorMode = value; } - virtual void setPortalExitID(const QUuid& value) { _portalExitID = value; } template std::shared_ptr asTypedEntity() { return std::static_pointer_cast(_entity); } @@ -157,8 +151,6 @@ protected: BillboardMode _billboardMode { BillboardMode::NONE }; bool _cauterized { false }; bool _moving { false }; - MirrorMode _mirrorMode { MirrorMode::NONE }; - QUuid _portalExitID; Transform _renderTransform; MaterialMap _materials; diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp index 10ae144334..42df1e2888 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp @@ -263,9 +263,8 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index 3f40218d46..e374fe29c0 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -103,9 +103,8 @@ void GridEntityRenderer::doRender(RenderArgs* args) { } else { transform.setTranslation(renderTransform.getTranslation()); } - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch->setModelTransform(transform); auto minCorner = glm::vec2(-0.5f, -0.5f); diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 66a5d0d609..9592a3e57f 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -147,9 +147,8 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { gpu::Batch* batch = args->_batch; - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float imageWidth = _texture->getWidth(); float imageHeight = _texture->getHeight(); @@ -199,10 +198,8 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent)); } else if (pipelineType == Pipeline::SIMPLE) { batch->setResourceTexture(0, _texture->getGPUTexture()); - } else if (pipelineType == Pipeline::MATERIAL) { - if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; - } + } else if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; } DependencyManager::get()->renderQuad( diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 1117c97c75..a36cdde212 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -47,9 +47,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) { const auto& modelTransform = getModelTransform(); Transform transform = Transform(); transform.setTranslation(modelTransform.getTranslation()); - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch, false, false, false, false, true, diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index fe44c41094..b8f829f4ba 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -303,9 +303,8 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { proceduralRender = true; } - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (!proceduralRender) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 6b83d87732..8ed3f84609 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1274,8 +1274,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint _model->setBillboardMode(_billboardMode, scene); _model->setCullWithParent(_cullWithParent, scene); _model->setRenderWithZones(_renderWithZones, scene); - _model->setMirrorMode(_mirrorMode, scene); - _model->setPortalExitID(_portalExitID, scene); }); if (didVisualGeometryRequestSucceed) { emit DependencyManager::get()-> @@ -1355,8 +1353,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint model->setBillboardMode(_billboardMode, scene); model->setCullWithParent(_cullWithParent, scene); model->setRenderWithZones(_renderWithZones, scene); - model->setMirrorMode(_mirrorMode, scene); - model->setPortalExitID(_portalExitID, scene); }); if (entity->blendshapesChanged()) { @@ -1470,18 +1466,6 @@ void ModelEntityRenderer::setCullWithParent(bool value) { setKey(_didLastVisualGeometryRequestSucceed, _model); } -void ModelEntityRenderer::setMirrorMode(MirrorMode value) { - Parent::setMirrorMode(value); - // called within a lock so no need to lock for _model - setKey(_didLastVisualGeometryRequestSucceed, _model); -} - -void ModelEntityRenderer::setPortalExitID(const QUuid& value) { - Parent::setPortalExitID(value); - // called within a lock so no need to lock for _model - setKey(_didLastVisualGeometryRequestSucceed, _model); -} - // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 425d082f01..f394d389f5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -170,8 +170,6 @@ protected: void setIsVisibleInSecondaryCamera(bool value) override; void setRenderLayer(RenderLayer value) override; void setCullWithParent(bool value) override; - void setMirrorMode(MirrorMode value) override; - void setPortalExitID(const QUuid& value) override; private: void animate(const TypedEntityPointer& entity, const ModelPointer& model); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 81f4c5fcb4..aca501985a 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -325,9 +325,8 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { buildPipelines(); } - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 26091a1ed4..8331e016fd 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1860,9 +1860,8 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); gpu::Batch& batch = *args->_batch; - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 82350f54bf..a6fee03311 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -118,9 +118,8 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron)); batch.setModelTransform(transform); @@ -158,7 +157,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } } } else { - if (pipelineType == Pipeline::MATERIAL && RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { + if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index a15e2839a4..2858e12afd 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -164,9 +164,8 @@ void TextEntityRenderer::doRender(RenderArgs* args) { transform = _renderTransform; }); - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); @@ -181,7 +180,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { } auto geometryCache = DependencyManager::get(); - if (pipelineType == Pipeline::SIMPLE || pipelineType == Pipeline::MIRROR) { + if (pipelineType == Pipeline::SIMPLE) { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), backgroundColor, _geometryID); } else { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), glm::vec2(0.0f), glm::vec2(1.0f), backgroundColor, _geometryID); @@ -261,10 +260,6 @@ ItemKey entities::TextPayload::getKey() const { builder.withInvisible(); } - if (textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull())) { - builder.withMirror(); - } - return builder; } } @@ -316,17 +311,6 @@ bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set(); - if (entityTreeRenderer) { - auto renderable = entityTreeRenderer->renderableForEntityId(_entityID); - if (renderable) { - return renderable->computeMirrorView(viewFrustum); - } - } - return Item::INVALID_ITEM_ID; -} - void entities::TextPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("TextPayload::render"); Q_ASSERT(args->_batch); @@ -351,15 +335,12 @@ void entities::TextPayload::render(RenderArgs* args) { glm::vec3 dimensions; glm::vec4 textColor; - bool mirror; textRenderable->withReadLock([&] { transform = textRenderable->_renderTransform; dimensions = textRenderable->_dimensions; float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f; textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha); - - mirror = textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull()); }); bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD; @@ -371,9 +352,8 @@ void entities::TextPayload::render(RenderArgs* args) { return; } - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float scale = textRenderable->_lineHeight / textRenderer->getFontSize(); transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z)); @@ -381,8 +361,9 @@ void entities::TextPayload::render(RenderArgs* args) { batch.setModelTransform(transform); glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin)); - textRenderer->draw(batch, textRenderable->_font, { textRenderable->_text, textColor, effectColor, { textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale }, - bounds / scale, scale, textRenderable->_effectThickness, textRenderable->_effect, textRenderable->_alignment, textRenderable->_unlit, forward, mirror }); + textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale, + textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect, + textRenderable->_alignment, textRenderable->_unlit, forward); } namespace render { @@ -418,11 +399,4 @@ template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Poi return false; } -template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) { - if (payload) { - return payload->computeMirrorView(viewFrustum); - } - return Item::INVALID_ITEM_ID; -} - } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index f48bb8085f..8a18554dea 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -101,7 +101,6 @@ public: ShapeKey getShapeKey() const; void render(RenderArgs* args); bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; - ItemID computeMirrorView(ViewFrustum& viewFrustum) const; protected: QUuid _entityID; @@ -118,7 +117,6 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload); template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set& containingZones); - template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum); } #endif // hifi_RenderableTextEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 77f6fe99f6..c98bfe7f63 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -320,9 +320,8 @@ void WebEntityRenderer::doRender(RenderArgs* args) { batch.setResourceTexture(0, _texture); - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); // Turn off jitter for these entities diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 34217d5bdf..b63f0d91ab 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -105,8 +105,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_RENDER_WITH_ZONES; requestedProperties += PROP_BILLBOARD_MODE; requestedProperties += _grabProperties.getEntityProperties(params); - requestedProperties += PROP_MIRROR_MODE; - requestedProperties += PROP_PORTAL_EXIT_ID; // Physics requestedProperties += PROP_DENSITY; @@ -307,8 +305,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); }); - APPEND_ENTITY_PROPERTY(PROP_MIRROR_MODE, (uint32_t)getMirrorMode()); - APPEND_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, getPortalExitID()); // Physics APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); @@ -885,8 +881,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += bytesFromGrab; dataAt += bytesFromGrab; }); - READ_ENTITY_PROPERTY(PROP_MIRROR_MODE, MirrorMode, setMirrorMode); - READ_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, QUuid, setPortalExitID); READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); { @@ -1367,8 +1361,6 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire withReadLock([&] { _grabProperties.getProperties(properties); }); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(mirrorMode, getMirrorMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(portalExitID, getPortalExitID); // Physics COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); @@ -1507,8 +1499,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { bool grabPropertiesChanged = _grabProperties.setProperties(properties); somethingChanged |= grabPropertiesChanged; }); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(mirrorMode, setMirrorMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(portalExitID, setPortalExitID); // Physics SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, setDensity); @@ -3563,29 +3553,3 @@ void EntityItem::setBillboardMode(BillboardMode value) { _billboardMode = value; }); } - -MirrorMode EntityItem::getMirrorMode() const { - return resultWithReadLock([&] { - return _mirrorMode; - }); -} - -void EntityItem::setMirrorMode(MirrorMode value) { - withWriteLock([&] { - _needsRenderUpdate |= _mirrorMode != value; - _mirrorMode = value; - }); -} - -QUuid EntityItem::getPortalExitID() const { - return resultWithReadLock([&] { - return _portalExitID; - }); -} - -void EntityItem::setPortalExitID(const QUuid& value) { - withWriteLock([&] { - _needsRenderUpdate |= _portalExitID != value; - _portalExitID = value; - }); -} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 32f6dccf37..ec84b0ccb2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -559,12 +559,6 @@ public: BillboardMode getBillboardMode() const; virtual bool getRotateForPicking() const { return false; } - MirrorMode getMirrorMode() const; - void setMirrorMode(MirrorMode value); - - QUuid getPortalExitID() const; - void setPortalExitID(const QUuid& value); - signals: void spaceUpdate(std::pair data); @@ -746,9 +740,6 @@ protected: bool _cullWithParent { false }; - MirrorMode _mirrorMode { MirrorMode::NONE }; - QUuid _portalExitID; - mutable bool _needsRenderUpdate { false }; }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4d21e040f5..f543169401 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -424,23 +424,6 @@ void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHost } } -inline void addMirrorMode(QHash& lookup, MirrorMode mirrorMode) { lookup[MirrorModeHelpers::getNameForMirrorMode(mirrorMode)] = mirrorMode; } -const QHash stringToMirrorModeLookup = [] { - QHash toReturn; - addMirrorMode(toReturn, MirrorMode::NONE); - addMirrorMode(toReturn, MirrorMode::MIRROR); - addMirrorMode(toReturn, MirrorMode::PORTAL); - return toReturn; -}(); -QString EntityItemProperties::getMirrorModeAsString() const { return MirrorModeHelpers::getNameForMirrorMode(_mirrorMode); } -void EntityItemProperties::setMirrorModeFromString(const QString& mirrorMode) { - auto mirrorModeItr = stringToMirrorModeLookup.find(mirrorMode.toLower()); - if (mirrorModeItr != stringToMirrorModeLookup.end()) { - _mirrorMode = mirrorModeItr.value(); - _mirrorModeChanged = true; - } -} - EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -472,8 +455,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones); CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode); changedProperties += _grab.getChangedProperties(); - CHECK_PROPERTY_CHANGE(PROP_MIRROR_MODE, mirrorMode); - CHECK_PROPERTY_CHANGE(PROP_PORTAL_EXIT_ID, portalExitID); // Physics CHECK_PROPERTY_CHANGE(PROP_DENSITY, density); @@ -844,11 +825,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * * @property {Entities.Grab} grab - The entity's grab-related properties. * - * @property {MirrorMode} mirrorMode="none" - If this entity should render as a mirror (reflecting the view of the camera), - * a portal (reflecting the view through its portalExitID), or normally. - * @property {Uuid} portalExitID=Uuid.NULL - The ID of the entity that should act as the portal exit if the mirrorMode - * is set to portal. - * * @comment The different entity types have additional properties as follows: * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} * @see {@link Entities.EntityProperties-Gizmo|EntityProperties-Gizmo} @@ -1640,8 +1616,6 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MIRROR_MODE, mirrorMode, getMirrorModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PORTAL_EXIT_ID, portalExitID); // Physics COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density); @@ -2058,8 +2032,6 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode); _grab.copyFromScriptValue(object, namesSet, _defaultSettings); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(mirrorMode, MirrorMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(portalExitID, QUuid, setPortalExitID); // Physics COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity); @@ -2346,8 +2318,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(renderWithZones); COPY_PROPERTY_IF_CHANGED(billboardMode); _grab.merge(other._grab); - COPY_PROPERTY_IF_CHANGED(mirrorMode); - COPY_PROPERTY_IF_CHANGED(portalExitID); // Physics COPY_PROPERTY_IF_CHANGED(density); @@ -2657,8 +2627,6 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, EquippableIndicatorOffset, equippableIndicatorOffset); } - ADD_PROPERTY_TO_MAP(PROP_MIRROR_MODE, MirrorMode, mirrorMode, MirrorMode); - ADD_PROPERTY_TO_MAP(PROP_PORTAL_EXIT_ID, PortalExitID, portalExitID, QUuid); // Physics ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_DENSITY, Density, density, float, @@ -3122,8 +3090,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticGrab.setProperties(properties); _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_MIRROR_MODE, (uint32_t)properties.getMirrorMode()); - APPEND_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, properties.getPortalExitID()); // Physics APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity()); @@ -3602,8 +3568,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MIRROR_MODE, MirrorMode, setMirrorMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PORTAL_EXIT_ID, QUuid, setPortalExitID); // Physics READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity); @@ -3996,8 +3960,6 @@ void EntityItemProperties::markAllChanged() { _renderWithZonesChanged = true; _billboardModeChanged = true; _grab.markAllChanged(); - _mirrorModeChanged = true; - _portalExitIDChanged = true; // Physics _densityChanged = true; @@ -4397,12 +4359,6 @@ QList EntityItemProperties::listChangedProperties() { out += "billboardMode"; } getGrab().listChangedProperties(out); - if (mirrorModeChanged()) { - out += "mirrorMode"; - } - if (portalExitIDChanged()) { - out += "portalExitID"; - } // Physics if (densityChanged()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3e07a75616..283d14c4cc 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -70,7 +70,6 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" -#include "MirrorMode.h" class ScriptEngine; @@ -205,8 +204,6 @@ public: DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector, QVector()); DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE); DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); - DEFINE_PROPERTY_REF_ENUM(PROP_MIRROR_MODE, MirrorMode, mirrorMode, MirrorMode, MirrorMode::NONE); - DEFINE_PROPERTY_REF(PROP_PORTAL_EXIT_ID, PortalExitID, portalExitID, QUuid, UNKNOWN_ENTITY_ID); // Physics DEFINE_PROPERTY(PROP_DENSITY, Density, density, float, ENTITY_ITEM_DEFAULT_DENSITY); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index c0cbb3f9a1..e0b5a04094 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -60,8 +60,6 @@ enum EntityPropertyList { PROP_GRAB_EQUIPPABLE_INDICATOR_URL, PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, - PROP_MIRROR_MODE, - PROP_PORTAL_EXIT_ID, // Physics PROP_DENSITY, diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index c0116274ee..af39458f17 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -81,7 +81,6 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_disableContextViewCorrection), (&::gpu::gl::GLBackend::do_restoreContextViewCorrection), - (&::gpu::gl::GLBackend::do_setContextMirrorViewCorrection), (&::gpu::gl::GLBackend::do_disableContextStereo), (&::gpu::gl::GLBackend::do_restoreContextStereo), @@ -349,7 +348,6 @@ void GLBackend::renderPassTransfer(const Batch& batch) { case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: case Batch::COMMAND_setProjectionJitter: - case Batch::COMMAND_setContextMirrorViewCorrection: { CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); @@ -415,7 +413,6 @@ void GLBackend::renderPassDraw(const Batch& batch) { case Batch::COMMAND_setProjectionJitter: case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setDepthRangeTransform: - case Batch::COMMAND_setContextMirrorViewCorrection: { PROFILE_RANGE(render_gpu_gl_detail, "transform"); CommandCall call = _commandCalls[(*command)]; @@ -622,16 +619,6 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param _transform._viewCorrectionEnabled = true; } -void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { - bool prevMirrorViewCorrection = _transform._mirrorViewCorrection; - _transform._mirrorViewCorrection = batch._params[paramOffset]._uint != 0; - - if (_transform._correction.correction != glm::mat4()) { - setCameraCorrection(_transform._mirrorViewCorrection ? _transform._flippedCorrection : _transform._unflippedCorrection, _transform._correction.prevView, false); - _transform._invalidView = true; - } -} - void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { } @@ -1010,29 +997,15 @@ void GLBackend::recycle() const { _textureManagement._transferEngine->manageMemory(); } -void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset) { +void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) { auto invCorrection = glm::inverse(correction); auto invPrevView = glm::inverse(prevRenderView); _transform._correction.prevView = (reset ? Mat4() : prevRenderView); _transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView); _transform._correction.correction = correction; _transform._correction.correctionInverse = invCorrection; - - if (!_inRenderTransferPass) { - _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); - _pipeline._cameraCorrectionBuffer._buffer->flush(); - } - - if (primary) { - _transform._unflippedCorrection = _transform._correction.correction; - quat flippedRotation = glm::quat_cast(_transform._unflippedCorrection); - flippedRotation.y *= -1.0f; - flippedRotation.z *= -1.0f; - vec3 flippedTranslation = _transform._unflippedCorrection[3]; - flippedTranslation.x *= -1.0f; - _transform._flippedCorrection = glm::translate(glm::mat4_cast(flippedRotation), flippedTranslation); - _transform._mirrorViewCorrection = false; - } + _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); + _pipeline._cameraCorrectionBuffer._buffer->flush(); } void GLBackend::syncProgram(const gpu::ShaderPointer& program) { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 5545858877..2947649ce7 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -121,7 +121,7 @@ public: // Shutdown rendering and persist any required resources void shutdown() override; - void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) override; + void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) override; void render(const Batch& batch) final override; // This call synchronize the Full Backend cache with the current GLState @@ -211,7 +211,6 @@ public: virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final; - virtual void do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final; @@ -434,9 +433,6 @@ protected: Transform _view; CameraCorrection _correction; bool _viewCorrectionEnabled{ true }; - mat4 _unflippedCorrection; - mat4 _flippedCorrection; - bool _mirrorViewCorrection{ false }; Mat4 _projection; Vec4i _viewport{ 0, 0, 1, 1 }; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index a41f586d74..e6217cc600 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -464,12 +464,6 @@ void Batch::restoreContextViewCorrection() { ADD_COMMAND(restoreContextViewCorrection); } -void Batch::setContextMirrorViewCorrection(bool shouldMirror) { - ADD_COMMAND(setContextMirrorViewCorrection); - uint mirrorFlag = shouldMirror ? 1 : 0; - _params.emplace_back(mirrorFlag); -} - void Batch::disableContextStereo() { ADD_COMMAND(disableContextStereo); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index f89dd3ea90..0a438ea148 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -239,7 +239,6 @@ public: void disableContextViewCorrection(); void restoreContextViewCorrection(); - void setContextMirrorViewCorrection(bool shouldMirror); void disableContextStereo(); void restoreContextStereo(); @@ -341,7 +340,6 @@ public: COMMAND_disableContextViewCorrection, COMMAND_restoreContextViewCorrection, - COMMAND_setContextMirrorViewCorrection, COMMAND_disableContextStereo, COMMAND_restoreContextStereo, diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index ebc81f14e9..1946f447f8 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -66,7 +66,7 @@ public: virtual void syncProgram(const gpu::ShaderPointer& program) = 0; virtual void recycle() const = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) {} + virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) {} virtual bool supportedTextureFormat(const gpu::Element& format) = 0; diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index 2d88158afb..1a98d0decd 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -181,7 +181,6 @@ constexpr const char* COMMAND_NAMES[] = { "disableContextViewCorrection", "restoreContextViewCorrection", - "setContextMirrorViewCorrection", "disableContextStereo", "restoreContextStereo", diff --git a/libraries/graphics/src/graphics/ShaderConstants.h b/libraries/graphics/src/graphics/ShaderConstants.h index 8fd0df31f0..3a614d26cd 100644 --- a/libraries/graphics/src/graphics/ShaderConstants.h +++ b/libraries/graphics/src/graphics/ShaderConstants.h @@ -27,7 +27,6 @@ #define GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS 4 #define GRAPHICS_TEXTURE_MATERIAL_OCCLUSION 5 #define GRAPHICS_TEXTURE_MATERIAL_SCATTERING 6 -#define GRAPHICS_TEXTURE_MATERIAL_MIRROR 1 // Mirrors use albedo textures, but nothing else // Make sure these match the ones in render-utils/ShaderConstants.h #define GRAPHICS_TEXTURE_SKYBOX 11 @@ -60,7 +59,6 @@ enum Texture { MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS, MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION, MaterialScattering = GRAPHICS_TEXTURE_MATERIAL_SCATTERING, - MaterialMirror = GRAPHICS_TEXTURE_MATERIAL_MIRROR, Skybox = GRAPHICS_TEXTURE_SKYBOX }; } // namespace texture diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 51739e0f77..3badfdf418 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -290,7 +290,6 @@ enum class EntityVersion : PacketVersion { UserAgent, AllBillboardMode, TextAlignment, - Mirror, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 30b826aaec..583f090942 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -42,7 +42,6 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" -#include "MirrorMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -281,7 +280,6 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, GizmoType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } 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, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 78652bfb09..dc1ffb7b67 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -71,15 +71,14 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { - bool useCauterizedMesh = _enableCauterization && (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && - mirrorDepth == 0; +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { + bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer); } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, transform, renderMode, mirrorDepth); + ModelMeshPartPayload::bindTransform(batch, transform, renderMode); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index cef7b6d9b5..430f41fc08 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ public: void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning); - void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const override; + void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 3eb5924d19..8d7fc345ac 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -286,7 +286,6 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); - outputs.edit2() = _deferredFramebuffer->getDeferredFramebuffer(); gpu::doInBatch("PrepareDeferred::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 058e0a4cbf..4779376410 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -78,8 +78,8 @@ class PrepareDeferred { public: // Inputs: primaryFramebuffer and lightingModel using Inputs = render::VaryingSet2 ; - // Output: DeferredFramebuffer, LightingFramebuffer, the framebuffer to be used for mirrors (same as DeferredFramebuffer) - using Outputs = render::VaryingSet3; + // Output: DeferredFramebuffer, LightingFramebuffer + using Outputs = render::VaryingSet2; using JobModel = render::Job::ModelIO; diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index b4aced626d..5a8b09b018 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -506,9 +506,8 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren const auto jitter = inputs.getN(4); // Prepare the ShapePipeline - static ShapePlumberPointer shapePlumber = std::make_shared(); - static std::once_flag once; - std::call_once(once, [] { + auto shapePlumber = std::make_shared(); + { auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); @@ -516,7 +515,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - }); + } auto sharedParameters = std::make_shared(); const auto highlightSelectionNames = task.addJob("SelectionToHighlight", sharedParameters); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 9adeb39e7c..8ba5be54e6 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -12,7 +12,6 @@ #include "MeshPartPayload.h" #include -#include #include #include #include @@ -189,7 +188,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { if (_clusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); } @@ -221,10 +220,6 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withSubMetaCulled(); } - if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { - builder.withMirror(); - } - _itemKey = builder.build(); } @@ -304,9 +299,8 @@ Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const { auto worldBound = _adjustedLocalBound; auto parentTransform = _parentTransform; if (args) { - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); } worldBound.transform(parentTransform); return worldBound; @@ -319,19 +313,18 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!args || (_cauterized && args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && args->_mirrorDepth == 0)) { + if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) { return; } gpu::Batch& batch = *(args->_batch); Transform transform = _parentTransform; - bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform modelTransform = transform.worldTransform(_localTransform); - bindTransform(batch, modelTransform, args->_renderMode, args->_mirrorDepth); + bindTransform(batch, modelTransform, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); @@ -353,7 +346,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned())); batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); - } else if (!_itemKey.isMirror()) { + } else { // apply material properties if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; @@ -384,12 +377,6 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set& blendshapeBuffers, const QVector& blendedMeshSizes) { if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); @@ -439,11 +426,4 @@ template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin } return false; } - -template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum) { - if (payload) { - return payload->computeMirrorView(viewFrustum); - } - return Item::INVALID_ITEM_ID; -} } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 7e331a9497..1a3a898582 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -37,7 +37,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch); - virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const; + virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const; void drawCall(gpu::Batch& batch) const; void updateKey(const render::ItemKey& key); @@ -58,10 +58,7 @@ public: void setCullWithParent(bool value) { _cullWithParent = value; } void setRenderWithZones(const QVector& renderWithZones) { _renderWithZones = renderWithZones; } void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; } - void setMirrorMode(MirrorMode mirrorMode) { _mirrorMode = mirrorMode; } - void setPortalExitID(const QUuid& portalExitID) { _portalExitID = portalExitID; } bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; - render::ItemID computeMirrorView(ViewFrustum& viewFrustum) const; void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } @@ -96,8 +93,6 @@ private: bool _cullWithParent { false }; QVector _renderWithZones; BillboardMode _billboardMode { BillboardMode::NONE }; - MirrorMode _mirrorMode { MirrorMode::NONE }; - QUuid _portalExitID; uint64_t _created; Transform _localTransform; @@ -112,8 +107,6 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set& containingZones); - template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum); - } #endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7d622ab489..eabcabc7e5 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -232,8 +232,6 @@ void Model::updateRenderItems() { auto renderWithZones = self->getRenderWithZones(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool cauterized = self->isCauterized(); - auto mirrorMode = self->getMirrorMode(); - const QUuid& portalExitID = self->getPortalExitID(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -248,7 +246,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags, - cauterized, renderWithZones, mirrorMode, portalExitID](ModelMeshPartPayload& data) { + cauterized, renderWithZones](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); @@ -262,8 +260,6 @@ void Model::updateRenderItems() { data.setCauterized(cauterized); data.setRenderWithZones(renderWithZones); data.setBillboardMode(billboardMode); - data.setMirrorMode(mirrorMode); - data.setPortalExitID(portalExitID); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); @@ -1069,46 +1065,6 @@ void Model::setRenderWithZones(const QVector& renderWithZones, const rend } } -void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene) { - if (_mirrorMode != mirrorMode) { - _mirrorMode = mirrorMode; - if (!scene) { - _needsFixupInScene = true; - return; - } - - render::Transaction transaction; - auto renderItemsKey = _renderItemKeyGlobalFlags; - for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) { - data.setMirrorMode(mirrorMode); - data.updateKey(renderItemsKey); - }); - } - scene->enqueueTransaction(transaction); - } -} - -void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene) { - if (_portalExitID != portalExitID) { - _portalExitID = portalExitID; - if (!scene) { - _needsFixupInScene = true; - return; - } - - render::Transaction transaction; - auto renderItemsKey = _renderItemKeyGlobalFlags; - for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) { - data.setPortalExitID(portalExitID); - data.updateKey(renderItemsKey); - }); - } - scene->enqueueTransaction(transaction); - } -} - const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { return _renderItemKeyGlobalFlags; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 63a96f7253..17b7df9b23 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -41,7 +41,6 @@ #include "Rig.h" #include "PrimitiveMode.h" #include "BillboardMode.h" -#include "MirrorMode.h" // Use dual quaternion skinning! // Must match define in Skinning.slh @@ -132,12 +131,6 @@ public: void setRenderWithZones(const QVector& renderWithZones, const render::ScenePointer& scene = nullptr); const QVector& getRenderWithZones() const { return _renderWithZones; } - void setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene = nullptr); - MirrorMode getMirrorMode() const { return _mirrorMode; } - - void setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene = nullptr); - const QUuid& getPortalExitID() const { return _portalExitID; } - // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; @@ -510,8 +503,6 @@ protected: bool _cauterized { false }; bool _cullWithParent { false }; QVector _renderWithZones; - MirrorMode _mirrorMode { MirrorMode::NONE }; - QUuid _portalExitID; bool shouldInvalidatePayloadShapeKey(int meshIndex); diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index a509ede437..7cf7f1129f 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -13,10 +13,7 @@ #include "render-utils/ShaderConstants.h" #include "DeferredLightingEffect.h" -#include "FadeEffect.h" #include "RenderUtilsLogging.h" -#include "RenderViewTask.h" -#include "StencilMaskPass.h" namespace ru { using render_utils::slot::texture::Texture; @@ -28,11 +25,9 @@ namespace gr { using graphics::slot::buffer::Buffer; } -using RenderArgsPointer = std::shared_ptr; using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); -extern void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void BeginGPURangeTimer::run(const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) { timer = _gpuTimer; @@ -50,14 +45,10 @@ void EndGPURangeTimer::run(const render::RenderContextPointer& renderContext, co config->setGPUBatchRunTime(timer->getGPUAverage(), timer->getBatchAverage()); } -render::ShapePlumberPointer DrawLayered3D::_shapePlumber = std::make_shared(); - DrawLayered3D::DrawLayered3D(bool opaque) : + _shapePlumber(std::make_shared()), _opaquePass(opaque) { - static std::once_flag once; - std::call_once(once, [] { - initForwardPipelines(*_shapePlumber); - }); + initForwardPipelines(*_shapePlumber); } void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& inputs) { @@ -271,149 +262,3 @@ void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, } } -class SetupMirrorTask { -public: - using Input = RenderMirrorTask::Inputs; - using Outputs = render::VaryingSet4; - using JobModel = render::Job::ModelIO; - - SetupMirrorTask(size_t mirrorIndex, size_t depth) : _mirrorIndex(mirrorIndex), _depth(depth) {} - - void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) { - auto args = renderContext->args; - auto items = inputs.get0(); - - if (items.empty() || _mirrorIndex > items.size() - 1) { - renderContext->taskFlow.abortTask(); - return; - } - - auto inputFramebuffer = inputs.get1(); - if (!_mirrorFramebuffer || _mirrorFramebuffer->getWidth() != inputFramebuffer->getWidth() || _mirrorFramebuffer->getHeight() != inputFramebuffer->getHeight()) { - _mirrorFramebuffer.reset(gpu::Framebuffer::create("mirror" + _mirrorIndex, gpu::Element::COLOR_SRGBA_32, inputFramebuffer->getWidth(), inputFramebuffer->getHeight())); - } - - render::ItemBound mirror = items[_mirrorIndex]; - - _cachedArgsPointer->_renderMode = args->_renderMode; - _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; - _cachedArgsPointer->_ignoreItem = args->_ignoreItem; - _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; - _cachedArgsPointer->_numMirrorFlips = args->_numMirrorFlips; - - ViewFrustum srcViewFrustum = args->getViewFrustum(); - ItemID portalExitID = args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); - - args->_blitFramebuffer = _mirrorFramebuffer; - args->_ignoreItem = portalExitID != Item::INVALID_ITEM_ID ? portalExitID : mirror.id; - args->_mirrorDepth = _depth; - args->_numMirrorFlips += portalExitID != Item::INVALID_ITEM_ID ? 0 : 1; - - gpu::doInBatch("SetupMirrorTask::run", args->_context, [&](gpu::Batch& batch) { - bool shouldMirror = args->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); - batch.setContextMirrorViewCorrection(shouldMirror); - }); - - // Without calculating the bound planes, the mirror will use the same culling frustum as the main camera, - // which is not what we want here. - srcViewFrustum.calculate(); - args->pushViewFrustum(srcViewFrustum); - - outputs.edit0() = mirror; - outputs.edit1() = inputFramebuffer; - outputs.edit2() = _cachedArgsPointer; - outputs.edit3() = inputs.get2(); - } - -protected: - gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; - RenderArgsPointer _cachedArgsPointer { std::make_shared() }; - size_t _mirrorIndex; - size_t _depth; - -}; - -class DrawMirrorTask { -public: - using Inputs = SetupMirrorTask::Outputs; - using JobModel = render::Job::ModelI; - - DrawMirrorTask() { - static std::once_flag once; - std::call_once(once, [this] { - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - PrepareStencil::testMaskDrawShape(*state); - - auto fadeEffect = DependencyManager::get(); - initMirrorPipelines(*_forwardPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), true); - initMirrorPipelines(*_deferredPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), false); - }); - } - - void run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { - auto args = renderContext->args; - auto mirror = inputs.get0(); - auto framebuffer = inputs.get1(); - auto cachedArgs = inputs.get2(); - auto jitter = inputs.get3(); - - if (cachedArgs) { - args->_renderMode = cachedArgs->_renderMode; - } - args->popViewFrustum(); - - gpu::doInBatch("DrawMirrorTask::run", args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - if (cachedArgs) { - bool shouldMirror = cachedArgs->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); - batch.setContextMirrorViewCorrection(shouldMirror); - } - - batch.setFramebuffer(framebuffer); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setProjectionJitter(jitter.x, jitter.y); - batch.setViewTransform(viewMat); - - batch.setResourceTexture(gr::Texture::MaterialMirror, args->_blitFramebuffer->getRenderBuffer(0)); - - renderShapes(renderContext, args->_renderMethod == render::Args::RenderMethod::FORWARD ? _forwardPipelines : _deferredPipelines, { mirror }); - - args->_batch = nullptr; - }); - - if (cachedArgs) { - // Restore the blit framebuffer after we've sampled from it - args->_blitFramebuffer = cachedArgs->_blitFramebuffer; - args->_ignoreItem = cachedArgs->_ignoreItem; - args->_mirrorDepth = cachedArgs->_mirrorDepth; - args->_numMirrorFlips = cachedArgs->_numMirrorFlips; - } - } - -private: - static ShapePlumberPointer _forwardPipelines; - static ShapePlumberPointer _deferredPipelines; -}; - -ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared(); -ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared(); - - void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { - size_t nextDepth = depth + 1; - const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex, nextDepth); - - task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, nextDepth); - - task.addJob("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); - } diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index cada3cb6ea..15d6ff9895 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -10,8 +10,6 @@ #define hifi_RenderCommonTask_h #include -#include - #include "LightStage.h" #include "HazeStage.h" #include "LightingModel.h" @@ -73,7 +71,7 @@ public: void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: - static render::ShapePlumberPointer _shapePlumber; + render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config bool _opaquePass { true }; }; @@ -154,17 +152,4 @@ protected: render::Args::RenderMethod _method; }; -class RenderMirrorTask { -public: - using Inputs = render::VaryingSet3; - using JobModel = render::Task::ModelI; - - RenderMirrorTask() {} - - void build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth); - - static const size_t MAX_MIRROR_DEPTH { 3 }; - static const size_t MAX_MIRRORS_PER_LEVEL { 3 }; -}; - #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index fd10452dfa..c506f22bc7 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -100,14 +100,11 @@ void RenderDeferredTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { - static auto fadeEffect = DependencyManager::get(); +void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { + auto fadeEffect = DependencyManager::get(); // Prepare the ShapePipelines - static ShapePlumberPointer shapePlumber = std::make_shared(); - static std::once_flag once; - std::call_once(once, [] { - initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - }); + ShapePlumberPointer shapePlumber = std::make_shared(); + initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); const auto& inputs = input.get(); @@ -119,7 +116,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Extract opaques / transparents / lights / metas / layered / background const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; - const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -143,6 +139,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Shadow Stage Frame const auto shadowFrame = shadowTaskOutputs[1]; + fadeEffect->build(task, opaques); const auto jitter = task.addJob("JitterCam"); @@ -157,7 +154,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); - const auto mirrorTargetFramebuffer = prepareDeferredOutputs.getN(2); // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", scaledPrimaryFramebuffer); @@ -166,13 +162,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); - if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { - const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, mirrorTargetFramebuffer, jitter).asVarying(); - for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { - task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); - } - } - // Opaque all rendered // Linear Depth Pass @@ -245,7 +234,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); + const auto toneMappedBuffer = task.addJob("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 @@ -409,12 +398,8 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatusJob - static gpu::TexturePointer statusIconMap; - static std::once_flag once; - std::call_once(once, [] { - auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; - statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); - }); + auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; + auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); const auto drawStatusInputs = DrawStatus::Input(opaques, jitter).asVarying(); task.addJob("DrawStatus", drawStatusInputs, DrawStatus(statusIconMap)); } @@ -422,6 +407,8 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input const auto debugZoneInputs = DebugZoneLighting::Inputs(deferredFrameTransform, lightFrame, backgroundFrame).asVarying(); task.addJob("DrawZoneStack", debugZoneInputs); } + + } gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 5fc9580981..969094488e 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -144,7 +144,7 @@ public: RenderDeferredTask(); void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); + void build(JobModel& task, const render::Varying& input, render::Varying& output); private: }; diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 722ba2248c..e34db755b7 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -34,8 +34,6 @@ #include "RenderCommonTask.h" #include "RenderHUDLayerTask.h" -#include "RenderViewTask.h" - namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; @@ -68,16 +66,13 @@ void RenderForwardTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { +void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { task.addJob("SetRenderMethodTask", render::Args::FORWARD); // Prepare the ShapePipelines auto fadeEffect = DependencyManager::get(); - static ShapePlumberPointer shapePlumber = std::make_shared(); - static std::once_flag once; - std::call_once(once, [] { - initForwardPipelines(*shapePlumber); - }); + ShapePlumberPointer shapePlumber = std::make_shared(); + initForwardPipelines(*shapePlumber); // Unpack inputs const auto& inputs = input.get(); @@ -91,7 +86,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; const auto& metas = items[RenderFetchCullSortTask::META]; - const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -113,6 +107,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // First job, alter faded fadeEffect->build(task, opaques); + // GPU jobs: Start preparing the main framebuffer const auto scaledPrimaryFramebuffer = task.addJob("PreparePrimaryBufferForward"); @@ -130,16 +125,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel, hazeFrame).asVarying(); task.addJob("DrawOpaques", opaqueInputs, shapePlumber, true); - const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); -#ifndef Q_OS_ANDROID - if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { - const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, scaledPrimaryFramebuffer, nullJitter).asVarying(); - for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { - task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); - } - } -#endif - // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job const auto backgroundInputs = DrawBackgroundStage::Inputs(lightingModel, backgroundFrame, hazeFrame).asVarying(); task.addJob("DrawBackgroundForward", backgroundInputs); @@ -149,6 +134,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("DrawTransparents", transparentInputs, shapePlumber, false); // Layered + const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, hazeFrame, nullJitter).asVarying(); const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, hazeFrame, nullJitter).asVarying(); task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); @@ -173,7 +159,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto destFramebuffer = static_cast(nullptr); const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); // HUD Layer const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying(); task.addJob("RenderHUDLayer", renderHUDLayerInputs); diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index de3a6dd205..6833e42449 100644 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -36,7 +36,7 @@ public: RenderForwardTask() {} void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); + void build(JobModel& task, const render::Varying& input, render::Varying& output); }; diff --git a/libraries/render-utils/src/RenderHUDLayerTask.cpp b/libraries/render-utils/src/RenderHUDLayerTask.cpp index 8fee3d57bc..743e59eebc 100644 --- a/libraries/render-utils/src/RenderHUDLayerTask.cpp +++ b/libraries/render-utils/src/RenderHUDLayerTask.cpp @@ -16,8 +16,8 @@ void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::Fra assert(renderContext->args); assert(renderContext->args->_context); - // We do not want to render HUD elements in secondary camera or mirrors - if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE || renderContext->args->_mirrorDepth > 0) { + // We do not want to render HUD elements in secondary camera + if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { return; } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index b5a88b0ba9..ed9fb326c4 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -42,7 +42,6 @@ namespace gr { void initDeferredPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); void initForwardPipelines(ShapePlumber& plumber); void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); -void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void addPlumberPipeline(ShapePlumber& plumber, const ShapeKey& key, int programId, @@ -369,45 +368,6 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, con gpu::Shader::createProgram(model_shadow_fade_deformeddq), state, extraBatchSetter, itemSetter); } -void initMirrorPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& extraBatchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward) { - using namespace shader::render_utils::program; - - if (forward) { - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), - gpu::Shader::createProgram(model_shadow_mirror_forward), state); - - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), - gpu::Shader::createProgram(model_shadow_mirror_forward_deformed), state); - - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), - gpu::Shader::createProgram(model_shadow_mirror_forward_deformeddq), state); - } else { - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), - gpu::Shader::createProgram(model_shadow_mirror), state); - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withoutDeformed().withFade(), - gpu::Shader::createProgram(model_shadow_mirror_fade), state, extraBatchSetter, itemSetter); - - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), - gpu::Shader::createProgram(model_shadow_mirror_deformed), state); - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withFade(), - gpu::Shader::createProgram(model_shadow_mirror_fade_deformed), state, extraBatchSetter, itemSetter); - - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), - gpu::Shader::createProgram(model_shadow_mirror_deformeddq), state); - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withFade(), - gpu::Shader::createProgram(model_shadow_mirror_fade_deformeddq), state, extraBatchSetter, itemSetter); - } -} - bool RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures) { graphics::MultiMaterial multiMaterial; multiMaterial.push(graphics::MaterialLayer(material, 0)); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 9fabad5fd0..dbfa23a143 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -46,16 +46,15 @@ void RenderShadowTask::configure(const Config& configuration) { void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cameraCullFunctor, uint8_t tagBits, uint8_t tagMask) { // Prepare the ShapePipeline - static ShapePlumberPointer shapePlumber = std::make_shared(); - static std::once_flag once; - std::call_once(once, [] { + ShapePlumberPointer shapePlumber = std::make_shared(); + { auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - }); + } const auto setupOutput = task.addJob("ShadowSetup", input); const auto queryResolution = setupOutput.getN(1); const auto shadowFrame = setupOutput.getN(3); diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index b9320b6ad3..93a3ff2d67 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -15,7 +15,7 @@ #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { +void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { task.addJob("SetRenderMethodTask", render::Args::DEFERRED); const auto items = input.getN(0); @@ -28,16 +28,16 @@ void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& const auto shadowTaskOut = task.addJob("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask); const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); - task.addJob("RenderDeferredTask", renderDeferredInput, cullFunctor, depth); + task.addJob("RenderDeferredTask", renderDeferredInput); } -void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { - task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask, depth); +void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { + task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask); - task.addBranch("RenderForwardTask", 1, input, cullFunctor, depth); + task.addBranch("RenderForwardTask", 1, input); } -void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { +void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); // Issue the lighting model, aka the big global settings for the view @@ -48,7 +48,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: #ifndef Q_OS_ANDROID const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); - task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask, depth); + task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask); #else const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("RenderForwardTask", renderInput); diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index 139d00125e..cdb56a2189 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -24,7 +24,7 @@ public: RenderShadowsAndDeferredTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); }; @@ -36,7 +36,7 @@ public: DeferredForwardSwitchJob() {} void configure(const render::SwitchConfig& config) {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); }; @@ -47,7 +47,7 @@ public: RenderViewTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00, size_t depth = 0); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); }; diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 8ab1b8e0e9..76d8374fb7 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -40,18 +40,21 @@ float TextRenderer3D::getFontSize() const { return 0.0f; } -void TextRenderer3D::draw(gpu::Batch& batch, const Font::DrawProps& props) { +void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, + const QString& str, const glm::vec4& color, bool unlit, bool forward) { if (_font) { - _font->drawString(batch, _drawInfo, props); + _font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, TextAlignment::LEFT, { x, y }, bounds, 1.0f, unlit, forward); } } -void TextRenderer3D::draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props) { +void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, + const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, + float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward) { if (font != _family) { _family = font; _font = Font::load(_family); } if (_font) { - _font->drawString(batch, _drawInfo, props); + _font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, alignment, { x, y }, bounds, scale, unlit, forward); } } \ No newline at end of file diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index 9db93e9dcc..edccf1429c 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -26,9 +26,12 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const; // Pixel size - - void draw(gpu::Batch& batch, const Font::DrawProps& props); - void draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props); + + void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, + const QString& str, const glm::vec4& color, bool unlit, bool forward); + void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, + const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, + float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward); private: TextRenderer3D(const char* family); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 1ea9deb1fa..10312f7f2e 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -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(sizeof(Parameters), (const gpu::Byte*) ¶meters)); - _depth = depth; } void ToneMapAndResample::init() { @@ -96,8 +95,7 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); - batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); + batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.h b/libraries/render-utils/src/ToneMapAndResampleTask.h index 3a812cf445..1c7ef2cf48 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.h +++ b/libraries/render-utils/src/ToneMapAndResampleTask.h @@ -49,9 +49,11 @@ signals: class ToneMapAndResample { public: - ToneMapAndResample(size_t depth); + ToneMapAndResample(); virtual ~ToneMapAndResample() {} + void render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, gpu::FramebufferPointer& destinationBuffer); + void setExposure(float exposure); float getExposure() const { return _parametersBuffer.get()._exposure; } @@ -73,8 +75,7 @@ protected: gpu::FramebufferPointer _destinationFrameBuffer; - float _factor { 2.0f }; - size_t _depth { 0 }; + float _factor{ 2.0f }; gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index 2f80fbde99..98abc29d8c 100644 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -36,15 +36,7 @@ <@include DeferredBufferWrite.slh@> <@endif@> <@else@> - <@if HIFI_USE_MIRROR@> - <@if HIFI_USE_FORWARD@> - layout(location=0) out vec4 _fragColor0; - <@else@> - <@include DeferredBufferWrite.slh@> - <@endif@> - <@else@> - layout(location=0) out vec4 _fragColor0; - <@endif@> + layout(location=0) out vec4 _fragColor0; <@endif@> <@if HIFI_USE_UNLIT@> @@ -53,9 +45,6 @@ <@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@> <$declareMaterialTextures(ALBEDO)$> - <@if HIFI_USE_MIRROR@> - LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; - <@endif@> <@else@> <@if not HIFI_USE_LIGHTMAP@> <@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@> @@ -135,14 +124,7 @@ void main(void) { <@endif@> <@endif@> - <@if HIFI_USE_MIRROR@> - vec3 mirrorColor = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; - <@if HIFI_USE_FORWARD@> - _fragColor0 = vec4(mirrorColor, 1.0); - <@else@> - packDeferredFragmentUnlit(vec3(1.0, 0.0, 0.0), 1.0, mirrorColor); - <@endif@> - <@elif HIFI_USE_SHADOW@> + <@if HIFI_USE_SHADOW@> _fragColor0 = vec4(1.0); <@elif HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(albedo * isUnlitEnabled(), opacity); diff --git a/libraries/render-utils/src/render-utils/model.slp b/libraries/render-utils/src/render-utils/model.slp index a3c28631e9..b63ec898eb 100644 --- a/libraries/render-utils/src/render-utils/model.slp +++ b/libraries/render-utils/src/render-utils/model.slp @@ -1 +1 @@ -DEFINES (normalmap translucent:f unlit:f/lightmap:f)/(shadow mirror:f) fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file +DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file diff --git a/libraries/render-utils/src/render-utils/sdf_text3D.slp b/libraries/render-utils/src/render-utils/sdf_text3D.slp index f3f9af59aa..118135d099 100644 --- a/libraries/render-utils/src/render-utils/sdf_text3D.slp +++ b/libraries/render-utils/src/render-utils/sdf_text3D.slp @@ -1 +1 @@ -DEFINES (translucent unlit:f)/forward mirror:f \ No newline at end of file +DEFINES (translucent unlit:f)/forward \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index bf9bb0babd..c5bed1ecab 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -41,12 +41,6 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; #define _texCoord1 _texCoord01.zw layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reusing the fade texcoord locations here -<@if HIFI_USE_MIRROR@> - <@include graphics/ShaderConstants.h@> - - LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; -<@endif@> - void main() { vec4 color = evalSDFSuperSampled(_texCoord0, _glyphBounds); @@ -57,11 +51,6 @@ void main() { } <@endif@> -<@if HIFI_USE_MIRROR@> - color.rgb = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; - color.a = 1.0; -<@endif@> - <@if HIFI_USE_UNLIT@> <@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(color.rgb * isUnlitEnabled(), color.a); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index dd7074a071..81cdaa51c9 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -29,7 +29,7 @@ static std::mutex fontMutex; -std::map, gpu::PipelinePointer> Font::_pipelines; +std::map, gpu::PipelinePointer> Font::_pipelines; gpu::Stream::FormatPointer Font::_format; struct TextureVertex { @@ -277,7 +277,6 @@ void Font::setupGPU() { if (_pipelines.empty()) { using namespace shader::render_utils::program; - // transparent, unlit, forward static const std::vector> keys = { std::make_tuple(false, false, false, sdf_text3D), std::make_tuple(true, false, false, sdf_text3D_translucent), std::make_tuple(false, true, false, sdf_text3D_unlit), std::make_tuple(true, true, false, sdf_text3D_translucent_unlit), @@ -285,23 +284,18 @@ void Font::setupGPU() { std::make_tuple(false, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_unlit_forward*/), std::make_tuple(true, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_translucent_unlit_forward*/) }; for (auto& key : keys) { - bool transparent = std::get<0>(key); - bool unlit = std::get<1>(key); - bool forward = std::get<2>(key); - auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, !transparent, gpu::LESS_EQUAL); - state->setBlendFunction(transparent, + state->setDepthTest(true, !std::get<0>(key), gpu::LESS_EQUAL); + state->setBlendFunction(std::get<0>(key), gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - if (transparent) { + if (std::get<0>(key)) { PrepareStencil::testMask(*state); } else { PrepareStencil::testMaskDrawShape(*state); } - _pipelines[std::make_tuple(transparent, unlit, forward, false)] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); - _pipelines[std::make_tuple(transparent, unlit, forward, true)] = gpu::Pipeline::create(gpu::Shader::createProgram(forward ? sdf_text3D_forward_mirror : sdf_text3D_mirror), state); + _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key))] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); } // Sanity checks @@ -450,30 +444,32 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm } } -void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const DrawProps& props) { - if (!_loaded || props.str == "") { +void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, + const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, + const glm::vec2& origin, const glm::vec2& bounds, float scale, bool unlit, bool forward) { + if (!_loaded || str == "") { return; } - int textEffect = (int)props.effect; + int textEffect = (int)effect; const int SHADOW_EFFECT = (int)TextEffect::SHADOW_EFFECT; // If we're switching to or from shadow effect mode, we need to rebuild the vertices - if (props.str != drawInfo.string || props.bounds != drawInfo.bounds || props.origin != drawInfo.origin || props.alignment != _alignment || + if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin || alignment != _alignment || (drawInfo.params.effect != textEffect && (textEffect == SHADOW_EFFECT || drawInfo.params.effect == SHADOW_EFFECT)) || - (textEffect == SHADOW_EFFECT && props.scale != _scale)) { - _scale = props.scale; - _alignment = props.alignment; - buildVertices(drawInfo, props.str, props.origin, props.bounds, props.scale, textEffect == SHADOW_EFFECT, props.alignment); + (textEffect == SHADOW_EFFECT && scale != _scale)) { + _scale = scale; + _alignment = alignment; + buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT, alignment); } setupGPU(); - if (!drawInfo.paramsBuffer || drawInfo.params.color != props.color || drawInfo.params.effectColor != props.effectColor || - drawInfo.params.effectThickness != props.effectThickness || drawInfo.params.effect != textEffect) { - drawInfo.params.color = props.color; - drawInfo.params.effectColor = props.effectColor; - drawInfo.params.effectThickness = props.effectThickness; + if (!drawInfo.paramsBuffer || drawInfo.params.color != color || drawInfo.params.effectColor != effectColor || + drawInfo.params.effectThickness != effectThickness || drawInfo.params.effect != textEffect) { + drawInfo.params.color = color; + drawInfo.params.effectColor = effectColor; + drawInfo.params.effectThickness = effectThickness; drawInfo.params.effect = textEffect; // need the gamma corrected color here @@ -488,7 +484,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const DrawPro drawInfo.paramsBuffer->setSubData(0, sizeof(DrawParams), (const gpu::Byte*)&gpuDrawParams); } - batch.setPipeline(_pipelines[std::make_tuple(props.color.a < 1.0f, props.unlit, props.forward, props.mirror)]); + batch.setPipeline(_pipelines[std::make_tuple(color.a < 1.0f, unlit, forward)]); batch.setInputFormat(_format); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index e8a353a686..322e96439e 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -57,30 +57,10 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const { return _fontSize; } - struct DrawProps { - DrawProps(const QString& str, const glm::vec4& color, const glm::vec3& effectColor, const glm::vec2& origin, const glm::vec2& bounds, - float scale, float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward, bool mirror) : - str(str), color(color), effectColor(effectColor), origin(origin), bounds(bounds), scale(scale), effectThickness(effectThickness), - effect(effect), alignment(alignment), unlit(unlit), forward(forward), mirror(mirror) {} - DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, bool forward) : - str(str), color(color), origin(origin), bounds(bounds), forward(forward) {} - - const QString& str; - const glm::vec4& color; - const glm::vec3& effectColor { glm::vec3(0.0f) }; - const glm::vec2& origin; - const glm::vec2& bounds; - float scale { 1.0f }; - float effectThickness { 0.0f }; - TextEffect effect { TextEffect::NO_EFFECT }; - TextAlignment alignment { TextAlignment::LEFT }; - bool unlit = true; - bool forward; - bool mirror = false; - }; - // Render string to batch - void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const DrawProps& props); + void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color, + const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, + const glm::vec2& origin, const glm::vec2& bound, float scale, bool unlit, bool forward); static Pointer load(const QString& family); @@ -125,7 +105,7 @@ private: gpu::TexturePointer _texture; gpu::BufferStreamPointer _stream; - static std::map, gpu::PipelinePointer> _pipelines; + static std::map, gpu::PipelinePointer> _pipelines; static gpu::Stream::FormatPointer _format; }; diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index fb7d698672..d09b0d2f2f 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -159,10 +159,6 @@ namespace render { bool _takingSnapshot { false }; StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE }; std::function _stencilMaskOperator; - - ItemID _ignoreItem { 0 }; - size_t _mirrorDepth { 0 }; - size_t _numMirrorFlips { 0 }; }; } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index cd69114bbf..039cf01c86 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -82,7 +82,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const outItems.reserve(items.size()); for (auto& id : items) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { + if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args))); } } @@ -190,7 +190,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -205,7 +205,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -220,7 +220,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -235,7 +235,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -252,7 +252,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -267,7 +267,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -284,7 +284,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -301,7 +301,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -325,6 +325,73 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, std::static_pointer_cast(renderContext->jobConfig)->numItems = (int)outItems.size(); } +void CullShapeBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + + const auto& inShapes = inputs.get0(); + const auto& cullFilter = inputs.get1(); + const auto& boundsFilter = inputs.get2(); + ViewFrustumPointer antiFrustum; + auto& outShapes = outputs.edit0(); + auto& outBounds = outputs.edit1(); + + if (!inputs[3].isNull()) { + antiFrustum = inputs.get3(); + } + outShapes.clear(); + outBounds = AABox(); + + if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { + auto& details = args->_details.edit(_detailType); + CullTest test(_cullFunctor, args, details, antiFrustum); + auto scene = args->_scene; + + for (auto& inItems : inShapes) { + auto key = inItems.first; + auto outItems = outShapes.find(key); + if (outItems == outShapes.end()) { + outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first; + outItems->second.reserve(inItems.second.size()); + } + + details._considered += (int)inItems.second.size(); + + if (antiFrustum == nullptr) { + for (auto& item : inItems.second) { + if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } + } + } + } else { + for (auto& item : inItems.second) { + if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } + } + } + } + details._rendered += (int)outItems->second.size(); + } + + for (auto& items : outShapes) { + items.second.shrink_to_fit(); + } + } +} + void ApplyCullFunctorOnItemBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 9e214fd988..9a7466223d 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -121,6 +121,29 @@ namespace render { void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; + class CullShapeBounds { + public: + using Inputs = render::VaryingSet4; + using Outputs = render::VaryingSet2; + using JobModel = Job::ModelIO; + + CullShapeBounds(CullFunctor cullFunctor, RenderDetails::Type type) : + _cullFunctor{ cullFunctor }, + _detailType(type) {} + + CullShapeBounds(CullFunctor cullFunctor) : + _cullFunctor{ cullFunctor } { + } + + void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); + + private: + + CullFunctor _cullFunctor; + RenderDetails::Type _detailType{ RenderDetails::OTHER }; + + }; + class ApplyCullFunctorOnItemBounds { public: using Inputs = render::VaryingSet2; diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 1633523267..369f227566 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -160,11 +160,4 @@ namespace render { } return payload->passesZoneOcclusionTest(containingZones); } - - template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum) { - if (!payload) { - return Item::INVALID_ITEM_ID; - } - return payload->computeMirrorView(viewFrustum); - } } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index f91b887fcb..5952be8a84 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -110,8 +110,6 @@ public: FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, - MIRROR, - __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag @@ -164,7 +162,6 @@ public: Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } - Builder& withMirror() { _flags.set(MIRROR); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -208,9 +205,6 @@ public: bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } - bool isNotMirror() const { return !_flags[MIRROR]; } - bool isMirror() const { return _flags[MIRROR]; } - bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } @@ -280,10 +274,7 @@ public: Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } - Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } - - Builder& withoutMirror() { _value.reset(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } - Builder& withMirror() { _value.set(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } + Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } @@ -301,7 +292,6 @@ public: static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } - static Builder mirror() { return Builder().withMirror(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; @@ -450,8 +440,6 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; - virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; - ~PayloadInterface() {} // Status interface is local to the base class @@ -505,8 +493,6 @@ public: bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); } - ItemID computeMirrorView(ViewFrustum& viewFrustum) const { return _payload->computeMirrorView(viewFrustum); } - // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -561,9 +547,6 @@ template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payl // Allows payloads to determine if they should render or not, based on the zones that contain the current camera template bool payloadPassesZoneOcclusionTest(const std::shared_ptr& payloadData, const std::unordered_set& containingZones) { return true; } -// Mirror Interface -template ItemID payloadComputeMirrorView(const std::shared_ptr& payloadData, ViewFrustum& viewFrustum) { return Item::INVALID_ITEM_ID; } - // THe Payload class is the real Payload to be used // THis allow anything to be turned into a Payload as long as the required interface functions are available // When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" @@ -590,8 +573,6 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override { return payloadPassesZoneOcclusionTest(_data, containingZones); } - virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView(_data, viewFrustum); } - protected: DataPointer _data; @@ -647,7 +628,6 @@ public: virtual void render(RenderArgs* args) = 0; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; - virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface virtual void handleBlendedVertices(int blendshapeNumber, const QVector& blendshapeOffsets, @@ -660,7 +640,6 @@ template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, Re template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems); template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload); template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set& containingZones); -template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum); typedef Item::PayloadPointer PayloadPointer; typedef std::vector Payloads; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 3bdaee25c6..b2656a597f 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -35,20 +35,18 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto nonspatialSelection = task.addJob("FetchLayeredSelection", nonspatialFilter); // Multi filter visible items into different buckets - const int NUM_SPATIAL_FILTERS = 5; + const int NUM_SPATIAL_FILTERS = 4; const int NUM_NON_SPATIAL_FILTERS = 3; const int OPAQUE_SHAPE_BUCKET = 0; const int TRANSPARENT_SHAPE_BUCKET = 1; const int LIGHT_BUCKET = 2; const int META_BUCKET = 3; - const int MIRROR_BUCKET = 4; const int BACKGROUND_BUCKET = 2; MultiFilterItems::ItemFilterArray spatialFilters = { { - ItemFilter::Builder::opaqueShape().withoutMirror(), + ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::light(), - ItemFilter::Builder::meta().withoutMirror(), - ItemFilter::Builder::mirror() + ItemFilter::Builder::meta() } }; MultiFilterItems::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), @@ -67,7 +65,6 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto transparents = task.addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; const auto metas = filteredSpatialBuckets[META_BUCKET]; - const auto mirrors = task.addJob("DepthSortMirrors", filteredSpatialBuckets[MIRROR_BUCKET]); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; @@ -79,7 +76,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin task.addJob("ClearContainingZones"); - output = Output(BucketList{ opaques, transparents, lights, metas, mirrors, + output = Output(BucketList{ opaques, transparents, lights, metas, filteredLayeredOpaque.getN(0), filteredLayeredTransparent.getN(0), filteredLayeredOpaque.getN(1), filteredLayeredTransparent.getN(1), background }, spatialSelection); diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index 9823c2acdf..0b475614a1 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -23,7 +23,6 @@ public: TRANSPARENT_SHAPE, LIGHT, META, - MIRROR, LAYER_FRONT_OPAQUE_SHAPE, LAYER_FRONT_TRANSPARENT_SHAPE, LAYER_HUD_OPAQUE_SHAPE, diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index e77dda600c..b868c53542 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,8 +167,7 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); - batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); + batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index bf1e535949..92f720c843 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -73,7 +73,7 @@ namespace render { using Input = gpu::FramebufferPointer; using JobModel = Job::ModelIO; - UpsampleToBlitFramebuffer(size_t depth) : _depth(depth) {} + UpsampleToBlitFramebuffer() {} void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); @@ -81,8 +81,6 @@ namespace render { static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _mirrorPipeline; - - size_t _depth; }; } diff --git a/libraries/shared/src/MirrorMode.cpp b/libraries/shared/src/MirrorMode.cpp deleted file mode 100644 index 272eb5d7c0..0000000000 --- a/libraries/shared/src/MirrorMode.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// -// Created by HifiExperiments on 3/14/22. -// Copyright 2022 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 "MirrorMode.h" - -const char* MirrorModeNames[] = { - "none", - "mirror", - "portal" -}; - -static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0])); -std::function MirrorModeHelpers::_computeMirrorViewOperator = - [](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return 0; }; - -QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { - if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) { - mode = (MirrorMode)0; - } - - return MirrorModeNames[(int)mode]; -} - -void MirrorModeHelpers::setComputeMirrorViewOperator(std::function computeMirrorViewOperator) { - _computeMirrorViewOperator = computeMirrorViewOperator; -} - -uint32_t MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID) { - return _computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); -} \ No newline at end of file diff --git a/libraries/shared/src/MirrorMode.h b/libraries/shared/src/MirrorMode.h deleted file mode 100644 index e48e564df0..0000000000 --- a/libraries/shared/src/MirrorMode.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Created by HifiExperiments on 3/14/22. -// Copyright 2022 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_MirrorMode_h -#define hifi_MirrorMode_h - -#include - -#include "QString" - -#include "ViewFrustum.h" - -/*@jsdoc - *

If an entity is rendered as a mirror, a portal, or normally.

- *
- * - * - * - * - * - * - * - * - *
ValueDescription
"none"The entity will render normally.
"mirror"The entity will render as a mirror.
"portal"The entity will render as a portal.
- * @typedef {string} MirrorMode - */ - -enum class MirrorMode { - NONE = 0, - MIRROR, - PORTAL -}; - -class MirrorModeHelpers { -public: - static QString getNameForMirrorMode(MirrorMode mode); - - static void setComputeMirrorViewOperator(std::function computeMirrorViewOperator); - static uint32_t computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, - MirrorMode mirrorMode, const QUuid& portalExitID); - -private: - static std::function _computeMirrorViewOperator; -}; - -#endif // hifi_MirrorMode_h diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index daa08b5dbc..e925ef960d 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -53,7 +53,7 @@ static const glm::vec4 NDC_VALUES[NUM_FRUSTUM_CORNERS] = { glm::vec4(-1.0f, 1.0f, 1.0f, 1.0f), }; -void ViewFrustum::setProjection(const glm::mat4& projection, bool isOblique) { +void ViewFrustum::setProjection(const glm::mat4& projection) { _projection = projection; glm::mat4 inverseProjection = glm::inverse(projection); @@ -63,21 +63,16 @@ void ViewFrustum::setProjection(const glm::mat4& projection, bool isOblique) { _corners[i] /= _corners[i].w; } - // HACK: these calculations aren't correct for our oblique mirror frustums, but we can just reuse the values from the original - // frustum since these values are only used on the CPU. - if (!isOblique) { - // compute frustum properties - _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; - _farClip = -_corners[BOTTOM_LEFT_FAR].z; - _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / - (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); - glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); - top /= top.w; - _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); - _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; - _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; - } - _isOblique = isOblique; + // compute frustum properties + _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; + _farClip = -_corners[BOTTOM_LEFT_FAR].z; + _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / + (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); + glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); + top /= top.w; + _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); + _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; + _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; } void ViewFrustum::setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip) { @@ -114,24 +109,12 @@ void ViewFrustum::calculate() { // the function set3Points assumes that the points are given in counter clockwise order, assume you // are inside the frustum, facing the plane. Start with any point, and go counter clockwise for // three consecutive points - if (!_isOblique) { - _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); - _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); - _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); - _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); - } else { - Corners near = getCorners(_nearClip); - Corners far = getCorners(_farClip); - - _planes[TOP_PLANE].set3Points(near.topRight, near.topLeft, far.topLeft); - _planes[BOTTOM_PLANE].set3Points(near.bottomLeft, near.bottomRight, far.bottomRight); - _planes[LEFT_PLANE].set3Points(near.bottomLeft, far.bottomLeft, far.topLeft); - _planes[RIGHT_PLANE].set3Points(far.bottomRight, near.bottomRight, far.topRight); - _planes[NEAR_PLANE].set3Points(near.bottomRight, near.bottomLeft, near.topLeft); - _planes[FAR_PLANE].set3Points(far.bottomLeft, far.bottomRight, far.topRight); - } + _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); + _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); + _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); + _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); // Also calculate our projection matrix in case people want to project points... // Projection matrix : Field of View, ratio, display range : near to far diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index fa66a0a87e..9c80538e60 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -47,7 +47,7 @@ public: const glm::vec3& getRight() const { return _right; } // setters for lens attributes - void setProjection(const glm::mat4& projection, bool isOblique = false); + void setProjection(const glm::mat4 & projection); void setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip); void setFocalLength(float focalLength) { _focalLength = focalLength; } bool isPerspective() const; @@ -103,6 +103,7 @@ public: bool pointIntersectsFrustum(const glm::vec3& point) const; bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const; + bool cubeIntersectsFrustum(const AACube& box) const; bool boxIntersectsFrustum(const AABox& box) const; bool boxInsideFrustum(const AABox& box) const; @@ -174,8 +175,6 @@ private: float _nearClip { DEFAULT_NEAR_CLIP }; float _farClip { DEFAULT_FAR_CLIP }; - bool _isOblique { false }; - const char* debugPlaneName (int plane) const; // Used to project points diff --git a/scripts/system/create/assets/data/createAppTooltips.json b/scripts/system/create/assets/data/createAppTooltips.json index 57cb3d1bc8..9f6c3ef278 100644 --- a/scripts/system/create/assets/data/createAppTooltips.json +++ b/scripts/system/create/assets/data/createAppTooltips.json @@ -215,7 +215,7 @@ }, "imageAlpha": { "tooltip": "The opacity of the image between 0.0 fully transparent and 1.0 completely opaque." - }, + }, "emissive": { "tooltip": "If enabled, the image will display at full brightness." }, @@ -236,7 +236,7 @@ }, "showKeyboardFocusHighlight": { "tooltip": "If enabled, highlights when it has keyboard focus." - }, + }, "isEmitting": { "tooltip": "If enabled, then particles are emitted." }, @@ -503,12 +503,6 @@ "grab.triggerable": { "tooltip": "If enabled, the collider on this entity is used for triggering events." }, - "mirrorMode": { - "tooltip": "If this entity should render normally, or as a \"Mirror\" or \"Portal\"" - }, - "portalExitID": { - "tooltip": "If this entity is a portal, what entity it should use as its exit." - }, "cloneable": { "tooltip": "If enabled, this entity can be duplicated." }, @@ -612,7 +606,7 @@ }, "useBackground": { "tooltip": "If disabled, this web entity will support a transparent background for the webpage and its elements if the CSS property of 'background-color' on the 'body' is set with transparency." - }, + }, "maxFPS": { "tooltip": "The FPS at which to render the web entity. Higher values will have a performance impact." }, diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index b509168262..e16b6ca653 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -127,22 +127,6 @@ const GROUPS = [ }, propertyID: "billboardMode", }, - { - label: "Mirror Mode", - type: "dropdown", - options: { - none: "None", - mirror: "Mirror", - portal: "Portal" - }, - propertyID: "mirrorMode", - }, - { - label: "Portal Exit", - type: "string", - propertyID: "portalExitID", - showPropertyRule: { "mirrorMode": "portal" }, - }, { label: "Render With Zones", type: "multipleZonesSelection", diff --git a/tools/gpu-frame-player/src/RenderThread.cpp b/tools/gpu-frame-player/src/RenderThread.cpp index de39dacdea..0089c1577b 100644 --- a/tools/gpu-frame-player/src/RenderThread.cpp +++ b/tools/gpu-frame-player/src/RenderThread.cpp @@ -122,7 +122,7 @@ void RenderThread::renderFrame(gpu::FramePointer& frame) { if (_correction != glm::mat4()) { std::unique_lock lock(_frameLock); if (_correction != glm::mat4()) { - _backend->setCameraCorrection(_correction, _activeFrame->view, true); + _backend->setCameraCorrection(_correction, _activeFrame->view); //_prevRenderView = _correction * _activeFrame->view; } } From e7591d6794436d6a16bcd47dfdbe291bad2c6c16 Mon Sep 17 00:00:00 2001 From: Dale Glass <51060919+daleglass@users.noreply.github.com> Date: Sat, 13 Jan 2024 11:23:36 +0100 Subject: [PATCH 18/18] Revert "Revert "Mirrors + Portals"" --- interface/src/Application.cpp | 1 + interface/src/SecondaryCamera.cpp | 3 +- interface/src/avatar/MyAvatar.cpp | 3 +- .../scripting/RenderScriptingInterface.cpp | 24 ++- .../src/avatars-renderer/Avatar.cpp | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 4 +- .../src/RenderableEntityItem.cpp | 114 ++++++++++++- .../src/RenderableEntityItem.h | 12 +- .../src/RenderableGizmoEntityItem.cpp | 3 +- .../src/RenderableGridEntityItem.cpp | 3 +- .../src/RenderableImageEntityItem.cpp | 9 +- .../src/RenderableLineEntityItem.cpp | 3 +- .../src/RenderableMaterialEntityItem.cpp | 3 +- .../src/RenderableModelEntityItem.cpp | 16 ++ .../src/RenderableModelEntityItem.h | 2 + .../src/RenderablePolyLineEntityItem.cpp | 3 +- .../src/RenderablePolyVoxEntityItem.cpp | 3 +- .../src/RenderableShapeEntityItem.cpp | 5 +- .../src/RenderableTextEntityItem.cpp | 38 ++++- .../src/RenderableTextEntityItem.h | 2 + .../src/RenderableWebEntityItem.cpp | 3 +- libraries/entities/src/EntityItem.cpp | 36 ++++ libraries/entities/src/EntityItem.h | 9 + .../entities/src/EntityItemProperties.cpp | 44 +++++ libraries/entities/src/EntityItemProperties.h | 3 + libraries/entities/src/EntityPropertyFlags.h | 2 + .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 33 +++- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 6 +- libraries/gpu/src/gpu/Batch.cpp | 6 + libraries/gpu/src/gpu/Batch.h | 2 + libraries/gpu/src/gpu/Context.h | 2 +- libraries/gpu/src/gpu/FrameIOKeys.h | 1 + .../graphics/src/graphics/ShaderConstants.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/octree/src/OctreePacketData.h | 2 + .../src/CauterizedMeshPartPayload.cpp | 7 +- .../src/CauterizedMeshPartPayload.h | 2 +- .../src/DeferredLightingEffect.cpp | 1 + .../render-utils/src/DeferredLightingEffect.h | 4 +- .../render-utils/src/HighlightEffect.cpp | 7 +- .../render-utils/src/MeshPartPayload.cpp | 32 +++- libraries/render-utils/src/MeshPartPayload.h | 9 +- libraries/render-utils/src/Model.cpp | 46 ++++- libraries/render-utils/src/Model.h | 9 + .../render-utils/src/RenderCommonTask.cpp | 159 +++++++++++++++++- libraries/render-utils/src/RenderCommonTask.h | 17 +- .../render-utils/src/RenderDeferredTask.cpp | 33 ++-- .../render-utils/src/RenderDeferredTask.h | 2 +- .../render-utils/src/RenderForwardTask.cpp | 26 ++- .../render-utils/src/RenderForwardTask.h | 2 +- .../render-utils/src/RenderHUDLayerTask.cpp | 4 +- .../render-utils/src/RenderPipelines.cpp | 40 +++++ .../render-utils/src/RenderShadowTask.cpp | 7 +- libraries/render-utils/src/RenderViewTask.cpp | 14 +- libraries/render-utils/src/RenderViewTask.h | 6 +- libraries/render-utils/src/TextRenderer3D.cpp | 11 +- libraries/render-utils/src/TextRenderer3D.h | 9 +- .../src/ToneMapAndResampleTask.cpp | 6 +- .../render-utils/src/ToneMapAndResampleTask.h | 7 +- libraries/render-utils/src/model.slf | 22 ++- .../render-utils/src/render-utils/model.slp | 2 +- .../src/render-utils/sdf_text3D.slp | 2 +- libraries/render-utils/src/sdf_text3D.slf | 11 ++ libraries/render-utils/src/text/Font.cpp | 46 ++--- libraries/render-utils/src/text/Font.h | 28 ++- libraries/render/src/render/Args.h | 4 + libraries/render/src/render/CullTask.cpp | 85 +--------- libraries/render/src/render/CullTask.h | 23 --- libraries/render/src/render/Item.cpp | 7 + libraries/render/src/render/Item.h | 23 ++- .../src/render/RenderFetchCullSortTask.cpp | 11 +- .../src/render/RenderFetchCullSortTask.h | 1 + libraries/render/src/render/ResampleTask.cpp | 3 +- libraries/render/src/render/ResampleTask.h | 4 +- libraries/shared/src/MirrorMode.cpp | 36 ++++ libraries/shared/src/MirrorMode.h | 51 ++++++ libraries/shared/src/ViewFrustum.cpp | 51 ++++-- libraries/shared/src/ViewFrustum.h | 5 +- .../create/assets/data/createAppTooltips.json | 12 +- .../html/js/entityProperties.js | 16 ++ tools/gpu-frame-player/src/RenderThread.cpp | 2 +- 81 files changed, 1047 insertions(+), 263 deletions(-) create mode 100644 libraries/shared/src/MirrorMode.cpp create mode 100644 libraries/shared/src/MirrorMode.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a9e4bedbbd..931c41703b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2479,6 +2479,7 @@ Application::Application( copyViewFrustum(viewFrustum); return viewFrustum.getPosition(); }); + MirrorModeHelpers::setComputeMirrorViewOperator(EntityRenderer::computeMirrorViewOperator); DependencyManager::get()->setKickConfirmationOperator([this] (const QUuid& nodeID, unsigned int banFlags) { userKickConfirmation(nodeID, banFlags); }); diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 704d7963e7..130b8c77ea 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -27,7 +27,7 @@ public: using Config = SecondaryCameraJobConfig; using JobModel = render::Job::ModelO; SecondaryCameraJob() { - _cachedArgsPointer = std::make_shared(_cachedArgs); + _cachedArgsPointer = std::make_shared(); _attachedEntityPropertyFlags += PROP_POSITION; _attachedEntityPropertyFlags += PROP_ROTATION; } @@ -203,7 +203,6 @@ public: } protected: - RenderArgs _cachedArgs; RenderArgsPointer _cachedArgsPointer; private: diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 827388aa1c..bb6fbcd899 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3530,8 +3530,9 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false; + bool isInMirror = renderArgs->_mirrorDepth > 0; bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); - return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); + return !defaultMode || isInMirror || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); } void MyAvatar::setRotationRecenterFilterLength(float length) { diff --git a/interface/src/scripting/RenderScriptingInterface.cpp b/interface/src/scripting/RenderScriptingInterface.cpp index 12814aa6b6..47f772b4bc 100644 --- a/interface/src/scripting/RenderScriptingInterface.cpp +++ b/interface/src/scripting/RenderScriptingInterface.cpp @@ -9,6 +9,7 @@ // #include "RenderScriptingInterface.h" +#include #include #include "LightingModel.h" @@ -79,14 +80,35 @@ void RenderScriptingInterface::setRenderMethod(RenderMethod renderMethod) { emit settingsChanged(); } } + +void recursivelyUpdateMirrorRenderMethods(const QString& parentTaskName, int renderMethod, int depth) { + if (depth == RenderMirrorTask::MAX_MIRROR_DEPTH) { + return; + } + + for (size_t mirrorIndex = 0; mirrorIndex < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; mirrorIndex++) { + std::string mirrorTaskString = parentTaskName.toStdString() + ".RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth) + ".DeferredForwardSwitch"; + auto mirrorConfig = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(QString::fromStdString(mirrorTaskString))); + if (mirrorConfig) { + mirrorConfig->setBranch((int)renderMethod); + recursivelyUpdateMirrorRenderMethods(QString::fromStdString(mirrorTaskString) + (renderMethod == 1 ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), + renderMethod, depth + 1); + } + } +} + void RenderScriptingInterface::forceRenderMethod(RenderMethod renderMethod) { _renderSettingLock.withWriteLock([&] { _renderMethod = (int)renderMethod; _renderMethodSetting.set((int)renderMethod); - auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch")); + QString configName = "RenderMainView.DeferredForwardSwitch"; + auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(configName)); if (config) { config->setBranch((int)renderMethod); + + recursivelyUpdateMirrorRenderMethods(configName + (renderMethod == RenderMethod::FORWARD ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), + (int)renderMethod, 0); } }); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index b2d6a6260b..790b45843c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1120,7 +1120,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - displayNameRenderer->draw(batch, text_x, -text_y, glm::vec2(-1.0f), nameUTF8.data(), textColor, true, forward); + displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), forward }); } } } diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 03a463c82a..47f22dfaee 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -357,7 +357,7 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - getGLBackend()->setCameraCorrection(mat4(), mat4(), true); + getGLBackend()->setCameraCorrection(mat4(), mat4(), true, true); for (auto& cursorValue : _cursorsData) { auto& cursorData = cursorValue.second; @@ -701,7 +701,7 @@ void OpenGLDisplayPlugin::present(const std::shared_ptr& if (_currentFrame) { auto correction = getViewCorrection(); - getGLBackend()->setCameraCorrection(correction, _prevRenderView); + getGLBackend()->setCameraCorrection(correction, _prevRenderView, true); _prevRenderView = correction * _currentFrame->view; { withPresentThreadLock([&] { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 212baa6634..09bbfb9284 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -12,6 +12,7 @@ #include "RenderableEntityItem.h" +#include #include #include "RenderableShapeEntityItem.h" @@ -192,6 +193,10 @@ ItemKey EntityRenderer::getKey() { builder.withSubMetaCulled(); } + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + builder.withMirror(); + } + if (!_visible) { builder.withInvisible(); } @@ -221,12 +226,113 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co return true; } +ItemID EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { + glm::vec3 inPropertiesPosition; + glm::quat inPropertiesRotation; + MirrorMode mirrorMode; + QUuid portalExitID; + withReadLock([&]{ + inPropertiesPosition = _entity->getWorldPosition(); + inPropertiesRotation = _entity->getWorldOrientation(); + mirrorMode = _mirrorMode; + portalExitID = _portalExitID; + }); + return computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +} + +ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { + glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation); + glm::mat4 worldToIn = glm::inverse(inToWorld); + + glm::vec3 outPropertiesPosition = inPropertiesPosition; + glm::quat outPropertiesRotation = inPropertiesRotation; + glm::mat4 outToWorld = inToWorld; + bool foundPortalExit = false; + if (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) { + auto renderer = DependencyManager::get(); + if (renderer) { + if (auto renderable = renderer->renderableForEntityId(portalExitID)) { + renderable->withReadLock([&] { + outPropertiesPosition = renderable->_entity->getWorldPosition(); + outPropertiesRotation = renderable->_entity->getWorldOrientation(); + }); + + outToWorld = glm::translate(outPropertiesPosition) * glm::mat4_cast(outPropertiesRotation); + foundPortalExit = true; + } + } + } + + // get mirror camera position by reflecting main camera position's z coordinate in mirror space + glm::vec3 cameraPositionWorld = viewFrustum.getPosition(); + glm::vec3 cameraPositionIn = vec3(worldToIn * vec4(cameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionIn = vec3(cameraPositionIn.x, cameraPositionIn.y, -cameraPositionIn.z); + if (foundPortalExit) { + // portals also flip over x + mirrorCameraPositionIn.x *= -1.0f; + } + glm::vec3 mirrorCameraPositionWorld = vec3(outToWorld * vec4(mirrorCameraPositionIn, 1.0f)); + + // get mirror camera rotation by reflecting main camera rotation in mirror space + // TODO: we are assuming here that UP is world y-axis + glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); + glm::quat mainCameraRotationMirror = worldToIn * glm::mat4_cast(mainCameraRotationWorld); + glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * + glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); + if (foundPortalExit) { + // portals also flip over x + mirrorCameraRotationMirror = glm::quat(mirrorCameraRotationMirror.w, mirrorCameraRotationMirror.x, -mirrorCameraRotationMirror.y, -mirrorCameraRotationMirror.z); + } + glm::quat mirrorCameraRotationWorld = outToWorld * glm::mat4_cast(mirrorCameraRotationMirror); + + viewFrustum.setPosition(mirrorCameraPositionWorld); + viewFrustum.setOrientation(mirrorCameraRotationWorld); + + // modify the near clip plane to be the XY plane of the mirror + // from: https://terathon.com/lengyel/Lengyel-Oblique.pdf + glm::mat4 view = viewFrustum.getView(); + glm::mat4 projection = viewFrustum.getProjection(); + + //Find the camera-space 4D reflection plane vector + glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(outPropertiesPosition, 1.0f); + glm::vec3 cameraSpaceNormal = glm::transpose(view) * (outPropertiesRotation * glm::vec4(0, 0, -1, 0)); + glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); + // Make sure we pick the direction facing away from us + if (clipPlane.w > 0.0f) { + clipPlane *= -1.0f; + } + + // Calculate the clip-space corner point opposite the clipping plane + // as (sign(clipPlane.x), sign(clipPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + glm::vec4 q; + q.x = (glm::sign(clipPlane.x) + projection[0][2]) / projection[0][0]; + q.y = (glm::sign(clipPlane.y) + projection[1][2]) / projection[1][1]; + q.z = -1.0f; + q.w = (1.0f + projection[2][2]) / projection[2][3]; + + // Calculate the scaled plane vector + glm::vec4 c = (2.0f / glm::dot(clipPlane, q)) * clipPlane; + + // Replace the third row of the projection matrix + projection[0][2] = c.x; + projection[1][2] = c.y; + projection[2][2] = c.z + 1.0f; + projection[3][2] = c.w; + + viewFrustum.setProjection(projection, true); + + return foundPortalExit ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID; +} + void EntityRenderer::render(RenderArgs* args) { if (!isValidRenderItem()) { return; } - if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { + if (_visible && (!_cauterized || args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || args->_mirrorDepth > 0)) { doRender(args); } } @@ -454,6 +560,8 @@ void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) _canCastShadow = entity->getCanCastShadow(); setCullWithParent(entity->getCullWithParent()); _cauterized = entity->getCauterized(); + setMirrorMode(entity->getMirrorMode()); + setPortalExitID(entity->getPortalExitID()); if (entity->needsZoneOcclusionUpdate()) { entity->resetNeedsZoneOcclusionUpdate(); _renderWithZones = entity->getRenderWithZones(); @@ -505,6 +613,10 @@ graphics::MaterialPointer EntityRenderer::getTopMaterial() { } EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) { + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + return Pipeline::MIRROR; + } + if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) { return Pipeline::PROCEDURAL; } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 3caeef0713..99dbffbc72 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -58,12 +58,13 @@ public: enum class Pipeline { SIMPLE, MATERIAL, - PROCEDURAL + PROCEDURAL, + MIRROR }; virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); virtual graphics::MaterialPointer getTopMaterial(); - static Pipeline getPipelineType(const graphics::MultiMaterial& materials); + Pipeline getPipelineType(const graphics::MultiMaterial& materials); virtual gpu::TexturePointer getTexture() { return nullptr; } virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); } @@ -74,6 +75,9 @@ public: virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override; virtual Item::Bound getBound(RenderArgs* args) override; bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override; + ItemID computeMirrorView(ViewFrustum& viewFrustum) const override; + static ItemID computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } @@ -116,6 +120,8 @@ protected: virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; } virtual void setCullWithParent(bool value) { _cullWithParent = value; } + virtual void setMirrorMode(MirrorMode value) { _mirrorMode = value; } + virtual void setPortalExitID(const QUuid& value) { _portalExitID = value; } template std::shared_ptr asTypedEntity() { return std::static_pointer_cast(_entity); } @@ -151,6 +157,8 @@ protected: BillboardMode _billboardMode { BillboardMode::NONE }; bool _cauterized { false }; bool _moving { false }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; Transform _renderTransform; MaterialMap _materials; diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp index 42df1e2888..10ae144334 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp @@ -263,8 +263,9 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index e374fe29c0..3f40218d46 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -103,8 +103,9 @@ void GridEntityRenderer::doRender(RenderArgs* args) { } else { transform.setTranslation(renderTransform.getTranslation()); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch->setModelTransform(transform); auto minCorner = glm::vec2(-0.5f, -0.5f); diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 9592a3e57f..66a5d0d609 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -147,8 +147,9 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { gpu::Batch* batch = args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float imageWidth = _texture->getWidth(); float imageHeight = _texture->getHeight(); @@ -198,8 +199,10 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent)); } else if (pipelineType == Pipeline::SIMPLE) { batch->setResourceTexture(0, _texture->getGPUTexture()); - } else if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; + } else if (pipelineType == Pipeline::MATERIAL) { + if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; + } } DependencyManager::get()->renderQuad( diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index a36cdde212..1117c97c75 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -47,8 +47,9 @@ void LineEntityRenderer::doRender(RenderArgs* args) { const auto& modelTransform = getModelTransform(); Transform transform = Transform(); transform.setTranslation(modelTransform.getTranslation()); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch, false, false, false, false, true, diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index b8f829f4ba..fe44c41094 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -303,8 +303,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { proceduralRender = true; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (!proceduralRender) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8ed3f84609..6b83d87732 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1274,6 +1274,8 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint _model->setBillboardMode(_billboardMode, scene); _model->setCullWithParent(_cullWithParent, scene); _model->setRenderWithZones(_renderWithZones, scene); + _model->setMirrorMode(_mirrorMode, scene); + _model->setPortalExitID(_portalExitID, scene); }); if (didVisualGeometryRequestSucceed) { emit DependencyManager::get()-> @@ -1353,6 +1355,8 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint model->setBillboardMode(_billboardMode, scene); model->setCullWithParent(_cullWithParent, scene); model->setRenderWithZones(_renderWithZones, scene); + model->setMirrorMode(_mirrorMode, scene); + model->setPortalExitID(_portalExitID, scene); }); if (entity->blendshapesChanged()) { @@ -1466,6 +1470,18 @@ void ModelEntityRenderer::setCullWithParent(bool value) { setKey(_didLastVisualGeometryRequestSucceed, _model); } +void ModelEntityRenderer::setMirrorMode(MirrorMode value) { + Parent::setMirrorMode(value); + // called within a lock so no need to lock for _model + setKey(_didLastVisualGeometryRequestSucceed, _model); +} + +void ModelEntityRenderer::setPortalExitID(const QUuid& value) { + Parent::setPortalExitID(value); + // called within a lock so no need to lock for _model + setKey(_didLastVisualGeometryRequestSucceed, _model); +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index f394d389f5..425d082f01 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -170,6 +170,8 @@ protected: void setIsVisibleInSecondaryCamera(bool value) override; void setRenderLayer(RenderLayer value) override; void setCullWithParent(bool value) override; + void setMirrorMode(MirrorMode value) override; + void setPortalExitID(const QUuid& value) override; private: void animate(const TypedEntityPointer& entity, const ModelPointer& model); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index aca501985a..81f4c5fcb4 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -325,8 +325,9 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { buildPipelines(); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 8331e016fd..26091a1ed4 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1860,8 +1860,9 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); gpu::Batch& batch = *args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index a6fee03311..82350f54bf 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -118,8 +118,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron)); batch.setModelTransform(transform); @@ -157,7 +158,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } } } else { - if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { + if (pipelineType == Pipeline::MATERIAL && RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 2858e12afd..a15e2839a4 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -164,8 +164,9 @@ void TextEntityRenderer::doRender(RenderArgs* args) { transform = _renderTransform; }); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); @@ -180,7 +181,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { } auto geometryCache = DependencyManager::get(); - if (pipelineType == Pipeline::SIMPLE) { + if (pipelineType == Pipeline::SIMPLE || pipelineType == Pipeline::MIRROR) { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), backgroundColor, _geometryID); } else { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), glm::vec2(0.0f), glm::vec2(1.0f), backgroundColor, _geometryID); @@ -260,6 +261,10 @@ ItemKey entities::TextPayload::getKey() const { builder.withInvisible(); } + if (textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull())) { + builder.withMirror(); + } + return builder; } } @@ -311,6 +316,17 @@ bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set(); + if (entityTreeRenderer) { + auto renderable = entityTreeRenderer->renderableForEntityId(_entityID); + if (renderable) { + return renderable->computeMirrorView(viewFrustum); + } + } + return Item::INVALID_ITEM_ID; +} + void entities::TextPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("TextPayload::render"); Q_ASSERT(args->_batch); @@ -335,12 +351,15 @@ void entities::TextPayload::render(RenderArgs* args) { glm::vec3 dimensions; glm::vec4 textColor; + bool mirror; textRenderable->withReadLock([&] { transform = textRenderable->_renderTransform; dimensions = textRenderable->_dimensions; float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f; textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha); + + mirror = textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull()); }); bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD; @@ -352,8 +371,9 @@ void entities::TextPayload::render(RenderArgs* args) { return; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float scale = textRenderable->_lineHeight / textRenderer->getFontSize(); transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z)); @@ -361,9 +381,8 @@ void entities::TextPayload::render(RenderArgs* args) { batch.setModelTransform(transform); glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin)); - textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale, - textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect, - textRenderable->_alignment, textRenderable->_unlit, forward); + textRenderer->draw(batch, textRenderable->_font, { textRenderable->_text, textColor, effectColor, { textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale }, + bounds / scale, scale, textRenderable->_effectThickness, textRenderable->_effect, textRenderable->_alignment, textRenderable->_unlit, forward, mirror }); } namespace render { @@ -399,4 +418,11 @@ template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Poi return false; } +template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) { + if (payload) { + return payload->computeMirrorView(viewFrustum); + } + return Item::INVALID_ITEM_ID; +} + } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index 8a18554dea..f48bb8085f 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -101,6 +101,7 @@ public: ShapeKey getShapeKey() const; void render(RenderArgs* args); bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; + ItemID computeMirrorView(ViewFrustum& viewFrustum) const; protected: QUuid _entityID; @@ -117,6 +118,7 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload); template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set& containingZones); + template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum); } #endif // hifi_RenderableTextEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index c98bfe7f63..77f6fe99f6 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -320,8 +320,9 @@ void WebEntityRenderer::doRender(RenderArgs* args) { batch.setResourceTexture(0, _texture); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); // Turn off jitter for these entities diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b63f0d91ab..34217d5bdf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -105,6 +105,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_RENDER_WITH_ZONES; requestedProperties += PROP_BILLBOARD_MODE; requestedProperties += _grabProperties.getEntityProperties(params); + requestedProperties += PROP_MIRROR_MODE; + requestedProperties += PROP_PORTAL_EXIT_ID; // Physics requestedProperties += PROP_DENSITY; @@ -305,6 +307,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); }); + APPEND_ENTITY_PROPERTY(PROP_MIRROR_MODE, (uint32_t)getMirrorMode()); + APPEND_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, getPortalExitID()); // Physics APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); @@ -881,6 +885,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += bytesFromGrab; dataAt += bytesFromGrab; }); + READ_ENTITY_PROPERTY(PROP_MIRROR_MODE, MirrorMode, setMirrorMode); + READ_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, QUuid, setPortalExitID); READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); { @@ -1361,6 +1367,8 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire withReadLock([&] { _grabProperties.getProperties(properties); }); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(mirrorMode, getMirrorMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(portalExitID, getPortalExitID); // Physics COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); @@ -1499,6 +1507,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { bool grabPropertiesChanged = _grabProperties.setProperties(properties); somethingChanged |= grabPropertiesChanged; }); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(mirrorMode, setMirrorMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(portalExitID, setPortalExitID); // Physics SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, setDensity); @@ -3553,3 +3563,29 @@ void EntityItem::setBillboardMode(BillboardMode value) { _billboardMode = value; }); } + +MirrorMode EntityItem::getMirrorMode() const { + return resultWithReadLock([&] { + return _mirrorMode; + }); +} + +void EntityItem::setMirrorMode(MirrorMode value) { + withWriteLock([&] { + _needsRenderUpdate |= _mirrorMode != value; + _mirrorMode = value; + }); +} + +QUuid EntityItem::getPortalExitID() const { + return resultWithReadLock([&] { + return _portalExitID; + }); +} + +void EntityItem::setPortalExitID(const QUuid& value) { + withWriteLock([&] { + _needsRenderUpdate |= _portalExitID != value; + _portalExitID = value; + }); +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ec84b0ccb2..32f6dccf37 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -559,6 +559,12 @@ public: BillboardMode getBillboardMode() const; virtual bool getRotateForPicking() const { return false; } + MirrorMode getMirrorMode() const; + void setMirrorMode(MirrorMode value); + + QUuid getPortalExitID() const; + void setPortalExitID(const QUuid& value); + signals: void spaceUpdate(std::pair data); @@ -740,6 +746,9 @@ protected: bool _cullWithParent { false }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; + mutable bool _needsRenderUpdate { false }; }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f543169401..4d21e040f5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -424,6 +424,23 @@ void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHost } } +inline void addMirrorMode(QHash& lookup, MirrorMode mirrorMode) { lookup[MirrorModeHelpers::getNameForMirrorMode(mirrorMode)] = mirrorMode; } +const QHash stringToMirrorModeLookup = [] { + QHash toReturn; + addMirrorMode(toReturn, MirrorMode::NONE); + addMirrorMode(toReturn, MirrorMode::MIRROR); + addMirrorMode(toReturn, MirrorMode::PORTAL); + return toReturn; +}(); +QString EntityItemProperties::getMirrorModeAsString() const { return MirrorModeHelpers::getNameForMirrorMode(_mirrorMode); } +void EntityItemProperties::setMirrorModeFromString(const QString& mirrorMode) { + auto mirrorModeItr = stringToMirrorModeLookup.find(mirrorMode.toLower()); + if (mirrorModeItr != stringToMirrorModeLookup.end()) { + _mirrorMode = mirrorModeItr.value(); + _mirrorModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -455,6 +472,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones); CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode); changedProperties += _grab.getChangedProperties(); + CHECK_PROPERTY_CHANGE(PROP_MIRROR_MODE, mirrorMode); + CHECK_PROPERTY_CHANGE(PROP_PORTAL_EXIT_ID, portalExitID); // Physics CHECK_PROPERTY_CHANGE(PROP_DENSITY, density); @@ -825,6 +844,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * * @property {Entities.Grab} grab - The entity's grab-related properties. * + * @property {MirrorMode} mirrorMode="none" - If this entity should render as a mirror (reflecting the view of the camera), + * a portal (reflecting the view through its portalExitID), or normally. + * @property {Uuid} portalExitID=Uuid.NULL - The ID of the entity that should act as the portal exit if the mirrorMode + * is set to portal. + * * @comment The different entity types have additional properties as follows: * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} * @see {@link Entities.EntityProperties-Gizmo|EntityProperties-Gizmo} @@ -1616,6 +1640,8 @@ ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool s COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MIRROR_MODE, mirrorMode, getMirrorModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PORTAL_EXIT_ID, portalExitID); // Physics COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density); @@ -2032,6 +2058,8 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool h COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode); _grab.copyFromScriptValue(object, namesSet, _defaultSettings); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(mirrorMode, MirrorMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE(portalExitID, QUuid, setPortalExitID); // Physics COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity); @@ -2318,6 +2346,8 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(renderWithZones); COPY_PROPERTY_IF_CHANGED(billboardMode); _grab.merge(other._grab); + COPY_PROPERTY_IF_CHANGED(mirrorMode); + COPY_PROPERTY_IF_CHANGED(portalExitID); // Physics COPY_PROPERTY_IF_CHANGED(density); @@ -2627,6 +2657,8 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, EquippableIndicatorOffset, equippableIndicatorOffset); } + ADD_PROPERTY_TO_MAP(PROP_MIRROR_MODE, MirrorMode, mirrorMode, MirrorMode); + ADD_PROPERTY_TO_MAP(PROP_PORTAL_EXIT_ID, PortalExitID, portalExitID, QUuid); // Physics ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_DENSITY, Density, density, float, @@ -3090,6 +3122,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticGrab.setProperties(properties); _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_MIRROR_MODE, (uint32_t)properties.getMirrorMode()); + APPEND_ENTITY_PROPERTY(PROP_PORTAL_EXIT_ID, properties.getPortalExitID()); // Physics APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity()); @@ -3568,6 +3602,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MIRROR_MODE, MirrorMode, setMirrorMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PORTAL_EXIT_ID, QUuid, setPortalExitID); // Physics READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity); @@ -3960,6 +3996,8 @@ void EntityItemProperties::markAllChanged() { _renderWithZonesChanged = true; _billboardModeChanged = true; _grab.markAllChanged(); + _mirrorModeChanged = true; + _portalExitIDChanged = true; // Physics _densityChanged = true; @@ -4359,6 +4397,12 @@ QList EntityItemProperties::listChangedProperties() { out += "billboardMode"; } getGrab().listChangedProperties(out); + if (mirrorModeChanged()) { + out += "mirrorMode"; + } + if (portalExitIDChanged()) { + out += "portalExitID"; + } // Physics if (densityChanged()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 283d14c4cc..3e07a75616 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -70,6 +70,7 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" +#include "MirrorMode.h" class ScriptEngine; @@ -204,6 +205,8 @@ public: DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector, QVector()); DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE); DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); + DEFINE_PROPERTY_REF_ENUM(PROP_MIRROR_MODE, MirrorMode, mirrorMode, MirrorMode, MirrorMode::NONE); + DEFINE_PROPERTY_REF(PROP_PORTAL_EXIT_ID, PortalExitID, portalExitID, QUuid, UNKNOWN_ENTITY_ID); // Physics DEFINE_PROPERTY(PROP_DENSITY, Density, density, float, ENTITY_ITEM_DEFAULT_DENSITY); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index e0b5a04094..c0cbb3f9a1 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -60,6 +60,8 @@ enum EntityPropertyList { PROP_GRAB_EQUIPPABLE_INDICATOR_URL, PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, + PROP_MIRROR_MODE, + PROP_PORTAL_EXIT_ID, // Physics PROP_DENSITY, diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index af39458f17..c0116274ee 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -81,6 +81,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_disableContextViewCorrection), (&::gpu::gl::GLBackend::do_restoreContextViewCorrection), + (&::gpu::gl::GLBackend::do_setContextMirrorViewCorrection), (&::gpu::gl::GLBackend::do_disableContextStereo), (&::gpu::gl::GLBackend::do_restoreContextStereo), @@ -348,6 +349,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) { case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: case Batch::COMMAND_setProjectionJitter: + case Batch::COMMAND_setContextMirrorViewCorrection: { CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); @@ -413,6 +415,7 @@ void GLBackend::renderPassDraw(const Batch& batch) { case Batch::COMMAND_setProjectionJitter: case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setDepthRangeTransform: + case Batch::COMMAND_setContextMirrorViewCorrection: { PROFILE_RANGE(render_gpu_gl_detail, "transform"); CommandCall call = _commandCalls[(*command)]; @@ -619,6 +622,16 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param _transform._viewCorrectionEnabled = true; } +void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { + bool prevMirrorViewCorrection = _transform._mirrorViewCorrection; + _transform._mirrorViewCorrection = batch._params[paramOffset]._uint != 0; + + if (_transform._correction.correction != glm::mat4()) { + setCameraCorrection(_transform._mirrorViewCorrection ? _transform._flippedCorrection : _transform._unflippedCorrection, _transform._correction.prevView, false); + _transform._invalidView = true; + } +} + void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { } @@ -997,15 +1010,29 @@ void GLBackend::recycle() const { _textureManagement._transferEngine->manageMemory(); } -void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) { +void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset) { auto invCorrection = glm::inverse(correction); auto invPrevView = glm::inverse(prevRenderView); _transform._correction.prevView = (reset ? Mat4() : prevRenderView); _transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView); _transform._correction.correction = correction; _transform._correction.correctionInverse = invCorrection; - _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); - _pipeline._cameraCorrectionBuffer._buffer->flush(); + + if (!_inRenderTransferPass) { + _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); + _pipeline._cameraCorrectionBuffer._buffer->flush(); + } + + if (primary) { + _transform._unflippedCorrection = _transform._correction.correction; + quat flippedRotation = glm::quat_cast(_transform._unflippedCorrection); + flippedRotation.y *= -1.0f; + flippedRotation.z *= -1.0f; + vec3 flippedTranslation = _transform._unflippedCorrection[3]; + flippedTranslation.x *= -1.0f; + _transform._flippedCorrection = glm::translate(glm::mat4_cast(flippedRotation), flippedTranslation); + _transform._mirrorViewCorrection = false; + } } void GLBackend::syncProgram(const gpu::ShaderPointer& program) { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 2947649ce7..5545858877 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -121,7 +121,7 @@ public: // Shutdown rendering and persist any required resources void shutdown() override; - void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) override; + void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) override; void render(const Batch& batch) final override; // This call synchronize the Full Backend cache with the current GLState @@ -211,6 +211,7 @@ public: virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final; + virtual void do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final; @@ -433,6 +434,9 @@ protected: Transform _view; CameraCorrection _correction; bool _viewCorrectionEnabled{ true }; + mat4 _unflippedCorrection; + mat4 _flippedCorrection; + bool _mirrorViewCorrection{ false }; Mat4 _projection; Vec4i _viewport{ 0, 0, 1, 1 }; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index e6217cc600..a41f586d74 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -464,6 +464,12 @@ void Batch::restoreContextViewCorrection() { ADD_COMMAND(restoreContextViewCorrection); } +void Batch::setContextMirrorViewCorrection(bool shouldMirror) { + ADD_COMMAND(setContextMirrorViewCorrection); + uint mirrorFlag = shouldMirror ? 1 : 0; + _params.emplace_back(mirrorFlag); +} + void Batch::disableContextStereo() { ADD_COMMAND(disableContextStereo); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 0a438ea148..f89dd3ea90 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -239,6 +239,7 @@ public: void disableContextViewCorrection(); void restoreContextViewCorrection(); + void setContextMirrorViewCorrection(bool shouldMirror); void disableContextStereo(); void restoreContextStereo(); @@ -340,6 +341,7 @@ public: COMMAND_disableContextViewCorrection, COMMAND_restoreContextViewCorrection, + COMMAND_setContextMirrorViewCorrection, COMMAND_disableContextStereo, COMMAND_restoreContextStereo, diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 1946f447f8..ebc81f14e9 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -66,7 +66,7 @@ public: virtual void syncProgram(const gpu::ShaderPointer& program) = 0; virtual void recycle() const = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) {} + virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) {} virtual bool supportedTextureFormat(const gpu::Element& format) = 0; diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index 1a98d0decd..2d88158afb 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -181,6 +181,7 @@ constexpr const char* COMMAND_NAMES[] = { "disableContextViewCorrection", "restoreContextViewCorrection", + "setContextMirrorViewCorrection", "disableContextStereo", "restoreContextStereo", diff --git a/libraries/graphics/src/graphics/ShaderConstants.h b/libraries/graphics/src/graphics/ShaderConstants.h index 3a614d26cd..8fd0df31f0 100644 --- a/libraries/graphics/src/graphics/ShaderConstants.h +++ b/libraries/graphics/src/graphics/ShaderConstants.h @@ -27,6 +27,7 @@ #define GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS 4 #define GRAPHICS_TEXTURE_MATERIAL_OCCLUSION 5 #define GRAPHICS_TEXTURE_MATERIAL_SCATTERING 6 +#define GRAPHICS_TEXTURE_MATERIAL_MIRROR 1 // Mirrors use albedo textures, but nothing else // Make sure these match the ones in render-utils/ShaderConstants.h #define GRAPHICS_TEXTURE_SKYBOX 11 @@ -59,6 +60,7 @@ enum Texture { MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS, MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION, MaterialScattering = GRAPHICS_TEXTURE_MATERIAL_SCATTERING, + MaterialMirror = GRAPHICS_TEXTURE_MATERIAL_MIRROR, Skybox = GRAPHICS_TEXTURE_SKYBOX }; } // namespace texture diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3badfdf418..51739e0f77 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -290,6 +290,7 @@ enum class EntityVersion : PacketVersion { UserAgent, AllBillboardMode, TextAlignment, + Mirror, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 583f090942..30b826aaec 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -42,6 +42,7 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" +#include "MirrorMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -280,6 +281,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, GizmoType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } 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, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index dc1ffb7b67..78652bfb09 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -71,14 +71,15 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { + bool useCauterizedMesh = _enableCauterization && (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && + mirrorDepth == 0; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer); } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, transform, renderMode); + ModelMeshPartPayload::bindTransform(batch, transform, renderMode, mirrorDepth); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 430f41fc08..cef7b6d9b5 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ public: void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning); - void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 8d7fc345ac..3eb5924d19 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -286,6 +286,7 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); + outputs.edit2() = _deferredFramebuffer->getDeferredFramebuffer(); gpu::doInBatch("PrepareDeferred::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 4779376410..058e0a4cbf 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -78,8 +78,8 @@ class PrepareDeferred { public: // Inputs: primaryFramebuffer and lightingModel using Inputs = render::VaryingSet2 ; - // Output: DeferredFramebuffer, LightingFramebuffer - using Outputs = render::VaryingSet2; + // Output: DeferredFramebuffer, LightingFramebuffer, the framebuffer to be used for mirrors (same as DeferredFramebuffer) + using Outputs = render::VaryingSet3; using JobModel = render::Job::ModelIO; diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 5a8b09b018..b4aced626d 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -506,8 +506,9 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren const auto jitter = inputs.getN(4); // Prepare the ShapePipeline - auto shapePlumber = std::make_shared(); - { + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); @@ -515,7 +516,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - } + }); auto sharedParameters = std::make_shared(); const auto highlightSelectionNames = task.addJob("SelectionToHighlight", sharedParameters); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8ba5be54e6..9adeb39e7c 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -12,6 +12,7 @@ #include "MeshPartPayload.h" #include +#include #include #include #include @@ -188,7 +189,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { if (_clusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); } @@ -220,6 +221,10 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withSubMetaCulled(); } + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + builder.withMirror(); + } + _itemKey = builder.build(); } @@ -299,8 +304,9 @@ Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const { auto worldBound = _adjustedLocalBound; auto parentTransform = _parentTransform; if (args) { + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); } worldBound.transform(parentTransform); return worldBound; @@ -313,18 +319,19 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) { + if (!args || (_cauterized && args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && args->_mirrorDepth == 0)) { return; } gpu::Batch& batch = *(args->_batch); Transform transform = _parentTransform; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform modelTransform = transform.worldTransform(_localTransform); - bindTransform(batch, modelTransform, args->_renderMode); + bindTransform(batch, modelTransform, args->_renderMode, args->_mirrorDepth); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); @@ -346,7 +353,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned())); batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); - } else { + } else if (!_itemKey.isMirror()) { // apply material properties if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; @@ -377,6 +384,12 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set& blendshapeBuffers, const QVector& blendedMeshSizes) { if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); @@ -426,4 +439,11 @@ template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin } return false; } + +template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum) { + if (payload) { + return payload->computeMirrorView(viewFrustum); + } + return Item::INVALID_ITEM_ID; +} } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 1a3a898582..7e331a9497 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -37,7 +37,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch); - virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const; + virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const; void drawCall(gpu::Batch& batch) const; void updateKey(const render::ItemKey& key); @@ -58,7 +58,10 @@ public: void setCullWithParent(bool value) { _cullWithParent = value; } void setRenderWithZones(const QVector& renderWithZones) { _renderWithZones = renderWithZones; } void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; } + void setMirrorMode(MirrorMode mirrorMode) { _mirrorMode = mirrorMode; } + void setPortalExitID(const QUuid& portalExitID) { _portalExitID = portalExitID; } bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; + render::ItemID computeMirrorView(ViewFrustum& viewFrustum) const; void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } @@ -93,6 +96,8 @@ private: bool _cullWithParent { false }; QVector _renderWithZones; BillboardMode _billboardMode { BillboardMode::NONE }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; uint64_t _created; Transform _localTransform; @@ -107,6 +112,8 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set& containingZones); + template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum); + } #endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index eabcabc7e5..7d622ab489 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -232,6 +232,8 @@ void Model::updateRenderItems() { auto renderWithZones = self->getRenderWithZones(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool cauterized = self->isCauterized(); + auto mirrorMode = self->getMirrorMode(); + const QUuid& portalExitID = self->getPortalExitID(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -246,7 +248,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags, - cauterized, renderWithZones](ModelMeshPartPayload& data) { + cauterized, renderWithZones, mirrorMode, portalExitID](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); @@ -260,6 +262,8 @@ void Model::updateRenderItems() { data.setCauterized(cauterized); data.setRenderWithZones(renderWithZones); data.setBillboardMode(billboardMode); + data.setMirrorMode(mirrorMode); + data.setPortalExitID(portalExitID); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); @@ -1065,6 +1069,46 @@ void Model::setRenderWithZones(const QVector& renderWithZones, const rend } } +void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene) { + if (_mirrorMode != mirrorMode) { + _mirrorMode = mirrorMode; + if (!scene) { + _needsFixupInScene = true; + return; + } + + render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; + for (auto item : _modelMeshRenderItemIDs) { + transaction.updateItem(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) { + data.setMirrorMode(mirrorMode); + data.updateKey(renderItemsKey); + }); + } + scene->enqueueTransaction(transaction); + } +} + +void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene) { + if (_portalExitID != portalExitID) { + _portalExitID = portalExitID; + if (!scene) { + _needsFixupInScene = true; + return; + } + + render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; + for (auto item : _modelMeshRenderItemIDs) { + transaction.updateItem(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) { + data.setPortalExitID(portalExitID); + data.updateKey(renderItemsKey); + }); + } + scene->enqueueTransaction(transaction); + } +} + const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { return _renderItemKeyGlobalFlags; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 17b7df9b23..63a96f7253 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -41,6 +41,7 @@ #include "Rig.h" #include "PrimitiveMode.h" #include "BillboardMode.h" +#include "MirrorMode.h" // Use dual quaternion skinning! // Must match define in Skinning.slh @@ -131,6 +132,12 @@ public: void setRenderWithZones(const QVector& renderWithZones, const render::ScenePointer& scene = nullptr); const QVector& getRenderWithZones() const { return _renderWithZones; } + void setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene = nullptr); + MirrorMode getMirrorMode() const { return _mirrorMode; } + + void setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene = nullptr); + const QUuid& getPortalExitID() const { return _portalExitID; } + // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; @@ -503,6 +510,8 @@ protected: bool _cauterized { false }; bool _cullWithParent { false }; QVector _renderWithZones; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; bool shouldInvalidatePayloadShapeKey(int meshIndex); diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 7cf7f1129f..a509ede437 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -13,7 +13,10 @@ #include "render-utils/ShaderConstants.h" #include "DeferredLightingEffect.h" +#include "FadeEffect.h" #include "RenderUtilsLogging.h" +#include "RenderViewTask.h" +#include "StencilMaskPass.h" namespace ru { using render_utils::slot::texture::Texture; @@ -25,9 +28,11 @@ namespace gr { using graphics::slot::buffer::Buffer; } +using RenderArgsPointer = std::shared_ptr; using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); +extern void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void BeginGPURangeTimer::run(const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) { timer = _gpuTimer; @@ -45,10 +50,14 @@ void EndGPURangeTimer::run(const render::RenderContextPointer& renderContext, co config->setGPUBatchRunTime(timer->getGPUAverage(), timer->getBatchAverage()); } +render::ShapePlumberPointer DrawLayered3D::_shapePlumber = std::make_shared(); + DrawLayered3D::DrawLayered3D(bool opaque) : - _shapePlumber(std::make_shared()), _opaquePass(opaque) { - initForwardPipelines(*_shapePlumber); + static std::once_flag once; + std::call_once(once, [] { + initForwardPipelines(*_shapePlumber); + }); } void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& inputs) { @@ -262,3 +271,149 @@ void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, } } +class SetupMirrorTask { +public: + using Input = RenderMirrorTask::Inputs; + using Outputs = render::VaryingSet4; + using JobModel = render::Job::ModelIO; + + SetupMirrorTask(size_t mirrorIndex, size_t depth) : _mirrorIndex(mirrorIndex), _depth(depth) {} + + void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) { + auto args = renderContext->args; + auto items = inputs.get0(); + + if (items.empty() || _mirrorIndex > items.size() - 1) { + renderContext->taskFlow.abortTask(); + return; + } + + auto inputFramebuffer = inputs.get1(); + if (!_mirrorFramebuffer || _mirrorFramebuffer->getWidth() != inputFramebuffer->getWidth() || _mirrorFramebuffer->getHeight() != inputFramebuffer->getHeight()) { + _mirrorFramebuffer.reset(gpu::Framebuffer::create("mirror" + _mirrorIndex, gpu::Element::COLOR_SRGBA_32, inputFramebuffer->getWidth(), inputFramebuffer->getHeight())); + } + + render::ItemBound mirror = items[_mirrorIndex]; + + _cachedArgsPointer->_renderMode = args->_renderMode; + _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; + _cachedArgsPointer->_ignoreItem = args->_ignoreItem; + _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; + _cachedArgsPointer->_numMirrorFlips = args->_numMirrorFlips; + + ViewFrustum srcViewFrustum = args->getViewFrustum(); + ItemID portalExitID = args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); + + args->_blitFramebuffer = _mirrorFramebuffer; + args->_ignoreItem = portalExitID != Item::INVALID_ITEM_ID ? portalExitID : mirror.id; + args->_mirrorDepth = _depth; + args->_numMirrorFlips += portalExitID != Item::INVALID_ITEM_ID ? 0 : 1; + + gpu::doInBatch("SetupMirrorTask::run", args->_context, [&](gpu::Batch& batch) { + bool shouldMirror = args->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setContextMirrorViewCorrection(shouldMirror); + }); + + // Without calculating the bound planes, the mirror will use the same culling frustum as the main camera, + // which is not what we want here. + srcViewFrustum.calculate(); + args->pushViewFrustum(srcViewFrustum); + + outputs.edit0() = mirror; + outputs.edit1() = inputFramebuffer; + outputs.edit2() = _cachedArgsPointer; + outputs.edit3() = inputs.get2(); + } + +protected: + gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; + RenderArgsPointer _cachedArgsPointer { std::make_shared() }; + size_t _mirrorIndex; + size_t _depth; + +}; + +class DrawMirrorTask { +public: + using Inputs = SetupMirrorTask::Outputs; + using JobModel = render::Job::ModelI; + + DrawMirrorTask() { + static std::once_flag once; + std::call_once(once, [this] { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + PrepareStencil::testMaskDrawShape(*state); + + auto fadeEffect = DependencyManager::get(); + initMirrorPipelines(*_forwardPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), true); + initMirrorPipelines(*_deferredPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), false); + }); + } + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto args = renderContext->args; + auto mirror = inputs.get0(); + auto framebuffer = inputs.get1(); + auto cachedArgs = inputs.get2(); + auto jitter = inputs.get3(); + + if (cachedArgs) { + args->_renderMode = cachedArgs->_renderMode; + } + args->popViewFrustum(); + + gpu::doInBatch("DrawMirrorTask::run", args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + if (cachedArgs) { + bool shouldMirror = cachedArgs->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setContextMirrorViewCorrection(shouldMirror); + } + + batch.setFramebuffer(framebuffer); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setProjectionJitter(jitter.x, jitter.y); + batch.setViewTransform(viewMat); + + batch.setResourceTexture(gr::Texture::MaterialMirror, args->_blitFramebuffer->getRenderBuffer(0)); + + renderShapes(renderContext, args->_renderMethod == render::Args::RenderMethod::FORWARD ? _forwardPipelines : _deferredPipelines, { mirror }); + + args->_batch = nullptr; + }); + + if (cachedArgs) { + // Restore the blit framebuffer after we've sampled from it + args->_blitFramebuffer = cachedArgs->_blitFramebuffer; + args->_ignoreItem = cachedArgs->_ignoreItem; + args->_mirrorDepth = cachedArgs->_mirrorDepth; + args->_numMirrorFlips = cachedArgs->_numMirrorFlips; + } + } + +private: + static ShapePlumberPointer _forwardPipelines; + static ShapePlumberPointer _deferredPipelines; +}; + +ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared(); +ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared(); + + void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { + size_t nextDepth = depth + 1; + const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex, nextDepth); + + task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, nextDepth); + + task.addJob("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); + } diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index 15d6ff9895..cada3cb6ea 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -10,6 +10,8 @@ #define hifi_RenderCommonTask_h #include +#include + #include "LightStage.h" #include "HazeStage.h" #include "LightingModel.h" @@ -71,7 +73,7 @@ public: void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: - render::ShapePlumberPointer _shapePlumber; + static render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config bool _opaquePass { true }; }; @@ -152,4 +154,17 @@ protected: render::Args::RenderMethod _method; }; +class RenderMirrorTask { +public: + using Inputs = render::VaryingSet3; + using JobModel = render::Task::ModelI; + + RenderMirrorTask() {} + + void build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth); + + static const size_t MAX_MIRROR_DEPTH { 3 }; + static const size_t MAX_MIRRORS_PER_LEVEL { 3 }; +}; + #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c506f22bc7..fd10452dfa 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -100,11 +100,14 @@ void RenderDeferredTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { - auto fadeEffect = DependencyManager::get(); +void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { + static auto fadeEffect = DependencyManager::get(); // Prepare the ShapePipelines - ShapePlumberPointer shapePlumber = std::make_shared(); - initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { + initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + }); const auto& inputs = input.get(); @@ -116,6 +119,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Extract opaques / transparents / lights / metas / layered / background const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -139,7 +143,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Shadow Stage Frame const auto shadowFrame = shadowTaskOutputs[1]; - fadeEffect->build(task, opaques); const auto jitter = task.addJob("JitterCam"); @@ -154,6 +157,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); + const auto mirrorTargetFramebuffer = prepareDeferredOutputs.getN(2); // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", scaledPrimaryFramebuffer); @@ -162,6 +166,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); + if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, mirrorTargetFramebuffer, jitter).asVarying(); + for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { + task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); + } + } + // Opaque all rendered // Linear Depth Pass @@ -234,7 +245,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); // 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 @@ -398,8 +409,12 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatusJob - auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; - auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); + static gpu::TexturePointer statusIconMap; + static std::once_flag once; + std::call_once(once, [] { + auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; + statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); + }); const auto drawStatusInputs = DrawStatus::Input(opaques, jitter).asVarying(); task.addJob("DrawStatus", drawStatusInputs, DrawStatus(statusIconMap)); } @@ -407,8 +422,6 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input const auto debugZoneInputs = DebugZoneLighting::Inputs(deferredFrameTransform, lightFrame, backgroundFrame).asVarying(); task.addJob("DrawZoneStack", debugZoneInputs); } - - } gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 969094488e..5fc9580981 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -144,7 +144,7 @@ public: RenderDeferredTask(); void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output); + void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); private: }; diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index e34db755b7..722ba2248c 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -34,6 +34,8 @@ #include "RenderCommonTask.h" #include "RenderHUDLayerTask.h" +#include "RenderViewTask.h" + namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; @@ -66,13 +68,16 @@ void RenderForwardTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { +void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { task.addJob("SetRenderMethodTask", render::Args::FORWARD); // Prepare the ShapePipelines auto fadeEffect = DependencyManager::get(); - ShapePlumberPointer shapePlumber = std::make_shared(); - initForwardPipelines(*shapePlumber); + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { + initForwardPipelines(*shapePlumber); + }); // Unpack inputs const auto& inputs = input.get(); @@ -86,6 +91,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; const auto& metas = items[RenderFetchCullSortTask::META]; + const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -107,7 +113,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // First job, alter faded fadeEffect->build(task, opaques); - // GPU jobs: Start preparing the main framebuffer const auto scaledPrimaryFramebuffer = task.addJob("PreparePrimaryBufferForward"); @@ -125,6 +130,16 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel, hazeFrame).asVarying(); task.addJob("DrawOpaques", opaqueInputs, shapePlumber, true); + const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); +#ifndef Q_OS_ANDROID + if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, scaledPrimaryFramebuffer, nullJitter).asVarying(); + for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { + task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); + } + } +#endif + // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job const auto backgroundInputs = DrawBackgroundStage::Inputs(lightingModel, backgroundFrame, hazeFrame).asVarying(); task.addJob("DrawBackgroundForward", backgroundInputs); @@ -134,7 +149,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("DrawTransparents", transparentInputs, shapePlumber, false); // Layered - const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, hazeFrame, nullJitter).asVarying(); const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, hazeFrame, nullJitter).asVarying(); task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); @@ -159,7 +173,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto destFramebuffer = static_cast(nullptr); const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); // HUD Layer const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying(); task.addJob("RenderHUDLayer", renderHUDLayerInputs); diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 6833e42449..de3a6dd205 100644 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -36,7 +36,7 @@ public: RenderForwardTask() {} void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output); + void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); }; diff --git a/libraries/render-utils/src/RenderHUDLayerTask.cpp b/libraries/render-utils/src/RenderHUDLayerTask.cpp index 743e59eebc..8fee3d57bc 100644 --- a/libraries/render-utils/src/RenderHUDLayerTask.cpp +++ b/libraries/render-utils/src/RenderHUDLayerTask.cpp @@ -16,8 +16,8 @@ void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::Fra assert(renderContext->args); assert(renderContext->args->_context); - // We do not want to render HUD elements in secondary camera - if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { + // We do not want to render HUD elements in secondary camera or mirrors + if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE || renderContext->args->_mirrorDepth > 0) { return; } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index ed9fb326c4..b5a88b0ba9 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -42,6 +42,7 @@ namespace gr { void initDeferredPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); void initForwardPipelines(ShapePlumber& plumber); void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); +void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void addPlumberPipeline(ShapePlumber& plumber, const ShapeKey& key, int programId, @@ -368,6 +369,45 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, con gpu::Shader::createProgram(model_shadow_fade_deformeddq), state, extraBatchSetter, itemSetter); } +void initMirrorPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& extraBatchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward) { + using namespace shader::render_utils::program; + + if (forward) { + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward), state); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward_deformed), state); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward_deformeddq), state); + } else { + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade), state, extraBatchSetter, itemSetter); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_deformed), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade_deformed), state, extraBatchSetter, itemSetter); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_deformeddq), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade_deformeddq), state, extraBatchSetter, itemSetter); + } +} + bool RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures) { graphics::MultiMaterial multiMaterial; multiMaterial.push(graphics::MaterialLayer(material, 0)); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index dbfa23a143..9fabad5fd0 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -46,15 +46,16 @@ void RenderShadowTask::configure(const Config& configuration) { void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cameraCullFunctor, uint8_t tagBits, uint8_t tagMask) { // Prepare the ShapePipeline - ShapePlumberPointer shapePlumber = std::make_shared(); - { + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - } + }); const auto setupOutput = task.addJob("ShadowSetup", input); const auto queryResolution = setupOutput.getN(1); const auto shadowFrame = setupOutput.getN(3); diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index 93a3ff2d67..b9320b6ad3 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -15,7 +15,7 @@ #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { +void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { task.addJob("SetRenderMethodTask", render::Args::DEFERRED); const auto items = input.getN(0); @@ -28,16 +28,16 @@ void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& const auto shadowTaskOut = task.addJob("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask); const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); - task.addJob("RenderDeferredTask", renderDeferredInput); + task.addJob("RenderDeferredTask", renderDeferredInput, cullFunctor, depth); } -void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { - task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask); +void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { + task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask, depth); - task.addBranch("RenderForwardTask", 1, input); + task.addBranch("RenderForwardTask", 1, input, cullFunctor, depth); } -void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { +void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); // Issue the lighting model, aka the big global settings for the view @@ -48,7 +48,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: #ifndef Q_OS_ANDROID const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); - task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask); + task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask, depth); #else const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("RenderForwardTask", renderInput); diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index cdb56a2189..139d00125e 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -24,7 +24,7 @@ public: RenderShadowsAndDeferredTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); }; @@ -36,7 +36,7 @@ public: DeferredForwardSwitchJob() {} void configure(const render::SwitchConfig& config) {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); }; @@ -47,7 +47,7 @@ public: RenderViewTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00, size_t depth = 0); }; diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 76d8374fb7..8ab1b8e0e9 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -40,21 +40,18 @@ float TextRenderer3D::getFontSize() const { return 0.0f; } -void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, - const QString& str, const glm::vec4& color, bool unlit, bool forward) { +void TextRenderer3D::draw(gpu::Batch& batch, const Font::DrawProps& props) { if (_font) { - _font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, TextAlignment::LEFT, { x, y }, bounds, 1.0f, unlit, forward); + _font->drawString(batch, _drawInfo, props); } } -void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, - const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, - float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward) { +void TextRenderer3D::draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props) { if (font != _family) { _family = font; _font = Font::load(_family); } if (_font) { - _font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, alignment, { x, y }, bounds, scale, unlit, forward); + _font->drawString(batch, _drawInfo, props); } } \ No newline at end of file diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index edccf1429c..9db93e9dcc 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -26,12 +26,9 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const; // Pixel size - - void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, - const QString& str, const glm::vec4& color, bool unlit, bool forward); - void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, - const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, - float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward); + + void draw(gpu::Batch& batch, const Font::DrawProps& props); + void draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props); private: TextRenderer3D(const char* family); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 10312f7f2e..1ea9deb1fa 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -25,9 +25,10 @@ using namespace shader::render_utils::program; gpu::PipelinePointer ToneMapAndResample::_pipeline; gpu::PipelinePointer ToneMapAndResample::_mirrorPipeline; -ToneMapAndResample::ToneMapAndResample() { +ToneMapAndResample::ToneMapAndResample(size_t depth) { Parameters parameters; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); + _depth = depth; } void ToneMapAndResample::init() { @@ -95,7 +96,8 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.h b/libraries/render-utils/src/ToneMapAndResampleTask.h index 1c7ef2cf48..3a812cf445 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.h +++ b/libraries/render-utils/src/ToneMapAndResampleTask.h @@ -49,11 +49,9 @@ signals: class ToneMapAndResample { public: - ToneMapAndResample(); + ToneMapAndResample(size_t depth); virtual ~ToneMapAndResample() {} - void render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, gpu::FramebufferPointer& destinationBuffer); - void setExposure(float exposure); float getExposure() const { return _parametersBuffer.get()._exposure; } @@ -75,7 +73,8 @@ protected: gpu::FramebufferPointer _destinationFrameBuffer; - float _factor{ 2.0f }; + float _factor { 2.0f }; + size_t _depth { 0 }; gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index 98abc29d8c..2f80fbde99 100644 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -36,7 +36,15 @@ <@include DeferredBufferWrite.slh@> <@endif@> <@else@> - layout(location=0) out vec4 _fragColor0; + <@if HIFI_USE_MIRROR@> + <@if HIFI_USE_FORWARD@> + layout(location=0) out vec4 _fragColor0; + <@else@> + <@include DeferredBufferWrite.slh@> + <@endif@> + <@else@> + layout(location=0) out vec4 _fragColor0; + <@endif@> <@endif@> <@if HIFI_USE_UNLIT@> @@ -45,6 +53,9 @@ <@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@> <$declareMaterialTextures(ALBEDO)$> + <@if HIFI_USE_MIRROR@> + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; + <@endif@> <@else@> <@if not HIFI_USE_LIGHTMAP@> <@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@> @@ -124,7 +135,14 @@ void main(void) { <@endif@> <@endif@> - <@if HIFI_USE_SHADOW@> + <@if HIFI_USE_MIRROR@> + vec3 mirrorColor = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; + <@if HIFI_USE_FORWARD@> + _fragColor0 = vec4(mirrorColor, 1.0); + <@else@> + packDeferredFragmentUnlit(vec3(1.0, 0.0, 0.0), 1.0, mirrorColor); + <@endif@> + <@elif HIFI_USE_SHADOW@> _fragColor0 = vec4(1.0); <@elif HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(albedo * isUnlitEnabled(), opacity); diff --git a/libraries/render-utils/src/render-utils/model.slp b/libraries/render-utils/src/render-utils/model.slp index b63ec898eb..a3c28631e9 100644 --- a/libraries/render-utils/src/render-utils/model.slp +++ b/libraries/render-utils/src/render-utils/model.slp @@ -1 +1 @@ -DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file +DEFINES (normalmap translucent:f unlit:f/lightmap:f)/(shadow mirror:f) fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file diff --git a/libraries/render-utils/src/render-utils/sdf_text3D.slp b/libraries/render-utils/src/render-utils/sdf_text3D.slp index 118135d099..f3f9af59aa 100644 --- a/libraries/render-utils/src/render-utils/sdf_text3D.slp +++ b/libraries/render-utils/src/render-utils/sdf_text3D.slp @@ -1 +1 @@ -DEFINES (translucent unlit:f)/forward \ No newline at end of file +DEFINES (translucent unlit:f)/forward mirror:f \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index c5bed1ecab..bf9bb0babd 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -41,6 +41,12 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; #define _texCoord1 _texCoord01.zw layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reusing the fade texcoord locations here +<@if HIFI_USE_MIRROR@> + <@include graphics/ShaderConstants.h@> + + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; +<@endif@> + void main() { vec4 color = evalSDFSuperSampled(_texCoord0, _glyphBounds); @@ -51,6 +57,11 @@ void main() { } <@endif@> +<@if HIFI_USE_MIRROR@> + color.rgb = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; + color.a = 1.0; +<@endif@> + <@if HIFI_USE_UNLIT@> <@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(color.rgb * isUnlitEnabled(), color.a); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 81cdaa51c9..dd7074a071 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -29,7 +29,7 @@ static std::mutex fontMutex; -std::map, gpu::PipelinePointer> Font::_pipelines; +std::map, gpu::PipelinePointer> Font::_pipelines; gpu::Stream::FormatPointer Font::_format; struct TextureVertex { @@ -277,6 +277,7 @@ void Font::setupGPU() { if (_pipelines.empty()) { using namespace shader::render_utils::program; + // transparent, unlit, forward static const std::vector> keys = { std::make_tuple(false, false, false, sdf_text3D), std::make_tuple(true, false, false, sdf_text3D_translucent), std::make_tuple(false, true, false, sdf_text3D_unlit), std::make_tuple(true, true, false, sdf_text3D_translucent_unlit), @@ -284,18 +285,23 @@ void Font::setupGPU() { std::make_tuple(false, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_unlit_forward*/), std::make_tuple(true, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_translucent_unlit_forward*/) }; for (auto& key : keys) { + bool transparent = std::get<0>(key); + bool unlit = std::get<1>(key); + bool forward = std::get<2>(key); + auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, !std::get<0>(key), gpu::LESS_EQUAL); - state->setBlendFunction(std::get<0>(key), + state->setDepthTest(true, !transparent, gpu::LESS_EQUAL); + state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - if (std::get<0>(key)) { + if (transparent) { PrepareStencil::testMask(*state); } else { PrepareStencil::testMaskDrawShape(*state); } - _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key))] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + _pipelines[std::make_tuple(transparent, unlit, forward, false)] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + _pipelines[std::make_tuple(transparent, unlit, forward, true)] = gpu::Pipeline::create(gpu::Shader::createProgram(forward ? sdf_text3D_forward_mirror : sdf_text3D_mirror), state); } // Sanity checks @@ -444,32 +450,30 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm } } -void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, - const glm::vec2& origin, const glm::vec2& bounds, float scale, bool unlit, bool forward) { - if (!_loaded || str == "") { +void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const DrawProps& props) { + if (!_loaded || props.str == "") { return; } - int textEffect = (int)effect; + int textEffect = (int)props.effect; const int SHADOW_EFFECT = (int)TextEffect::SHADOW_EFFECT; // If we're switching to or from shadow effect mode, we need to rebuild the vertices - if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin || alignment != _alignment || + if (props.str != drawInfo.string || props.bounds != drawInfo.bounds || props.origin != drawInfo.origin || props.alignment != _alignment || (drawInfo.params.effect != textEffect && (textEffect == SHADOW_EFFECT || drawInfo.params.effect == SHADOW_EFFECT)) || - (textEffect == SHADOW_EFFECT && scale != _scale)) { - _scale = scale; - _alignment = alignment; - buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT, alignment); + (textEffect == SHADOW_EFFECT && props.scale != _scale)) { + _scale = props.scale; + _alignment = props.alignment; + buildVertices(drawInfo, props.str, props.origin, props.bounds, props.scale, textEffect == SHADOW_EFFECT, props.alignment); } setupGPU(); - if (!drawInfo.paramsBuffer || drawInfo.params.color != color || drawInfo.params.effectColor != effectColor || - drawInfo.params.effectThickness != effectThickness || drawInfo.params.effect != textEffect) { - drawInfo.params.color = color; - drawInfo.params.effectColor = effectColor; - drawInfo.params.effectThickness = effectThickness; + if (!drawInfo.paramsBuffer || drawInfo.params.color != props.color || drawInfo.params.effectColor != props.effectColor || + drawInfo.params.effectThickness != props.effectThickness || drawInfo.params.effect != textEffect) { + drawInfo.params.color = props.color; + drawInfo.params.effectColor = props.effectColor; + drawInfo.params.effectThickness = props.effectThickness; drawInfo.params.effect = textEffect; // need the gamma corrected color here @@ -484,7 +488,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString drawInfo.paramsBuffer->setSubData(0, sizeof(DrawParams), (const gpu::Byte*)&gpuDrawParams); } - batch.setPipeline(_pipelines[std::make_tuple(color.a < 1.0f, unlit, forward)]); + batch.setPipeline(_pipelines[std::make_tuple(props.color.a < 1.0f, props.unlit, props.forward, props.mirror)]); batch.setInputFormat(_format); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 322e96439e..e8a353a686 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -57,10 +57,30 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const { return _fontSize; } + struct DrawProps { + DrawProps(const QString& str, const glm::vec4& color, const glm::vec3& effectColor, const glm::vec2& origin, const glm::vec2& bounds, + float scale, float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward, bool mirror) : + str(str), color(color), effectColor(effectColor), origin(origin), bounds(bounds), scale(scale), effectThickness(effectThickness), + effect(effect), alignment(alignment), unlit(unlit), forward(forward), mirror(mirror) {} + DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, bool forward) : + str(str), color(color), origin(origin), bounds(bounds), forward(forward) {} + + const QString& str; + const glm::vec4& color; + const glm::vec3& effectColor { glm::vec3(0.0f) }; + const glm::vec2& origin; + const glm::vec2& bounds; + float scale { 1.0f }; + float effectThickness { 0.0f }; + TextEffect effect { TextEffect::NO_EFFECT }; + TextAlignment alignment { TextAlignment::LEFT }; + bool unlit = true; + bool forward; + bool mirror = false; + }; + // Render string to batch - void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, - const glm::vec2& origin, const glm::vec2& bound, float scale, bool unlit, bool forward); + void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const DrawProps& props); static Pointer load(const QString& family); @@ -105,7 +125,7 @@ private: gpu::TexturePointer _texture; gpu::BufferStreamPointer _stream; - static std::map, gpu::PipelinePointer> _pipelines; + static std::map, gpu::PipelinePointer> _pipelines; static gpu::Stream::FormatPointer _format; }; diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index d09b0d2f2f..fb7d698672 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -159,6 +159,10 @@ namespace render { bool _takingSnapshot { false }; StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE }; std::function _stencilMaskOperator; + + ItemID _ignoreItem { 0 }; + size_t _mirrorDepth { 0 }; + size_t _numMirrorFlips { 0 }; }; } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 039cf01c86..cd69114bbf 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -82,7 +82,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const outItems.reserve(items.size()); for (auto& id : items) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args))); } } @@ -190,7 +190,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -205,7 +205,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -220,7 +220,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -235,7 +235,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -252,7 +252,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -267,7 +267,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -284,7 +284,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -301,7 +301,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -325,73 +325,6 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, std::static_pointer_cast(renderContext->jobConfig)->numItems = (int)outItems.size(); } -void CullShapeBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { - assert(renderContext->args); - assert(renderContext->args->hasViewFrustum()); - RenderArgs* args = renderContext->args; - - const auto& inShapes = inputs.get0(); - const auto& cullFilter = inputs.get1(); - const auto& boundsFilter = inputs.get2(); - ViewFrustumPointer antiFrustum; - auto& outShapes = outputs.edit0(); - auto& outBounds = outputs.edit1(); - - if (!inputs[3].isNull()) { - antiFrustum = inputs.get3(); - } - outShapes.clear(); - outBounds = AABox(); - - if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { - auto& details = args->_details.edit(_detailType); - CullTest test(_cullFunctor, args, details, antiFrustum); - auto scene = args->_scene; - - for (auto& inItems : inShapes) { - auto key = inItems.first; - auto outItems = outShapes.find(key); - if (outItems == outShapes.end()) { - outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first; - outItems->second.reserve(inItems.second.size()); - } - - details._considered += (int)inItems.second.size(); - - if (antiFrustum == nullptr) { - for (auto& item : inItems.second) { - if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } - } - } else { - for (auto& item : inItems.second) { - if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } - } - } - details._rendered += (int)outItems->second.size(); - } - - for (auto& items : outShapes) { - items.second.shrink_to_fit(); - } - } -} - void ApplyCullFunctorOnItemBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 9a7466223d..9e214fd988 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -121,29 +121,6 @@ namespace render { void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; - class CullShapeBounds { - public: - using Inputs = render::VaryingSet4; - using Outputs = render::VaryingSet2; - using JobModel = Job::ModelIO; - - CullShapeBounds(CullFunctor cullFunctor, RenderDetails::Type type) : - _cullFunctor{ cullFunctor }, - _detailType(type) {} - - CullShapeBounds(CullFunctor cullFunctor) : - _cullFunctor{ cullFunctor } { - } - - void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); - - private: - - CullFunctor _cullFunctor; - RenderDetails::Type _detailType{ RenderDetails::OTHER }; - - }; - class ApplyCullFunctorOnItemBounds { public: using Inputs = render::VaryingSet2; diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 369f227566..1633523267 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -160,4 +160,11 @@ namespace render { } return payload->passesZoneOcclusionTest(containingZones); } + + template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum) { + if (!payload) { + return Item::INVALID_ITEM_ID; + } + return payload->computeMirrorView(viewFrustum); + } } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 5952be8a84..f91b887fcb 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -110,6 +110,8 @@ public: FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, + MIRROR, + __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag @@ -162,6 +164,7 @@ public: Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } + Builder& withMirror() { _flags.set(MIRROR); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -205,6 +208,9 @@ public: bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } + bool isNotMirror() const { return !_flags[MIRROR]; } + bool isMirror() const { return _flags[MIRROR]; } + bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } @@ -274,7 +280,10 @@ public: Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } - Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + + Builder& withoutMirror() { _value.reset(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } + Builder& withMirror() { _value.set(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } @@ -292,6 +301,7 @@ public: static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } + static Builder mirror() { return Builder().withMirror(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; @@ -440,6 +450,8 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; + ~PayloadInterface() {} // Status interface is local to the base class @@ -493,6 +505,8 @@ public: bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); } + ItemID computeMirrorView(ViewFrustum& viewFrustum) const { return _payload->computeMirrorView(viewFrustum); } + // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -547,6 +561,9 @@ template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payl // Allows payloads to determine if they should render or not, based on the zones that contain the current camera template bool payloadPassesZoneOcclusionTest(const std::shared_ptr& payloadData, const std::unordered_set& containingZones) { return true; } +// Mirror Interface +template ItemID payloadComputeMirrorView(const std::shared_ptr& payloadData, ViewFrustum& viewFrustum) { return Item::INVALID_ITEM_ID; } + // THe Payload class is the real Payload to be used // THis allow anything to be turned into a Payload as long as the required interface functions are available // When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" @@ -573,6 +590,8 @@ public: virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override { return payloadPassesZoneOcclusionTest(_data, containingZones); } + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView(_data, viewFrustum); } + protected: DataPointer _data; @@ -628,6 +647,7 @@ public: virtual void render(RenderArgs* args) = 0; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface virtual void handleBlendedVertices(int blendshapeNumber, const QVector& blendshapeOffsets, @@ -640,6 +660,7 @@ template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, Re template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems); template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload); template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set& containingZones); +template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum); typedef Item::PayloadPointer PayloadPointer; typedef std::vector Payloads; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index b2656a597f..3bdaee25c6 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -35,18 +35,20 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto nonspatialSelection = task.addJob("FetchLayeredSelection", nonspatialFilter); // Multi filter visible items into different buckets - const int NUM_SPATIAL_FILTERS = 4; + const int NUM_SPATIAL_FILTERS = 5; const int NUM_NON_SPATIAL_FILTERS = 3; const int OPAQUE_SHAPE_BUCKET = 0; const int TRANSPARENT_SHAPE_BUCKET = 1; const int LIGHT_BUCKET = 2; const int META_BUCKET = 3; + const int MIRROR_BUCKET = 4; const int BACKGROUND_BUCKET = 2; MultiFilterItems::ItemFilterArray spatialFilters = { { - ItemFilter::Builder::opaqueShape(), + ItemFilter::Builder::opaqueShape().withoutMirror(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::light(), - ItemFilter::Builder::meta() + ItemFilter::Builder::meta().withoutMirror(), + ItemFilter::Builder::mirror() } }; MultiFilterItems::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), @@ -65,6 +67,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto transparents = task.addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; const auto metas = filteredSpatialBuckets[META_BUCKET]; + const auto mirrors = task.addJob("DepthSortMirrors", filteredSpatialBuckets[MIRROR_BUCKET]); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; @@ -76,7 +79,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin task.addJob("ClearContainingZones"); - output = Output(BucketList{ opaques, transparents, lights, metas, + output = Output(BucketList{ opaques, transparents, lights, metas, mirrors, filteredLayeredOpaque.getN(0), filteredLayeredTransparent.getN(0), filteredLayeredOpaque.getN(1), filteredLayeredTransparent.getN(1), background }, spatialSelection); diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index 0b475614a1..9823c2acdf 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -23,6 +23,7 @@ public: TRANSPARENT_SHAPE, LIGHT, META, + MIRROR, LAYER_FRONT_OPAQUE_SHAPE, LAYER_FRONT_TRANSPARENT_SHAPE, LAYER_HUD_OPAQUE_SHAPE, diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index b868c53542..e77dda600c 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,7 +167,8 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index 92f720c843..bf1e535949 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -73,7 +73,7 @@ namespace render { using Input = gpu::FramebufferPointer; using JobModel = Job::ModelIO; - UpsampleToBlitFramebuffer() {} + UpsampleToBlitFramebuffer(size_t depth) : _depth(depth) {} void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); @@ -81,6 +81,8 @@ namespace render { static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _mirrorPipeline; + + size_t _depth; }; } diff --git a/libraries/shared/src/MirrorMode.cpp b/libraries/shared/src/MirrorMode.cpp new file mode 100644 index 0000000000..272eb5d7c0 --- /dev/null +++ b/libraries/shared/src/MirrorMode.cpp @@ -0,0 +1,36 @@ +// +// Created by HifiExperiments on 3/14/22. +// Copyright 2022 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 "MirrorMode.h" + +const char* MirrorModeNames[] = { + "none", + "mirror", + "portal" +}; + +static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0])); +std::function MirrorModeHelpers::_computeMirrorViewOperator = + [](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return 0; }; + +QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) { + mode = (MirrorMode)0; + } + + return MirrorModeNames[(int)mode]; +} + +void MirrorModeHelpers::setComputeMirrorViewOperator(std::function computeMirrorViewOperator) { + _computeMirrorViewOperator = computeMirrorViewOperator; +} + +uint32_t MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { + return _computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +} \ No newline at end of file diff --git a/libraries/shared/src/MirrorMode.h b/libraries/shared/src/MirrorMode.h new file mode 100644 index 0000000000..e48e564df0 --- /dev/null +++ b/libraries/shared/src/MirrorMode.h @@ -0,0 +1,51 @@ +// +// Created by HifiExperiments on 3/14/22. +// Copyright 2022 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_MirrorMode_h +#define hifi_MirrorMode_h + +#include + +#include "QString" + +#include "ViewFrustum.h" + +/*@jsdoc + *

If an entity is rendered as a mirror, a portal, or normally.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
"none"The entity will render normally.
"mirror"The entity will render as a mirror.
"portal"The entity will render as a portal.
+ * @typedef {string} MirrorMode + */ + +enum class MirrorMode { + NONE = 0, + MIRROR, + PORTAL +}; + +class MirrorModeHelpers { +public: + static QString getNameForMirrorMode(MirrorMode mode); + + static void setComputeMirrorViewOperator(std::function computeMirrorViewOperator); + static uint32_t computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); + +private: + static std::function _computeMirrorViewOperator; +}; + +#endif // hifi_MirrorMode_h diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index e925ef960d..daa08b5dbc 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -53,7 +53,7 @@ static const glm::vec4 NDC_VALUES[NUM_FRUSTUM_CORNERS] = { glm::vec4(-1.0f, 1.0f, 1.0f, 1.0f), }; -void ViewFrustum::setProjection(const glm::mat4& projection) { +void ViewFrustum::setProjection(const glm::mat4& projection, bool isOblique) { _projection = projection; glm::mat4 inverseProjection = glm::inverse(projection); @@ -63,16 +63,21 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { _corners[i] /= _corners[i].w; } - // compute frustum properties - _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; - _farClip = -_corners[BOTTOM_LEFT_FAR].z; - _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / - (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); - glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); - top /= top.w; - _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); - _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; - _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; + // HACK: these calculations aren't correct for our oblique mirror frustums, but we can just reuse the values from the original + // frustum since these values are only used on the CPU. + if (!isOblique) { + // compute frustum properties + _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; + _farClip = -_corners[BOTTOM_LEFT_FAR].z; + _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / + (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); + glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); + top /= top.w; + _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); + _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; + _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; + } + _isOblique = isOblique; } void ViewFrustum::setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip) { @@ -109,12 +114,24 @@ void ViewFrustum::calculate() { // the function set3Points assumes that the points are given in counter clockwise order, assume you // are inside the frustum, facing the plane. Start with any point, and go counter clockwise for // three consecutive points - _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); - _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); - _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); - _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); + if (!_isOblique) { + _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); + _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); + _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); + _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); + } else { + Corners near = getCorners(_nearClip); + Corners far = getCorners(_farClip); + + _planes[TOP_PLANE].set3Points(near.topRight, near.topLeft, far.topLeft); + _planes[BOTTOM_PLANE].set3Points(near.bottomLeft, near.bottomRight, far.bottomRight); + _planes[LEFT_PLANE].set3Points(near.bottomLeft, far.bottomLeft, far.topLeft); + _planes[RIGHT_PLANE].set3Points(far.bottomRight, near.bottomRight, far.topRight); + _planes[NEAR_PLANE].set3Points(near.bottomRight, near.bottomLeft, near.topLeft); + _planes[FAR_PLANE].set3Points(far.bottomLeft, far.bottomRight, far.topRight); + } // Also calculate our projection matrix in case people want to project points... // Projection matrix : Field of View, ratio, display range : near to far diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 9c80538e60..fa66a0a87e 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -47,7 +47,7 @@ public: const glm::vec3& getRight() const { return _right; } // setters for lens attributes - void setProjection(const glm::mat4 & projection); + void setProjection(const glm::mat4& projection, bool isOblique = false); void setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip); void setFocalLength(float focalLength) { _focalLength = focalLength; } bool isPerspective() const; @@ -103,7 +103,6 @@ public: bool pointIntersectsFrustum(const glm::vec3& point) const; bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const; - bool cubeIntersectsFrustum(const AACube& box) const; bool boxIntersectsFrustum(const AABox& box) const; bool boxInsideFrustum(const AABox& box) const; @@ -175,6 +174,8 @@ private: float _nearClip { DEFAULT_NEAR_CLIP }; float _farClip { DEFAULT_FAR_CLIP }; + bool _isOblique { false }; + const char* debugPlaneName (int plane) const; // Used to project points diff --git a/scripts/system/create/assets/data/createAppTooltips.json b/scripts/system/create/assets/data/createAppTooltips.json index 9f6c3ef278..57cb3d1bc8 100644 --- a/scripts/system/create/assets/data/createAppTooltips.json +++ b/scripts/system/create/assets/data/createAppTooltips.json @@ -215,7 +215,7 @@ }, "imageAlpha": { "tooltip": "The opacity of the image between 0.0 fully transparent and 1.0 completely opaque." - }, + }, "emissive": { "tooltip": "If enabled, the image will display at full brightness." }, @@ -236,7 +236,7 @@ }, "showKeyboardFocusHighlight": { "tooltip": "If enabled, highlights when it has keyboard focus." - }, + }, "isEmitting": { "tooltip": "If enabled, then particles are emitted." }, @@ -503,6 +503,12 @@ "grab.triggerable": { "tooltip": "If enabled, the collider on this entity is used for triggering events." }, + "mirrorMode": { + "tooltip": "If this entity should render normally, or as a \"Mirror\" or \"Portal\"" + }, + "portalExitID": { + "tooltip": "If this entity is a portal, what entity it should use as its exit." + }, "cloneable": { "tooltip": "If enabled, this entity can be duplicated." }, @@ -606,7 +612,7 @@ }, "useBackground": { "tooltip": "If disabled, this web entity will support a transparent background for the webpage and its elements if the CSS property of 'background-color' on the 'body' is set with transparency." - }, + }, "maxFPS": { "tooltip": "The FPS at which to render the web entity. Higher values will have a performance impact." }, diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index e16b6ca653..b509168262 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -127,6 +127,22 @@ const GROUPS = [ }, propertyID: "billboardMode", }, + { + label: "Mirror Mode", + type: "dropdown", + options: { + none: "None", + mirror: "Mirror", + portal: "Portal" + }, + propertyID: "mirrorMode", + }, + { + label: "Portal Exit", + type: "string", + propertyID: "portalExitID", + showPropertyRule: { "mirrorMode": "portal" }, + }, { label: "Render With Zones", type: "multipleZonesSelection", diff --git a/tools/gpu-frame-player/src/RenderThread.cpp b/tools/gpu-frame-player/src/RenderThread.cpp index 0089c1577b..de39dacdea 100644 --- a/tools/gpu-frame-player/src/RenderThread.cpp +++ b/tools/gpu-frame-player/src/RenderThread.cpp @@ -122,7 +122,7 @@ void RenderThread::renderFrame(gpu::FramePointer& frame) { if (_correction != glm::mat4()) { std::unique_lock lock(_frameLock); if (_correction != glm::mat4()) { - _backend->setCameraCorrection(_correction, _activeFrame->view); + _backend->setCameraCorrection(_correction, _activeFrame->view, true); //_prevRenderView = _correction * _activeFrame->view; } }