zone occlusion

This commit is contained in:
HifiExperiments 2020-01-11 22:29:07 -08:00
parent 6b5d1c6191
commit bc319cb340
29 changed files with 272 additions and 77 deletions

View file

@ -19,8 +19,6 @@
#include <GeometryCache.h>
#include "Menu.h"
class WorldBoxRenderData {
public:
typedef render::Payload<WorldBoxRenderData> Payload;
@ -29,8 +27,6 @@ public:
int _val = 0;
static render::ItemID _item; // unique WorldBoxRenderData
static void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
};

View file

@ -128,7 +128,7 @@ std::shared_ptr<T> make_renderer(const EntityItemPointer& entity) {
return std::shared_ptr<T>(new T(entity), [](T* ptr) { ptr->deleteLater(); });
}
EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entity->getCreated()), _entity(entity) {}
EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entity->getCreated()), _entity(entity), _entityID(entity->getID()) {}
EntityRenderer::~EntityRenderer() {}
@ -196,6 +196,23 @@ uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
return 0;
}
bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
auto renderWithZones = resultWithReadLock<QVector<QUuid>>([&] {
return _renderWithZones;
});
if (!renderWithZones.isEmpty()) {
if (!containingZones.empty()) {
for (auto renderWithZone : renderWithZones) {
if (containingZones.find(renderWithZone) != containingZones.end()) {
return true;
}
}
}
return false;
}
return true;
}
void EntityRenderer::render(RenderArgs* args) {
if (!isValidRenderItem()) {
return;
@ -385,6 +402,10 @@ bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity
return true;
}
if (entity->needsZoneOcclusionUpdate()) {
return true;
}
return false;
}
@ -426,6 +447,10 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
_canCastShadow = entity->getCanCastShadow();
setCullWithParent(entity->getCullWithParent());
_cauterized = entity->getCauterized();
if (entity->needsZoneOcclusionUpdate()) {
entity->resetNeedsZoneOcclusionUpdate();
setRenderWithZones(entity->getRenderWithZones());
}
entity->setNeedsRenderUpdate(false);
});
}

View file

@ -65,6 +65,7 @@ public:
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
virtual Item::Bound getBound() override;
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override;
protected:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
@ -109,6 +110,7 @@ protected:
virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
virtual void setPrimitiveMode(PrimitiveMode value) { _primitiveMode = value; }
virtual void setCullWithParent(bool value) { _cullWithParent = value; }
virtual void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
template <typename F, typename T>
T withReadLockResult(const std::function<T()>& f) {
@ -143,6 +145,7 @@ protected:
bool _cullWithParent { false };
RenderLayer _renderLayer { RenderLayer::WORLD };
PrimitiveMode _primitiveMode { PrimitiveMode::SOLID };
QVector<QUuid> _renderWithZones;
bool _cauterized { false };
bool _moving { false };
// Only touched on the rendering thread
@ -153,6 +156,7 @@ protected:
std::mutex _materialsLock;
quint64 _created;
QUuid _entityID;
// The base class relies on comparing the model transform to the entity transform in order
// to trigger an update, so the member must not be visible to derived classes as a modifiable

View file

@ -1324,6 +1324,9 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
setKey(didVisualGeometryRequestSucceed);
_model->setTagMask(getTagMask());
_model->setHifiRenderLayer(getHifiRenderLayer());
_model->setPrimitiveMode(_primitiveMode);
_model->setCullWithParent(_cullWithParent);
_model->setRenderWithZones(_renderWithZones);
emit requestRenderUpdate();
if(didVisualGeometryRequestSucceed) {
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
@ -1507,6 +1510,13 @@ void ModelEntityRenderer::setCullWithParent(bool value) {
}
}
void ModelEntityRenderer::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
Parent::setRenderWithZones(renderWithZones);
if (_model) {
_model->setRenderWithZones(renderWithZones);
}
}
// 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");

View file

@ -165,6 +165,7 @@ protected:
void setRenderLayer(RenderLayer value) override;
void setPrimitiveMode(PrimitiveMode value) override;
void setCullWithParent(bool value) override;
void setRenderWithZones(const QVector<QUuid>& renderWithZones) override;
private:
void animate(const TypedEntityPointer& entity);

View file

@ -289,6 +289,17 @@ ShapeKey entities::TextPayload::getShapeKey() const {
return ShapeKey::Builder::invalid();
}
bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
if (entityTreeRenderer) {
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (renderable) {
return std::static_pointer_cast<TextEntityRenderer>(renderable)->passesZoneOcclusionTest(containingZones);
}
}
return false;
}
void entities::TextPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("TextPayload::render");
Q_ASSERT(args->_batch);
@ -388,4 +399,12 @@ template <> const ShapeKey shapeGetShapeKey(const TextPayload::Pointer& payload)
template <> void payloadRender(const TextPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (payload) {
return payload->passesZoneOcclusionTest(containingZones);
}
return false;
}
}

View file

@ -94,6 +94,7 @@ public:
Item::Bound getBound() const;
ShapeKey getShapeKey() const;
void render(RenderArgs* args);
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
protected:
QUuid _entityID;
@ -109,6 +110,7 @@ namespace render {
template <> const Item::Bound payloadGetBound(const entities::TextPayload::Pointer& payload);
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<QUuid>& containingZones);
}
#endif // hifi_RenderableTextEntityItem_h

View file

@ -71,6 +71,11 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity
}
void ZoneEntityRenderer::doRender(RenderArgs* args) {
// This is necessary so that zones can themselves be zone culled
if (!passesZoneOcclusionTest(CullTest::_prevContainingZones)) {
return;
}
if (!_stage) {
_stage = args->_scene->getStage<LightStage>();
assert(_stage);
@ -180,6 +185,8 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
_bloomStage->_currentFrame.pushBloom(_bloomIndex);
}
}
CullTest::_containingZones.insert(_entityID);
}
void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {

View file

@ -105,6 +105,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_RENDER_LAYER;
requestedProperties += PROP_PRIMITIVE_MODE;
requestedProperties += PROP_IGNORE_PICK_INTERSECTION;
requestedProperties += PROP_RENDER_WITH_ZONES;
requestedProperties += _grabProperties.getEntityProperties(params);
// Physics
@ -300,6 +301,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)getRenderLayer());
APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)getPrimitiveMode());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, getIgnorePickIntersection());
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, getRenderWithZones());
withReadLock([&] {
_grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
@ -875,6 +877,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_RENDER_LAYER, RenderLayer, setRenderLayer);
READ_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode);
READ_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
READ_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, QVector<QUuid>, setRenderWithZones);
withWriteLock([&] {
int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData,
@ -1354,6 +1357,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderLayer, getRenderLayer);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(primitiveMode, getPrimitiveMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignorePickIntersection, getIgnorePickIntersection);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderWithZones, getRenderWithZones);
withReadLock([&] {
_grabProperties.getProperties(properties);
});
@ -1503,6 +1507,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderLayer, setRenderLayer);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(primitiveMode, setPrimitiveMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignorePickIntersection, setIgnorePickIntersection);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderWithZones, setRenderWithZones);
withWriteLock([&] {
bool grabPropertiesChanged = _grabProperties.setProperties(properties);
somethingChanged |= grabPropertiesChanged;
@ -3520,3 +3525,18 @@ void EntityItem::disableGrab(GrabPointer grab) {
}
}
}
void EntityItem::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
withWriteLock([&] {
if (_renderWithZones != renderWithZones) {
_needsZoneOcclusionUpdate = true;
_renderWithZones = renderWithZones;
}
});
}
QVector<QUuid> EntityItem::getRenderWithZones() const {
return resultWithReadLock<QVector<QUuid>>([&] {
return _renderWithZones;
});
}

View file

@ -577,6 +577,11 @@ public:
bool needsRenderUpdate() const { return resultWithReadLock<bool>([&] { return _needsRenderUpdate; }); }
void setNeedsRenderUpdate(bool needsRenderUpdate) { withWriteLock([&] { _needsRenderUpdate = needsRenderUpdate; }); }
void setRenderWithZones(const QVector<QUuid>& renderWithZones);
QVector<QUuid> getRenderWithZones() const;
bool needsZoneOcclusionUpdate() const { return _needsZoneOcclusionUpdate; }
void resetNeedsZoneOcclusionUpdate() { withWriteLock([&] { _needsZoneOcclusionUpdate = false; }); }
signals:
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
@ -765,6 +770,9 @@ protected:
QHash<QUuid, EntityDynamicPointer> _grabActions;
QVector<QUuid> _renderWithZones;
mutable bool _needsZoneOcclusionUpdate { false };
bool _cullWithParent { false };
mutable bool _needsRenderUpdate { false };

View file

@ -421,6 +421,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_RENDER_LAYER, renderLayer);
CHECK_PROPERTY_CHANGE(PROP_PRIMITIVE_MODE, primitiveMode);
CHECK_PROPERTY_CHANGE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones);
changedProperties += _grab.getChangedProperties();
// Physics
@ -793,6 +794,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* avatar entities, <code>false</code> if they won't be.
* @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from.
*
* @property {Uuid[]} renderWithZones=[]] - A list of entity IDs representing with which zones this entity should render.
* If it is empty, this entity will render normally. Otherwise, this entity will only render if your avatar is within
* one of the zones in this list.
*
* @property {Entities.Grab} grab - The entity's grab-related properties.
*
* @property {string} itemName="" - Certifiable name of the Marketplace item.
@ -1583,6 +1588,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_RENDER_LAYER, renderLayer, getRenderLayerAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PRIMITIVE_MODE, primitiveMode, getPrimitiveModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones);
_grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
// Physics
@ -2000,6 +2006,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(renderLayer, RenderLayer);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(primitiveMode, PrimitiveMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(ignorePickIntersection, bool, setIgnorePickIntersection);
COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones);
_grab.copyFromScriptValue(object, _defaultSettings);
// Physics
@ -2293,6 +2300,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(renderLayer);
COPY_PROPERTY_IF_CHANGED(primitiveMode);
COPY_PROPERTY_IF_CHANGED(ignorePickIntersection);
COPY_PROPERTY_IF_CHANGED(renderWithZones);
_grab.merge(other._grab);
// Physics
@ -2585,6 +2593,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer);
ADD_PROPERTY_TO_MAP(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode);
ADD_PROPERTY_TO_MAP(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool);
ADD_PROPERTY_TO_MAP(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector<QUuid>);
{ // Grab
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic);
@ -3073,6 +3082,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)properties.getRenderLayer());
APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)properties.getPrimitiveMode());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, properties.getIgnorePickIntersection());
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, properties.getRenderWithZones());
_staticGrab.setProperties(properties);
_staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
@ -3562,6 +3572,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_LAYER, RenderLayer, setRenderLayer);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector<QUuid>, setRenderWithZones);
properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
// Physics
@ -3979,6 +3990,7 @@ void EntityItemProperties::markAllChanged() {
_renderLayerChanged = true;
_primitiveModeChanged = true;
_ignorePickIntersectionChanged = true;
_renderWithZonesChanged = true;
_grab.markAllChanged();
// Physics
@ -4381,6 +4393,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (ignorePickIntersectionChanged()) {
out += "ignorePickIntersection";
}
if (renderWithZonesChanged()) {
out += "renderWithZones";
}
getGrab().listChangedProperties(out);
// Physics

View file

@ -192,6 +192,7 @@ public:
DEFINE_PROPERTY_REF_ENUM(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer, RenderLayer::WORLD);
DEFINE_PROPERTY_REF_ENUM(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode, PrimitiveMode::SOLID);
DEFINE_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool, false);
DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector<QUuid>, QVector<QUuid>());
DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup);
// Physics

View file

@ -119,6 +119,7 @@ inline QScriptValue qVectorVec3Color_convertScriptValue(QScriptEngine* e, const
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<glm::quat>& v) {return qVectorQuatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<bool>& v) {return qVectorBoolToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<float>& v) { return qVectorFloatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<QUuid>& v) { return qVectorQUuidToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); }
@ -216,6 +217,7 @@ typedef QVector<glm::vec3> qVectorVec3;
typedef QVector<glm::quat> qVectorQuat;
typedef QVector<bool> qVectorBool;
typedef QVector<float> qVectorFloat;
typedef QVector<QUuid> qVectorQUuid;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline quint64 quint64_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); }
inline quint32 quint32_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
@ -293,6 +295,11 @@ inline qVectorBool qVectorBool_convertFromScriptValue(const QScriptValue& v, boo
return qVectorBoolFromScriptValue(v);
}
inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
return qVectorQUuidFromScriptValue(v);
}
inline glm::quat quat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");

View file

@ -43,6 +43,7 @@ enum EntityPropertyList {
PROP_RENDER_LAYER,
PROP_PRIMITIVE_MODE,
PROP_IGNORE_PICK_INTERSECTION,
PROP_RENDER_WITH_ZONES,
// Grab
PROP_GRAB_GRABBABLE,
PROP_GRAB_KINEMATIC,

View file

@ -275,6 +275,7 @@ enum class EntityVersion : PacketVersion {
ShadowBiasAndDistance,
TextEntityFonts,
ScriptServerKinematicMotion,
ZoneOcclusion,
// Add new versions above here
NUM_PACKET_TYPE,

View file

@ -482,6 +482,19 @@ bool OctreePacketData::appendValue(const QVector<bool>& value) {
return success;
}
bool OctreePacketData::appendValue(const QVector<QUuid>& value) {
uint16_t qVecSize = value.size();
bool success = appendValue(qVecSize);
if (success) {
success = append((const unsigned char*)value.constData(), qVecSize * sizeof(QUuid));
if (success) {
_bytesOfValues += qVecSize * sizeof(QUuid);
_totalBytesOfValues += qVecSize * sizeof(QUuid);
}
}
return success;
}
bool OctreePacketData::appendValue(const glm::quat& value) {
const size_t VALUES_PER_QUAT = 4;
const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT;
@ -774,6 +787,15 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto
return (dataBytes - start) + (int)sizeof(uint16_t);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVector<QUuid>& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(uint16_t));
dataBytes += sizeof(length);
result.resize(length);
memcpy(result.data(), dataBytes, length * sizeof(QUuid));
return sizeof(uint16_t) + length * sizeof(QUuid);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));

View file

@ -186,6 +186,9 @@ public:
/// appends a QVector of bools to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QVector<bool>& value);
/// appends a QVector of QUuids to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QVector<QUuid>& value);
/// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::quat& value);
@ -284,6 +287,7 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<glm::quat>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<float>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<bool>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<QUuid>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, AACube& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QRect& result);

View file

@ -55,6 +55,13 @@ template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payl
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
template <> bool payloadPassesZoneOcclusionTest(const MeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (payload) {
return payload->passesZoneOcclusionTest(containingZones);
}
return false;
}
}
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material, const uint64_t& created) :
@ -167,10 +174,23 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setInputStream(0, _drawMesh->getVertexStream());
}
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
batch.setModelTransform(_drawTransform);
}
bool MeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
if (!_renderWithZones.isEmpty()) {
if (!containingZones.empty()) {
for (auto renderWithZone : _renderWithZones) {
if (containingZones.find(renderWithZone) != containingZones.end()) {
return true;
}
}
}
return false;
}
return true;
}
void MeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("MeshPartPayload::render");
@ -242,6 +262,12 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren
return payload->render(args);
}
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (payload) {
return payload->passesZoneOcclusionTest(containingZones);
}
return false;
}
}
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex,

View file

@ -75,11 +75,15 @@ public:
void setCullWithParent(bool value) { _cullWithParent = value; }
void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
static bool enableMaterialProceduralShaders;
protected:
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
bool _cullWithParent { false };
QVector<QUuid> _renderWithZones;
uint64_t _created;
};
@ -88,6 +92,7 @@ namespace render {
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload);
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
template <> bool payloadPassesZoneOcclusionTest(const MeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
}
class ModelMeshPartPayload : public MeshPartPayload {
@ -154,6 +159,7 @@ namespace render {
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload);
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);
}
#endif // hifi_MeshPartPayload_h

View file

@ -976,6 +976,16 @@ void Model::setCullWithParent(bool cullWithParent) {
}
}
void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
render::Transaction transaction;
for(auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderWithZones](ModelMeshPartPayload& data) {
data.setRenderWithZones(renderWithZones);
});
}
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
}
const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
return _renderItemKeyGlobalFlags;
}

View file

@ -131,6 +131,8 @@ public:
void setCullWithParent(bool value);
void setRenderWithZones(const QVector<QUuid>& renderWithZones);
// 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;

View file

@ -13,15 +13,16 @@
#include <functional>
#include <memory>
#include <stack>
#include <unordered_set>
#include <GLMHelpers.h>
#include <ViewFrustum.h>
#include <StencilMaskMode.h>
#include <UUIDHasher.h>
#include <gpu/Forward.h>
#include "Forward.h"
class AABox;
namespace render {
@ -142,13 +143,6 @@ namespace render {
bool _takingSnapshot { false };
StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE };
std::function<void(gpu::Batch&)> _stencilMaskOperator;
float _visionSqueezeX { 0.0f };
float _visionSqueezeY { 0.0f };
float _visionSqueezeTransition { 0.15f };
int _visionSqueezePerEye { 0 };
float _visionSqueezeGroundPlaneY { 0.0f };
float _visionSqueezeSpotlightSize { 0.02f };
};
}

View file

@ -19,6 +19,9 @@
using namespace render;
std::unordered_set<QUuid> CullTest::_containingZones = std::unordered_set<QUuid>();
std::unordered_set<QUuid> CullTest::_prevContainingZones = std::unordered_set<QUuid>();
CullTest::CullTest(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails, ViewFrustumPointer antiFrustum) :
_functor(functor),
_args(pargs),
@ -64,46 +67,8 @@ bool CullTest::solidAngleTest(const AABox& bound) {
return true;
}
void render::cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
const ItemBounds& inItems, ItemBounds& outItems) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
RenderArgs* args = renderContext->args;
const ViewFrustum& frustum = args->getViewFrustum();
details._considered += (int)inItems.size();
// Culling / LOD
for (auto item : inItems) {
if (item.bound.isNull()) {
outItems.emplace_back(item); // One more Item to render
continue;
}
// TODO: some entity types (like lights) might want to be rendered even
// when they are outside of the view frustum...
bool inView;
{
PerformanceTimer perfTimer("boxIntersectsFrustum");
inView = frustum.boxIntersectsFrustum(item.bound);
}
if (inView) {
bool bigEnoughToRender;
{
PerformanceTimer perfTimer("shouldRender");
bigEnoughToRender = cullFunctor(args, item.bound);
}
if (bigEnoughToRender) {
outItems.emplace_back(item); // One more Item to render
} else {
details._tooSmall++;
}
} else {
details._outOfView++;
}
}
details._rendered += (int)outItems.size();
bool CullTest::zoneOcclusionTest(const render::Item& item) {
return item.passesZoneOcclusionTest(_containingZones);
}
void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems) {
@ -117,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())) {
if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) {
outItems.emplace_back(ItemBound(id, item.getBound()));
}
}
@ -126,7 +91,6 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const
void FetchSpatialTree::configure(const Config& config) {
_justFrozeFrustum = _justFrozeFrustum || (config.freezeFrustum && !_freezeFrustum);
_freezeFrustum = config.freezeFrustum;
_lodAngle = config.lodAngle;
}
void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemSpatialTree::ItemSelection& outSelection) {
@ -215,7 +179,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
@ -230,7 +194,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
@ -245,7 +209,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
@ -260,7 +224,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
@ -277,7 +241,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
@ -292,7 +256,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
if (test.solidAngleTest(itemBound.bound)) {
outItems.emplace_back(itemBound);
@ -309,7 +273,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())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
if (test.frustumTest(itemBound.bound)) {
outItems.emplace_back(itemBound);
@ -326,14 +290,12 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("partialSmallItems");
for (auto id : inSelection.partialSubcellItems) {
auto& item = scene->getItem(id);
if (filter.test(item.getKey())) {
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
ItemBound itemBound(id, item.getBound());
if (test.frustumTest(itemBound.bound)) {
if (test.solidAngleTest(itemBound.bound)) {
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
item.fetchMetaSubItemBounds(outItems, (*scene));
}
if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) {
outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) {
item.fetchMetaSubItemBounds(outItems, (*scene));
}
}
}
@ -444,3 +406,13 @@ void ApplyCullFunctorOnItemBounds::run(const RenderContextPointer& renderContext
args->popViewFrustum();
}
}
void ClearContainingZones::run(const RenderContextPointer& renderContext) {
// This is a bit of a hack. We want to do zone culling as early as possible, so we do it
// during the RenderFetchCullSortTask (in CullSpatialSelection and FetchNonspatialItems),
// but the zones aren't collected until after (in SetupZones). To get around this,
// we actually use the zones from the previous frame to render, and then clear at the beginning
// of the next frame
CullTest::_prevContainingZones = CullTest::_containingZones;
CullTest::_containingZones.clear();
}

View file

@ -19,9 +19,6 @@ namespace render {
using CullFunctor = std::function<bool(const RenderArgs*, const AABox&)>;
void cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
const ItemBounds& inItems, ItemBounds& outItems);
// Culling Frustum / solidAngle test helper class
struct CullTest {
CullFunctor _functor;
@ -36,6 +33,10 @@ namespace render {
bool frustumTest(const AABox& bound);
bool antiFrustumTest(const AABox& bound);
bool solidAngleTest(const AABox& bound);
bool zoneOcclusionTest(const render::Item& item);
static std::unordered_set<QUuid> _containingZones;
static std::unordered_set<QUuid> _prevContainingZones;
};
class FetchNonspatialItems {
@ -48,7 +49,6 @@ namespace render {
Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems)
Q_PROPERTY(bool freezeFrustum MEMBER freezeFrustum WRITE setFreezeFrustum)
Q_PROPERTY(float LODAngle MEMBER lodAngle NOTIFY dirty)
public:
int numItems{ 0 };
@ -56,7 +56,6 @@ namespace render {
bool freezeFrustum{ false };
float lodAngle{ 2.0 };
public slots:
void setFreezeFrustum(bool enabled) { freezeFrustum = enabled; emit dirty(); }
@ -68,7 +67,6 @@ namespace render {
bool _freezeFrustum{ false }; // initialized by Config
bool _justFrozeFrustum{ false };
ViewFrustum _frozenFrustum;
float _lodAngle;
public:
using Config = FetchSpatialTreeConfig;
@ -159,6 +157,12 @@ namespace render {
render::CullFunctor _cullFunctor;
};
class ClearContainingZones {
public:
using JobModel = Job::Model<ClearContainingZones>;
void run(const RenderContextPointer& renderContext);
};
}
#endif // hifi_render_CullTask_h;

View file

@ -154,4 +154,10 @@ namespace render {
return payload->metaFetchMetaSubItems(subItems);
}
template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (!payload) {
return false;
}
return payload->passesZoneOcclusionTest(containingZones);
}
}

View file

@ -436,6 +436,8 @@ public:
virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0;
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
~PayloadInterface() {}
// Status interface is local to the base class
@ -487,6 +489,8 @@ public:
uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); }
uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const;
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); }
// Access the status
const StatusPointer& getStatus() const { return _payload->getStatus(); }
@ -537,6 +541,10 @@ template <class T> const ShapeKey shapeGetShapeKey(const std::shared_ptr<T>& pay
// Meta items act as the grouping object for several sub items (typically shapes).
template <class T> uint32_t metaFetchMetaSubItems(const std::shared_ptr<T>& payloadData, ItemIDs& subItems) { return 0; }
// Zone Occlusion Interface
// 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; }
// 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"
@ -561,6 +569,8 @@ public:
// Meta Type Interface
virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems<T>(_data, subItems); }
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override { return payloadPassesZoneOcclusionTest<T>(_data, containingZones); }
protected:
DataPointer _data;
@ -615,6 +625,7 @@ public:
virtual Item::Bound getBound() = 0;
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;
};
template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload);
@ -622,7 +633,7 @@ template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Point
template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
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);
typedef Item::PayloadPointer PayloadPointer;
typedef std::vector<PayloadPointer> Payloads;

View file

@ -74,6 +74,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
const auto filteredLayeredOpaque = task.addJob<FilterLayeredItems>("FilterLayeredOpaque", layeredOpaques, ItemKey::Layer::LAYER_1);
const auto filteredLayeredTransparent = task.addJob<FilterLayeredItems>("FilterLayeredTransparent", layeredTransparents, ItemKey::Layer::LAYER_1);
task.addJob<ClearContainingZones>("ClearContainingZones");
output = Output(BucketList{ opaques, transparents, lights, metas,
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(0), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(0),

View file

@ -36,6 +36,7 @@ int qVectorVec3MetaTypeId = qRegisterMetaType<QVector<glm::vec3>>();
int qVectorQuatMetaTypeId = qRegisterMetaType<QVector<glm::quat>>();
int qVectorBoolMetaTypeId = qRegisterMetaType<QVector<bool>>();
int qVectorGLMUint32MetaTypeId = qRegisterMetaType<QVector<unsigned int>>("QVector<glm::uint32>");
int qVectorQUuidMetaTypeId = qRegisterMetaType<QVector<QUuid>>();
int quatMetaTypeId = qRegisterMetaType<glm::quat>();
int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
int collisionMetaTypeId = qRegisterMetaType<Collision>();
@ -58,6 +59,7 @@ void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue);
qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue);
qScriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue);
qScriptRegisterMetaType(engine, qVectorQUuidToScriptValue, qVectorQUuidFromScriptValue);
qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue);
qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
@ -874,6 +876,22 @@ QVector<float> qVectorFloatFromScriptValue(const QScriptValue& array) {
return newVector;
}
QScriptValue qVectorQUuidToScriptValue(QScriptEngine* engine, const QVector<QUuid>& vector) {
QScriptValue array = engine->newArray();
for (int i = 0; i < vector.size(); i++) {
array.setProperty(i, quuidToScriptValue(engine, vector.at(i)));
}
return array;
}
void qVectorQUuidFromScriptValue(const QScriptValue& array, QVector<QUuid>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
vector << array.property(i).toVariant().toUuid();
}
}
QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array) {
if (!array.isArray()) {
return QVector<QUuid>();

View file

@ -247,6 +247,8 @@ QVector<float> qVectorFloatFromScriptValue(const QScriptValue& array);
QScriptValue qVectorIntToScriptValue(QScriptEngine* engine, const QVector<uint32_t>& vector);
void qVectorIntFromScriptValue(const QScriptValue& array, QVector<uint32_t>& vector);
QScriptValue qVectorQUuidToScriptValue(QScriptEngine* engine, const QVector<QUuid>& vector);
void qVectorQUuidFromScriptValue(const QScriptValue& array, QVector<QUuid>& vector);
QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array);
QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube);