mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
mirrors wip
This commit is contained in:
parent
fb5b0779a4
commit
89e6cbbfa4
40 changed files with 699 additions and 54 deletions
|
@ -27,7 +27,7 @@ public:
|
|||
using Config = SecondaryCameraJobConfig;
|
||||
using JobModel = render::Job::ModelO<SecondaryCameraJob, RenderArgsPointer, Config>;
|
||||
SecondaryCameraJob() {
|
||||
_cachedArgsPointer = std::make_shared<RenderArgs>(_cachedArgs);
|
||||
_cachedArgsPointer = std::make_shared<RenderArgs>();
|
||||
_attachedEntityPropertyFlags += PROP_POSITION;
|
||||
_attachedEntityPropertyFlags += PROP_ROTATION;
|
||||
}
|
||||
|
@ -203,7 +203,6 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
RenderArgs _cachedArgs;
|
||||
RenderArgsPointer _cachedArgsPointer;
|
||||
|
||||
private:
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//
|
||||
#include "RenderScriptingInterface.h"
|
||||
|
||||
#include <RenderCommonTask.h>
|
||||
#include <ScriptEngineCast.h>
|
||||
|
||||
#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<render::SwitchConfig*>(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<render::SwitchConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch"));
|
||||
QString configName = "RenderMainView.DeferredForwardSwitch";
|
||||
auto config = dynamic_cast<render::SwitchConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig(configName));
|
||||
if (config) {
|
||||
config->setBranch((int)renderMethod);
|
||||
|
||||
recursivelyUpdateMirrorRenderMethods(configName + (renderMethod == RenderMethod::FORWARD ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"),
|
||||
(int)renderMethod, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <ObjectMotionState.h>
|
||||
|
||||
#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<QUuid>& 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;
|
||||
}
|
||||
|
|
|
@ -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<QUuid>& 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<typename T>
|
||||
std::shared_ptr<T> asTypedEntity() { return std::static_pointer_cast<T>(_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;
|
||||
|
|
|
@ -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<scriptable::ModelProviderFactory>()->
|
||||
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<MirrorMode>([&] {
|
||||
return _mirrorMode;
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::setMirrorMode(MirrorMode value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _mirrorMode != value;
|
||||
_mirrorMode = value;
|
||||
});
|
||||
}
|
||||
|
||||
QUuid EntityItem::getPortalExitID() const {
|
||||
return resultWithReadLock<QUuid>([&] {
|
||||
return _portalExitID;
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::setPortalExitID(const QUuid& value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _portalExitID != value;
|
||||
_portalExitID = value;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<int32_t, glm::vec4> data);
|
||||
|
||||
|
@ -740,6 +746,9 @@ protected:
|
|||
|
||||
bool _cullWithParent { false };
|
||||
|
||||
MirrorMode _mirrorMode { MirrorMode::NONE };
|
||||
QUuid _portalExitID;
|
||||
|
||||
mutable bool _needsRenderUpdate { false };
|
||||
};
|
||||
|
||||
|
|
|
@ -424,6 +424,23 @@ void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHost
|
|||
}
|
||||
}
|
||||
|
||||
inline void addMirrorMode(QHash<QString, MirrorMode>& lookup, MirrorMode mirrorMode) { lookup[MirrorModeHelpers::getNameForMirrorMode(mirrorMode)] = mirrorMode; }
|
||||
const QHash<QString, MirrorMode> stringToMirrorModeLookup = [] {
|
||||
QHash<QString, MirrorMode> 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 <code>portalExitID</code>), or normally.
|
||||
* @property {Uuid} portalExitID=Uuid.NULL - The ID of the entity that should act as the portal exit if the <code>mirrorMode</code>
|
||||
* is set to <code>portal</code>.
|
||||
*
|
||||
* @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<QUuid>, 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<QString> EntityItemProperties::listChangedProperties() {
|
|||
out += "billboardMode";
|
||||
}
|
||||
getGrab().listChangedProperties(out);
|
||||
if (mirrorModeChanged()) {
|
||||
out += "mirrorMode";
|
||||
}
|
||||
if (portalExitIDChanged()) {
|
||||
out += "portalExitID";
|
||||
}
|
||||
|
||||
// Physics
|
||||
if (densityChanged()) {
|
||||
|
|
|
@ -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<QUuid>, QVector<QUuid>());
|
||||
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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -290,6 +290,7 @@ enum class EntityVersion : PacketVersion {
|
|||
UserAgent,
|
||||
AllBillboardMode,
|
||||
TextAlignment,
|
||||
Mirror,
|
||||
|
||||
// Add new versions above here
|
||||
NUM_PACKET_TYPE,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -506,8 +506,9 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
|
|||
const auto jitter = inputs.getN<Inputs>(4);
|
||||
|
||||
// Prepare the ShapePipeline
|
||||
auto shapePlumber = std::make_shared<ShapePlumber>();
|
||||
{
|
||||
static ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
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<FadeEffect>();
|
||||
initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
|
||||
}
|
||||
});
|
||||
auto sharedParameters = std::make_shared<HighlightSharedParameters>();
|
||||
|
||||
const auto highlightSelectionNames = task.addJob<SelectionToHighlight>("SelectionToHighlight", sharedParameters);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "MeshPartPayload.h"
|
||||
|
||||
#include <BillboardMode.h>
|
||||
#include <MirrorMode.h>
|
||||
#include <PerfStat.h>
|
||||
#include <DualQuaternion.h>
|
||||
#include <graphics/ShaderConstants.h>
|
||||
|
@ -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<QUui
|
|||
return true;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeMirrorView(ViewFrustum& viewFrustum) const {
|
||||
return;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,10 @@ public:
|
|||
void setCullWithParent(bool value) { _cullWithParent = value; }
|
||||
void setRenderWithZones(const QVector<QUuid>& 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<QUuid>& 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<QUuid> _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<QUuid>& containingZones);
|
||||
template <> void payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum);
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_MeshPartPayload_h
|
||||
|
|
|
@ -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<ModelMeshPartPayload>(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<QUuid>& 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<ModelMeshPartPayload>(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<ModelMeshPartPayload>(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) {
|
||||
data.setPortalExitID(portalExitID);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
|
||||
return _renderItemKeyGlobalFlags;
|
||||
}
|
||||
|
|
|
@ -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<QUuid>& renderWithZones, const render::ScenePointer& scene = nullptr);
|
||||
const QVector<QUuid>& 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<QUuid> _renderWithZones;
|
||||
MirrorMode _mirrorMode { MirrorMode::NONE };
|
||||
QUuid _portalExitID;
|
||||
|
||||
bool shouldInvalidatePayloadShapeKey(int meshIndex);
|
||||
|
||||
|
|
|
@ -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<RenderArgs>;
|
||||
|
||||
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<ShapePlumber>();
|
||||
|
||||
DrawLayered3D::DrawLayered3D(bool opaque) :
|
||||
_shapePlumber(std::make_shared<ShapePlumber>()),
|
||||
_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<render::ItemBound, gpu::FramebufferPointer, RenderArgsPointer, glm::vec2>;
|
||||
using JobModel = render::Job::ModelIO<SetupMirrorTask, Input, Outputs>;
|
||||
|
||||
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<RenderArgs>() };
|
||||
size_t _mirrorIndex;
|
||||
|
||||
};
|
||||
|
||||
class DrawMirrorTask {
|
||||
public:
|
||||
using Inputs = SetupMirrorTask::Outputs;
|
||||
using JobModel = render::Job::ModelI<DrawMirrorTask, Inputs>;
|
||||
|
||||
DrawMirrorTask() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [this] {
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
|
||||
auto fadeEffect = DependencyManager::get<FadeEffect>();
|
||||
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<ShapePlumber>();
|
||||
ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared<ShapePlumber>();
|
||||
|
||||
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<SetupMirrorTask>("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex);
|
||||
|
||||
task.addJob<RenderViewTask>("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>("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#define hifi_RenderCommonTask_h
|
||||
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <render/CullTask.h>
|
||||
|
||||
#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<render::ItemBounds, gpu::FramebufferPointer, glm::vec2>;
|
||||
using JobModel = render::Task::ModelI<RenderMirrorTask, Inputs>;
|
||||
|
||||
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
|
||||
|
|
|
@ -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<FadeEffect>();
|
||||
void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) {
|
||||
static auto fadeEffect = DependencyManager::get<FadeEffect>();
|
||||
// Prepare the ShapePipelines
|
||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
|
||||
static ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
|
||||
});
|
||||
|
||||
const auto& inputs = input.get<Input>();
|
||||
|
||||
|
@ -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<JitterSample>("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<DrawStateSortDeferred>("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>("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<TextureCache>()->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<TextureCache>()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE);
|
||||
});
|
||||
const auto drawStatusInputs = DrawStatus::Input(opaques, jitter).asVarying();
|
||||
task.addJob<DrawStatus>("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<DebugZoneLighting>("DrawZoneStack", debugZoneInputs);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) {
|
||||
|
|
|
@ -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:
|
||||
};
|
||||
|
|
|
@ -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<SetRenderMethod>("SetRenderMethodTask", render::Args::FORWARD);
|
||||
|
||||
// Prepare the ShapePipelines
|
||||
auto fadeEffect = DependencyManager::get<FadeEffect>();
|
||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
initForwardPipelines(*shapePlumber);
|
||||
static ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
initForwardPipelines(*shapePlumber);
|
||||
});
|
||||
|
||||
// Unpack inputs
|
||||
const auto& inputs = input.get<Input>();
|
||||
|
@ -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<PreparePrimaryFramebufferMSAA>("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<DrawForward>("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>("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<DrawBackgroundStage>("DrawBackgroundForward", backgroundInputs);
|
||||
|
@ -134,7 +149,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
|
|||
task.addJob<DrawForward>("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<DrawLayered3D>("DrawInFrontOpaque", inFrontOpaquesInputs, true);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<ShapePlumber>();
|
||||
{
|
||||
static ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
|
||||
auto fadeEffect = DependencyManager::get<FadeEffect>();
|
||||
initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
|
||||
}
|
||||
});
|
||||
const auto setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup", input);
|
||||
const auto queryResolution = setupOutput.getN<RenderShadowSetup::Output>(1);
|
||||
const auto shadowFrame = setupOutput.getN<RenderShadowSetup::Output>(3);
|
||||
|
|
|
@ -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<SetRenderMethod>("SetRenderMethodTask", render::Args::DEFERRED);
|
||||
|
||||
const auto items = input.getN<DeferredForwardSwitchJob::Input>(0);
|
||||
|
@ -28,16 +28,16 @@ void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying&
|
|||
const auto shadowTaskOut = task.addJob<RenderShadowTask>("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask);
|
||||
|
||||
const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying();
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", renderDeferredInput);
|
||||
task.addJob<RenderDeferredTask>("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>("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>("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask, depth);
|
||||
|
||||
task.addBranch<RenderForwardTask>("RenderForwardTask", 1, input);
|
||||
task.addBranch<RenderForwardTask>("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<RenderFetchCullSortTask>("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<DeferredForwardSwitchJob>("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask);
|
||||
task.addJob<DeferredForwardSwitchJob>("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask, depth);
|
||||
#else
|
||||
const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying();
|
||||
task.addJob<RenderForwardTask>("RenderForwardTask", renderInput);
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1 +1 @@
|
|||
DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow fade:f/forward:f deformed:v/deformeddq:v
|
||||
DEFINES (normalmap translucent:f unlit:f/lightmap:f)/(shadow mirror:f) fade:f/forward:f deformed:v/deformeddq:v
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<QUuid>& 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<QUuid>& 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 <class T> uint32_t metaFetchMetaSubItems(const std::shared_ptr<T>& payl
|
|||
// Allows payloads to determine if they should render or not, based on the zones that contain the current camera
|
||||
template <class T> bool payloadPassesZoneOcclusionTest(const std::shared_ptr<T>& payloadData, const std::unordered_set<QUuid>& containingZones) { return true; }
|
||||
|
||||
// Mirror Interface
|
||||
template <class T> void payloadComputeMirrorView(const std::shared_ptr<T>& 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<QUuid>& containingZones) const override { return payloadPassesZoneOcclusionTest<T>(_data, containingZones); }
|
||||
|
||||
virtual void computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView<T>(_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<QUuid>& 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<BlendshapeOffset>& 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<QUuid>& containingZones);
|
||||
template <> void payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum);
|
||||
|
||||
typedef Item::PayloadPointer PayloadPointer;
|
||||
typedef std::vector<PayloadPointer> Payloads;
|
||||
|
|
|
@ -35,18 +35,20 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
|
|||
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("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<NUM_SPATIAL_FILTERS>::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<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
|
||||
ItemFilter::Builder::opaqueShape(),
|
||||
|
@ -65,6 +67,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
|
|||
const auto transparents = task.addJob<DepthSortItems>("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
||||
const auto lights = filteredSpatialBuckets[LIGHT_BUCKET];
|
||||
const auto metas = filteredSpatialBuckets[META_BUCKET];
|
||||
const auto mirrors = task.addJob<DepthSortItems>("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>("ClearContainingZones");
|
||||
|
||||
output = Output(BucketList{ opaques, transparents, lights, metas,
|
||||
output = Output(BucketList{ opaques, transparents, lights, metas, mirrors,
|
||||
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(0), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(0),
|
||||
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(1), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(1),
|
||||
background }, spatialSelection);
|
||||
|
|
|
@ -23,6 +23,7 @@ public:
|
|||
TRANSPARENT_SHAPE,
|
||||
LIGHT,
|
||||
META,
|
||||
MIRROR,
|
||||
LAYER_FRONT_OPAQUE_SHAPE,
|
||||
LAYER_FRONT_TRANSPARENT_SHAPE,
|
||||
LAYER_HUD_OPAQUE_SHAPE,
|
||||
|
|
25
libraries/shared/src/MirrorMode.cpp
Normal file
25
libraries/shared/src/MirrorMode.cpp
Normal file
|
@ -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];
|
||||
}
|
40
libraries/shared/src/MirrorMode.h
Normal file
40
libraries/shared/src/MirrorMode.h
Normal file
|
@ -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
|
||||
* <p>If an entity is rendered as a mirror, a portal, or normally.</p>
|
||||
* <table>
|
||||
* <thead>
|
||||
* <tr><th>Value</th><th>Description</th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td><code>"none"</code></td><td>The entity will render normally.</td></tr>
|
||||
* <tr><td><code>"mirror"</code></td><td>The entity will render as a mirror.</td></tr>
|
||||
* <tr><td><code>"portal"</code></td><td>The entity will render as a portal.</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {string} MirrorMode
|
||||
*/
|
||||
|
||||
enum class MirrorMode {
|
||||
NONE = 0,
|
||||
MIRROR,
|
||||
PORTAL
|
||||
};
|
||||
|
||||
class MirrorModeHelpers {
|
||||
public:
|
||||
static QString getNameForMirrorMode(MirrorMode mode);
|
||||
};
|
||||
|
||||
#endif // hifi_MirrorMode_h
|
|
@ -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."
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue