Merge pull request #12649 from samcake/punk

Fix addressing the avatar mesh visibility switch bug
This commit is contained in:
Sam Gateau 2018-05-31 14:16:04 -07:00 committed by GitHub
commit 46d055a488
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 384 additions and 335 deletions

View file

@ -104,6 +104,9 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
_myAvatar->update(deltaTime);
render::Transaction transaction;
_myAvatar->updateRenderItem(transaction);
qApp->getMain3DScene()->enqueueTransaction(transaction);
quint64 now = usecTimestampNow();
quint64 dt = now - _lastSendAvatarDataTime;

View file

@ -1127,7 +1127,11 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
}
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
return Avatar::setEnableMeshVisible(isEnabled);
}
bool MyAvatar::getEnableMeshVisible() const {
return Avatar::getEnableMeshVisible();
}
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@ -1479,7 +1483,10 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
_skeletonModelChangeCount++;
int skeletonModelChangeCount = _skeletonModelChangeCount;
Avatar::setSkeletonModelURL(skeletonModelURL);
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
_skeletonModel->setTagMask(render::hifi::TAG_NONE);
_skeletonModel->setGroupCulled(true);
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
_headBoneSet.clear();
_cauterizationNeedsUpdate = true;
@ -2054,14 +2061,12 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
uint8_t modelRenderTagBits = shouldDrawHead ? render::ItemKey::TAG_BITS_0 : render::ItemKey::TAG_BITS_NONE;
modelRenderTagBits |= render::ItemKey::TAG_BITS_1;
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene(),
modelRenderTagBits, false);
uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW;
uint8_t castShadowRenderTagBits = render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1;
_attachmentModels[i]->setCanCastShadow(true, qApp->getMain3DScene(),
castShadowRenderTagBits, false);
_attachmentModels[i]->setTagMask(modelRenderTagBits);
_attachmentModels[i]->setGroupCulled(false);
_attachmentModels[i]->setCanCastShadow(true);
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene());
}
}
}

View file

@ -1159,7 +1159,7 @@ public slots:
* @function MyAvatar.getEnableMeshVisible
* @returns {boolean} <code>true</code> if your avatar's mesh is visible, otherwise <code>false</code>.
*/
bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); }
bool getEnableMeshVisible() const override;
/**jsdoc
* Set whether or not your avatar mesh is visible.
@ -1171,7 +1171,7 @@ public slots:
* MyAvatar.setEnableMeshVisible(true);
* }, 10000);
*/
void setEnableMeshVisible(bool isEnabled);
virtual void setEnableMeshVisible(bool isEnabled) override;
/**jsdoc
* @function MyAvatar.setEnableInverseKinematics

View file

@ -103,10 +103,9 @@ void ModelOverlay::update(float deltatime) {
if (_visibleDirty) {
_visibleDirty = false;
// don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true
_model->setVisibleInScene(getVisible(), scene,
render::ItemKey::TAG_BITS_0 |
(_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE),
false);
uint8_t modelRenderTagMask = (_isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW);
_model->setTagMask(modelRenderTagMask, scene);
_model->setVisibleInScene(getVisible(), scene);
}
if (_drawInFrontDirty) {
_drawInFrontDirty = false;

View file

@ -132,7 +132,6 @@ private:
namespace render {
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
template <> int payloadGetLayer(const Overlay::Pointer& overlay);
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);

View file

@ -35,14 +35,18 @@ namespace render {
auto builder = ItemKey::Builder().withTypeShape();
if (overlay->is3D()) {
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
if (overlay3D->getDrawInFront() || overlay3D->getDrawHUDLayer()) {
builder.withLayered();
if (overlay3D->getDrawInFront()) {
builder.withLayer(render::hifi::LAYER_3D_FRONT);
} else if (overlay3D->getDrawHUDLayer()) {
builder.withLayer(render::hifi::LAYER_3D_HUD);
}
if (overlay->isTransparent()) {
builder.withTransparent();
}
} else {
builder.withViewSpace();
builder.withLayer(render::hifi::LAYER_2D);
}
if (!overlay->getVisible()) {
@ -50,30 +54,16 @@ namespace render {
}
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 |
(overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE);
uint32_t viewTagBits = render::hifi::TAG_MAIN_VIEW |
(overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE);
builder.withTagBits(viewTaskBits);
builder.withTagBits(viewTagBits);
return builder.build();
}
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
return overlay->getBounds();
}
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
if (overlay->is3D()) {
auto overlay3D = std::dynamic_pointer_cast<Base3DOverlay>(overlay);
if (overlay3D->getDrawInFront()) {
return Item::LAYER_3D_FRONT;
} else if (overlay3D->getDrawHUDLayer()) {
return Item::LAYER_3D_HUD;
} else {
return Item::LAYER_3D;
}
} else {
return Item::LAYER_2D;
}
}
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
if (args) {
overlay->render(args);
@ -83,7 +73,6 @@ namespace render {
return overlay->getShapeKey();
}
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) {
return overlay->fetchMetaSubItems(subItems);
}

View file

@ -52,10 +52,15 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup();
ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::hifi::TAG_ALL_VIEWS).withMetaCullGroup();
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
if (!avatarPtr->getEnableMeshVisible()) {
keyBuilder.withInvisible();
}
return keyBuilder.build();
}
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
return static_pointer_cast<Avatar>(avatar)->getBounds();
return static_pointer_cast<Avatar>(avatar)->getRenderBounds();
}
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
@ -164,6 +169,11 @@ AABox Avatar::getBounds() const {
return _skeletonModel->getRenderableMeshBound();
}
AABox Avatar::getRenderBounds() const {
return _renderBound;
}
void Avatar::animateScaleChanges(float deltaTime) {
if (_isAnimatingScale) {
@ -569,16 +579,26 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
auto avatarPayload = new render::Payload<AvatarData>(self);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
auto avatarPayloadPointer = std::shared_ptr<render::Payload<AvatarData>>(avatarPayload);
if (_renderItemID == render::Item::INVALID_ITEM_ID) {
_renderItemID = scene->allocateID();
}
// INitialize the _render bound as we are creating the avatar render item
_renderBound = getBounds();
transaction.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel->addToScene(scene, transaction);
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
_skeletonModel->setGroupCulled(true);
_skeletonModel->setCanCastShadow(true);
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
processMaterials();
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->addToScene(scene, transaction);
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
attachmentModel->setGroupCulled(false);
attachmentModel->setCanCastShadow(true);
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
}
_mustFadeIn = true;
@ -637,7 +657,15 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe
void Avatar::updateRenderItem(render::Transaction& transaction) {
if (render::Item::isValidID(_renderItemID)) {
transaction.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
auto renderBound = getBounds();
transaction.updateItem<AvatarData>(_renderItemID,
[renderBound](AvatarData& avatar) {
auto avatarPtr = dynamic_cast<Avatar*>(&avatar);
if (avatarPtr) {
avatarPtr->_renderBound = renderBound;
}
}
);
}
}
@ -759,6 +787,18 @@ void Avatar::render(RenderArgs* renderArgs) {
}
}
void Avatar::setEnableMeshVisible(bool isEnabled) {
if (_isMeshVisible != isEnabled) {
_isMeshVisible = isEnabled;
_needMeshVisibleSwitch = true;
}
}
bool Avatar::getEnableMeshVisible() const {
return _isMeshVisible;
}
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
bool canTryFade{ false };
@ -770,6 +810,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
_skeletonModel->removeFromScene(scene, transaction);
_skeletonModel->addToScene(scene, transaction);
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
_skeletonModel->setGroupCulled(true);
_skeletonModel->setCanCastShadow(true);
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
processMaterials();
canTryFade = true;
_isAnimatingScale = true;
@ -778,9 +824,25 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
attachmentModel->removeFromScene(scene, transaction);
attachmentModel->addToScene(scene, transaction);
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
attachmentModel->setGroupCulled(false);
attachmentModel->setCanCastShadow(true);
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
}
}
if (_needMeshVisibleSwitch) {
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
for (auto attachmentModel : _attachmentModels) {
if (attachmentModel->isRenderable()) {
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
}
}
updateRenderItem(transaction);
_needMeshVisibleSwitch = false;
}
if (_mustFadeIn && canTryFade) {
// Do it now to be sure all the sub items are ready and the fade is sent to them too
fade(transaction, render::Transition::USER_ENTER_DOMAIN);

View file

@ -74,7 +74,6 @@ public:
virtual void instantiableAvatar() = 0;
typedef render::Payload<AvatarData> Payload;
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
void init();
void updateAvatarEntities();
@ -322,6 +321,7 @@ public:
bool hasNewJointData() const { return _hasNewJointData; }
float getBoundingRadius() const;
AABox getRenderBounds() const; // THis call is accessible from rendering thread only to report the bounding box of the avatar during the frame.
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
@ -356,6 +356,10 @@ public:
virtual void setAvatarEntityDataChanged(bool value) override;
// Show hide the model representation of the avatar
virtual void setEnableMeshVisible(bool isEnabled);
virtual bool getEnableMeshVisible() const;
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
@ -532,6 +536,10 @@ protected:
std::mutex _materialsLock;
void processMaterials();
AABox _renderBound;
bool _isMeshVisible{ true };
bool _needMeshVisibleSwitch{ true };
};
#endif // hifi_Avatar_h

View file

@ -35,7 +35,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
_useDualQuaternionSkinning = true;
// Avatars all cast shadow
_canCastShadow = true;
setCanCastShadow(true);
assert(_owningAvatar);
}

View file

@ -1387,20 +1387,25 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->stopModelOverrideIfNoParent();
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
uint32_t viewTaskBits = _cauterized ?
render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero)
render::ItemKey::TAG_BITS_ALL; // draw in all views
auto tagMask = _cauterized ?
render::hifi::TAG_SECONDARY_VIEW : // draw in every view except the main one (view zero)
render::hifi::TAG_ALL_VIEWS; // draw in all views
if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
if (model->isVisible() != _visible) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
// the renderable item. As it stands now the model checks it's visible/invisible state
// so most of the time we don't do anything in this function.
model->setVisibleInScene(_visible, scene, viewTaskBits, false);
model->setVisibleInScene(_visible, scene);
}
if (model->getTagMask() != tagMask) {
model->setTagMask(tagMask, scene);
}
// TODO? early exit here when not visible?
if (model->canCastShadow() != _canCastShadow) {
model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false);
model->setCanCastShadow(_canCastShadow, scene);
}
if (_needsCollisionGeometryUpdate) {

View file

@ -215,10 +215,7 @@ void CauterizedModel::updateRenderItems() {
modelTransform.setRotation(self->getRotation());
bool isWireframe = self->isWireframe();
bool isVisible = self->isVisible();
bool canCastShadow = self->canCastShadow();
bool isLayeredInFront = self->isLayeredInFront();
bool isLayeredInHUD = self->isLayeredInHUD();
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
bool enableCauterization = self->getEnableCauterization();
render::Transaction transaction;
@ -234,7 +231,7 @@ void CauterizedModel::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) {
isWireframe, renderItemKeyGlobalFlags, enableCauterization](CauterizedMeshPartPayload& data) {
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions,
cauterizedMeshState.clusterDualQuaternions);
@ -276,8 +273,7 @@ void CauterizedModel::updateRenderItems() {
data.updateTransformForCauterizedMesh(renderTransform);
data.setEnableCauterization(enableCauterization);
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL);
data.setLayer(isLayeredInFront, isLayeredInHUD);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
});
}

View file

@ -79,28 +79,10 @@ void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
_drawMaterials.remove(material);
}
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) {
ItemKey::Builder builder;
void MeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder(key);
builder.withTypeShape();
if (!isVisible) {
builder.withInvisible();
}
builder.withTagBits(tagBits);
if (isLayered) {
builder.withLayered();
}
if (canCastShadow) {
builder.withShadowCaster();
}
if (isGroupCulled) {
builder.withSubMetaCulled();
}
if (topMaterialExists()) {
auto matKey = _drawMaterials.top().material->getKey();
if (matKey.isTranslucent()) {
@ -200,12 +182,6 @@ template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointe
}
return Item::Bound();
}
template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getLayer();
}
return 0;
}
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
@ -332,28 +308,10 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
}
// Note that this method is called for models but not for shapes
void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) {
ItemKey::Builder builder;
void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder(key);
builder.withTypeShape();
if (!isVisible) {
builder.withInvisible();
}
builder.withTagBits(tagBits);
if (isLayered) {
builder.withLayered();
}
if (canCastShadow) {
builder.withShadowCaster();
}
if (isGroupCulled) {
builder.withSubMetaCulled();
}
if (_isBlendShaped || _isSkinned) {
builder.withDeformed();
}
@ -368,20 +326,6 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas
_itemKey = builder.build();
}
void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
if (isLayeredInFront) {
_layer = Item::LAYER_3D_FRONT;
} else if (isLayeredInHUD) {
_layer = Item::LAYER_3D_HUD;
} else {
_layer = Item::LAYER_3D;
}
}
int ModelMeshPartPayload::getLayer() const {
return _layer;
}
void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning) {
if (invalidateShapeKey) {
_shapeKey = ShapeKey::Builder::invalid();

View file

@ -32,7 +32,7 @@ public:
typedef render::Payload<MeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
virtual void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false);
virtual void updateKey(const render::ItemKey& key);
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
@ -95,7 +95,7 @@ public:
void notifyLocationChanged() override;
void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false) override;
void updateKey(const render::ItemKey& key) override;
// matrix palette skinning
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
@ -105,11 +105,9 @@ public:
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface
int getLayer() const;
render::ShapeKey getShapeKey() const override; // shape interface
void render(RenderArgs* args) override;
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning);
// ModelMeshPartPayload functions to perform render
@ -139,13 +137,11 @@ private:
gpu::BufferPointer _blendedVertexBuffer;
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
int _layer { render::Item::LAYER_3D };
};
namespace render {
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload);
template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload);
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
}

View file

@ -103,11 +103,10 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
_snapModelToRegistrationPoint(false),
_snappedToRegistrationPoint(false),
_url(HTTP_INVALID_COM),
_isVisible(true),
_canCastShadow(false),
_blendNumber(0),
_appliedBlendNumber(0),
_isWireframe(false)
_isWireframe(false),
_renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build())
{
// we may have been created in the network thread, but we live in the main thread
if (_viewState) {
@ -268,12 +267,7 @@ void Model::updateRenderItems() {
modelTransform.setScale(glm::vec3(1.0f));
bool isWireframe = self->isWireframe();
bool isVisible = self->isVisible();
bool canCastShadow = self->canCastShadow();
uint8_t viewTagBits = self->getViewTagBits();
bool isLayeredInFront = self->isLayeredInFront();
bool isLayeredInHUD = self->isLayeredInHUD();
bool isGroupCulled = self->isGroupCulled();
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
render::Transaction transaction;
for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
@ -287,9 +281,7 @@ void Model::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, isWireframe, isVisible,
canCastShadow, viewTagBits, isLayeredInFront,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
invalidatePayloadShapeKey, isWireframe, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions);
} else {
@ -313,8 +305,7 @@ void Model::updateRenderItems() {
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
data.setLayer(isLayeredInFront, isLayeredInHUD);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
});
}
@ -322,8 +313,9 @@ void Model::updateRenderItems() {
Transform collisionMeshOffset;
collisionMeshOffset.setIdentity();
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
transaction.updateItem<MeshPartPayload>(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) {
transaction.updateItem<MeshPartPayload>(itemID, [renderItemKeyGlobalFlags, modelTransform, collisionMeshOffset](MeshPartPayload& data) {
// update the model transform for this render item.
data.updateKey(renderItemKeyGlobalFlags);
data.updateTransform(modelTransform, collisionMeshOffset);
});
}
@ -773,110 +765,100 @@ void Model::calculateTriangleSets(const FBXGeometry& geometry) {
}
}
void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) {
if (_isVisible != isVisible || _viewTagBits != viewTagBits || _isGroupCulled != isGroupCulled) {
_isVisible = isVisible;
_viewTagBits = viewTagBits;
_isGroupCulled = isGroupCulled;
void Model::updateRenderItemsKey(const render::ScenePointer& scene) {
if (!scene) {
_needsFixupInScene = true;
return;
}
auto renderItemsKey = _renderItemKeyGlobalFlags;
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
data.updateKey(renderItemsKey);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
data.updateKey(renderItemsKey);
});
}
scene->enqueueTransaction(transaction);
}
bool isLayeredInFront = _isLayeredInFront;
bool isLayeredInHUD = _isLayeredInHUD;
bool canCastShadow = _canCastShadow;
render::Transaction transaction;
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
});
}
scene->enqueueTransaction(transaction);
void Model::setVisibleInScene(bool visible, const render::ScenePointer& scene) {
if (Model::isVisible() != visible) {
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = (visible ? keyBuilder.withVisible() : keyBuilder.withInvisible());
updateRenderItemsKey(scene);
}
}
void Model::setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) {
if (_canCastShadow != canCastShadow) {
_canCastShadow = canCastShadow;
bool Model::isVisible() const {
return _renderItemKeyGlobalFlags.isVisible();
}
bool isVisible = _isVisible;
bool isLayeredInFront = _isLayeredInFront;
bool isLayeredInHUD = _isLayeredInHUD;
render::Transaction transaction;
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item,
[isVisible, viewTagBits, canCastShadow, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, viewTagBits, canCastShadow, isLayeredInFront || isLayeredInHUD, isGroupCulled);
});
}
scene->enqueueTransaction(transaction);
void Model::setCanCastShadow(bool castShadow, const render::ScenePointer& scene) {
if (Model::canCastShadow() != castShadow) {
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = (castShadow ? keyBuilder.withShadowCaster() : keyBuilder.withoutShadowCaster());
updateRenderItemsKey(scene);
}
}
void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) {
if (_isLayeredInFront != isLayeredInFront) {
_isLayeredInFront = isLayeredInFront;
bool Model::canCastShadow() const {
return _renderItemKeyGlobalFlags.isShadowCaster();
}
bool isVisible = _isVisible;
bool canCastShadow = _canCastShadow;
uint8_t viewTagBits = _viewTagBits;
bool isLayeredInHUD = _isLayeredInHUD;
bool isGroupCulled = _isGroupCulled;
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
scene->enqueueTransaction(transaction);
void Model::setLayeredInFront(bool layeredInFront, const render::ScenePointer& scene) {
if (Model::isLayeredInFront() != layeredInFront) {
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = (layeredInFront ? keyBuilder.withLayer(render::hifi::LAYER_3D_FRONT) : keyBuilder.withoutLayer());
updateRenderItemsKey(scene);
}
}
void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene) {
if (_isLayeredInHUD != isLayeredInHUD) {
_isLayeredInHUD = isLayeredInHUD;
bool Model::isLayeredInFront() const {
return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_FRONT);
}
bool isVisible = _isVisible;
bool canCastShadow = _canCastShadow;
uint8_t viewTagBits = _viewTagBits;
bool isLayeredInFront = _isLayeredInFront;
bool isGroupCulled = _isGroupCulled;
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
scene->enqueueTransaction(transaction);
void Model::setLayeredInHUD(bool layeredInHUD, const render::ScenePointer& scene) {
if (Model::isLayeredInHUD() != layeredInHUD) {
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = (layeredInHUD ? keyBuilder.withLayer(render::hifi::LAYER_3D_HUD) : keyBuilder.withoutLayer());
updateRenderItemsKey(scene);
}
}
bool Model::isLayeredInHUD() const {
return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_HUD);
}
void Model::setTagMask(uint8_t mask, const render::ScenePointer& scene) {
if (Model::getTagMask() != mask) {
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = keyBuilder.withTagBits(mask);
updateRenderItemsKey(scene);
}
}
render::hifi::Tag Model::getTagMask() const {
return (render::hifi::Tag) _renderItemKeyGlobalFlags.getTagBits();
}
void Model::setGroupCulled(bool groupCulled, const render::ScenePointer& scene) {
if (Model::isGroupCulled() != groupCulled) {
auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = (groupCulled ? keyBuilder.withSubMetaCulled() : keyBuilder.withoutSubMetaCulled());
updateRenderItemsKey(scene);
}
}
bool Model::isGroupCulled() const {
return _renderItemKeyGlobalFlags.isSubMetaCulled();
}
const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
return _renderItemKeyGlobalFlags;
}
bool Model::addToScene(const render::ScenePointer& scene,
render::Transaction& transaction,
render::Item::Status::Getters& statusGetters) {
@ -1676,20 +1658,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
for (auto shapeID : shapeIDs) {
if (shapeID < _modelMeshRenderItemIDs.size()) {
auto itemID = _modelMeshRenderItemIDs[shapeID];
bool visible = isVisible();
uint8_t viewTagBits = getViewTagBits();
bool layeredInFront = isLayeredInFront();
bool layeredInHUD = isLayeredInHUD();
bool canCastShadow = _canCastShadow;
auto renderItemsKey = _renderItemKeyGlobalFlags;
bool wireframe = isWireframe();
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow,
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
data.addMaterial(material);
// if the material changed, we might need to update our item key or shape key
data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits);
data.updateKey(renderItemsKey);
data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
});
}
@ -1704,19 +1682,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
if (shapeID < _modelMeshRenderItemIDs.size()) {
auto itemID = _modelMeshRenderItemIDs[shapeID];
bool visible = isVisible();
uint8_t viewTagBits = getViewTagBits();
bool layeredInFront = isLayeredInFront();
bool layeredInHUD = isLayeredInHUD();
bool canCastShadow = _canCastShadow;
auto renderItemsKey = _renderItemKeyGlobalFlags;
bool wireframe = isWireframe();
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow,
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, renderItemsKey,
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
data.removeMaterial(material);
// if the material changed, we might need to update our item key or shape key
data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits);
data.updateKey(renderItemsKey);
data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
});
}

View file

@ -33,6 +33,7 @@
#include <TriangleSet.h>
#include <DualQuaternion.h>
#include "RenderHifi.h"
#include "GeometryCache.h"
#include "TextureCache.h"
#include "Rig.h"
@ -87,13 +88,27 @@ public:
const QUrl& getURL() const { return _url; }
// new Scene/Engine rendering support
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled);
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene = nullptr);
bool isVisible() const;
bool canCastShadow() const { return _canCastShadow; }
void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled);
render::hifi::Tag getTagMask() const;
void setTagMask(uint8_t mask, const render::ScenePointer& scene = nullptr);
bool isGroupCulled() const;
void setGroupCulled(bool isGroupCulled, const render::ScenePointer& scene = nullptr);
bool canCastShadow() const;
void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene = nullptr);
void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene = nullptr);
void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene = nullptr);
bool isLayeredInFront() const;
bool isLayeredInHUD() const;
// 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;
void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
bool needsFixupInScene() const;
bool needsReload() const { return _needsReload; }
@ -108,13 +123,7 @@ public:
void removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction);
bool isRenderable() const;
bool isVisible() const { return _isVisible; }
uint8_t getViewTagBits() const { return _viewTagBits; }
bool isLayeredInFront() const { return _isLayeredInFront; }
bool isLayeredInHUD() const { return _isLayeredInHUD; }
bool isGroupCulled() const { return _isGroupCulled; }
void updateRenderItemsKey(const render::ScenePointer& scene);
virtual void updateRenderItems();
void setRenderItemsNeedUpdate();
@ -404,10 +413,6 @@ protected:
QVector<float> _blendshapeCoefficients;
QUrl _url;
bool _isVisible;
uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL };
bool _canCastShadow;
gpu::Buffers _blendedVertexBuffers;
@ -471,10 +476,16 @@ protected:
int _renderInfoDrawCalls { 0 };
int _renderInfoHasTransparent { false };
bool _isLayeredInFront { false };
bool _isLayeredInHUD { false };
bool _isGroupCulled{ false };
// This Render ItemKey Global Flags capture the Model wide global set of flags that should be communicated to all the render items representing the Model.
// The flags concerned are:
// - isVisible: if true the Model is visible globally in the scene, regardless of the other flags in the item keys (tags or layer or shadow caster).
// - TagBits: the view mask defined through the TagBits telling in which view the Model is rendered if visible.
// - Layer: In which Layer this Model lives.
// - CastShadow: if true and visible and rendered in the view, the Model cast shadows if in a Light volume casting shadows.
// - CullGroup: if true, the render items representing the parts of the Model are culled by a single Meta render item that knows about them, they are not culled individually.
// For this to work, a Meta RI must exists and knows about the RIs of this Model.
//
render::ItemKey _renderItemKeyGlobalFlags;
bool shouldInvalidatePayloadShapeKey(int meshIndex);

View file

@ -27,6 +27,7 @@
#include <render/DrawSceneOctree.h>
#include <render/BlurTask.h>
#include "RenderHifi.h"
#include "RenderCommonTask.h"
#include "LightingModel.h"
#include "StencilMaskPass.h"
@ -200,8 +201,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto overlaysInFrontRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOverlaysInFrontRangeTimer", "BeginOverlaysInFrontRangeTimer");
// Layered Overlays
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT);
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);

View file

@ -23,6 +23,7 @@
#include <render/FilterTask.h>
#include "RenderHifi.h"
#include "StencilMaskPass.h"
#include "ZoneRenderer.h"
#include "FadeEffect.h"
@ -79,8 +80,8 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
task.addJob<PrepareStencil>("PrepareStencil", framebuffer);
// Layered Overlays
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT);
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);

View file

@ -0,0 +1,43 @@
//
// RenderHifi.h
// libraries/render-utils/src
//
// Created by Sam Gateau on 5/30/2018.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RenderHifi_h
#define hifi_RenderHifi_h
#include <render/Item.h>
// In the library render-utils we are specializing the generic components of the render library to create the custom hifi render engine
// Objects and types serving this goal are define in the namespace render.hifi
// TODO: extend the namespace to all the classes where it make sense in render-utils
namespace render {
namespace hifi {
// Tag is the alias names of render::ItemKey::Tag combinations used in the Hifi Render Engine
enum Tag : uint8_t {
TAG_NONE = render::ItemKey::TAG_BITS_NONE, // No Tags at all
TAG_MAIN_VIEW = render::ItemKey::TAG_BITS_0, // Main view
TAG_SECONDARY_VIEW = render::ItemKey::TAG_BITS_1, // Secondary View
TAG_ALL_VIEWS = TAG_MAIN_VIEW | TAG_SECONDARY_VIEW, // All views
};
// Layer is the alias names of the render::ItemKey::Layer used in the Hifi Render Engine
enum Layer : uint8_t {
LAYER_3D = render::ItemKey::LAYER_DEFAULT,
LAYER_3D_FRONT = render::ItemKey::LAYER_1,
LAYER_3D_HUD = render::ItemKey::LAYER_2,
LAYER_2D = render::ItemKey::LAYER_3,
LAYER_BACKGROUND = render::ItemKey::LAYER_BACKGROUND,
};
}
}
#endif // hifi_RenderHifi_h

View file

@ -368,9 +368,9 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
RenderArgs* args = renderContext->args;
const auto& inShapes = inputs.get0();
const auto& cullFilter = inputs.get1();
const auto& boundsFilter = inputs.get2();
const auto& antiFrustum = inputs.get3();
const auto& cullFilter = inputs.get1();
const auto& boundsFilter = inputs.get2();
const auto& antiFrustum = inputs.get3();
auto& outShapes = outputs.edit0();
auto& outBounds = outputs.edit1();
@ -380,7 +380,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) {
auto& details = args->_details.edit(_detailType);
Test test(_cullFunctor, args, details, antiFrustum);
auto scene = args->_scene;
auto scene = args->_scene;
for (auto& inItems : inShapes) {
auto key = inItems.first;
@ -395,26 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
if (antiFrustum == nullptr) {
for (auto& item : inItems.second) {
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) {
const auto shapeKey = scene->getItem(item.id).getKey();
if (cullFilter.test(shapeKey)) {
outItems->second.emplace_back(item);
}
if (boundsFilter.test(shapeKey)) {
outBounds += item.bound;
}
const auto shapeKey = scene->getItem(item.id).getKey();
if (cullFilter.test(shapeKey)) {
outItems->second.emplace_back(item);
}
if (boundsFilter.test(shapeKey)) {
outBounds += item.bound;
}
}
}
} else {
for (auto& item : inItems.second) {
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) {
const auto shapeKey = scene->getItem(item.id).getKey();
if (cullFilter.test(shapeKey)) {
outItems->second.emplace_back(item);
}
if (boundsFilter.test(shapeKey)) {
outBounds += item.bound;
}
}
const auto shapeKey = scene->getItem(item.id).getKey();
if (cullFilter.test(shapeKey)) {
outItems->second.emplace_back(item);
}
if (boundsFilter.test(shapeKey)) {
outBounds += item.bound;
}
}
}
}
details._rendered += (int)outItems->second.size();
@ -487,6 +487,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
if (filter.test(item.getKey())) {
ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound);
}
}
}

View file

@ -29,25 +29,9 @@ const float Item::Status::Value::CYAN = 180.0f;
const float Item::Status::Value::BLUE = 240.0f;
const float Item::Status::Value::MAGENTA = 300.0f;
const int Item::LAYER_2D = 0;
const int Item::LAYER_3D = 1;
const int Item::LAYER_3D_FRONT = 2;
const int Item::LAYER_3D_HUD = 3;
const uint8_t ItemKey::TAG_BITS_ALL { 0xFF };
const uint8_t ItemKey::TAG_BITS_NONE { 0x00 };
const uint8_t ItemKey::TAG_BITS_0 { 0x01 };
const uint8_t ItemKey::TAG_BITS_1 { 0x02 };
const uint8_t ItemKey::TAG_BITS_2 { 0x04 };
const uint8_t ItemKey::TAG_BITS_3 { 0x08 };
const uint8_t ItemKey::TAG_BITS_4 { 0x10 };
const uint8_t ItemKey::TAG_BITS_5 { 0x20 };
const uint8_t ItemKey::TAG_BITS_6 { 0x40 };
const uint8_t ItemKey::TAG_BITS_7 { 0x80 };
const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT;
const uint32_t ItemKey::KEY_LAYER_BITS_MASK = ((uint32_t)ItemKey::LAYER_BITS_ALL) << FIRST_LAYER_BIT;
void Item::Status::Value::setScale(float scale) {
_scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));

View file

@ -52,23 +52,45 @@ public:
TAG_6,
TAG_7,
NUM_TAGS
NUM_TAGS,
// Tag bits are derived from the Tag enum
TAG_BITS_ALL = 0xFF,
TAG_BITS_NONE = 0x00,
TAG_BITS_0 = 0x01,
TAG_BITS_1 = 0x02,
TAG_BITS_2 = 0x04,
TAG_BITS_3 = 0x08,
TAG_BITS_4 = 0x10,
TAG_BITS_5 = 0x20,
TAG_BITS_6 = 0x40,
TAG_BITS_7 = 0x80,
};
// Items are organized in layers, an item belongs to one of the 8 Layers available.
// By default an item is in the 'LAYER_DEFAULT' meaning that it is NOT layered.
// THere is NO ordering relationship between layers.
enum Layer : uint8_t {
LAYER_DEFAULT = 0, // layer 0 aka Default is a 'NOT' layer, items are not considered layered, this is the default value
LAYER_1,
LAYER_2,
LAYER_3,
LAYER_4,
LAYER_5,
LAYER_6,
LAYER_BACKGROUND, // Last Layer is the background by convention
NUM_LAYERS,
// Layer bits are derived from the Layer enum, the number of bits needed to represent integer 0 to NUM_LAYERS
NUM_LAYER_BITS = 3,
LAYER_BITS_ALL = 0x07,
};
// Tag bits are derived from the Tag enum
const static uint8_t TAG_BITS_ALL;
const static uint8_t TAG_BITS_NONE;
const static uint8_t TAG_BITS_0;
const static uint8_t TAG_BITS_1;
const static uint8_t TAG_BITS_2;
const static uint8_t TAG_BITS_3;
const static uint8_t TAG_BITS_4;
const static uint8_t TAG_BITS_5;
const static uint8_t TAG_BITS_6;
const static uint8_t TAG_BITS_7;
enum FlagBit : uint32_t {
TYPE_SHAPE = 0, // Item is a Shape
TYPE_LIGHT, // Item is a Light
TYPE_SHAPE = 0, // Item is a Shape: Implements the Shape Interface that draw a Geometry rendered with a Material
TYPE_LIGHT, // Item is a Light: Implements the Light Interface that
TYPE_CAMERA, // Item is a Camera: Implements the Camera Interface
TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items
TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
@ -77,13 +99,15 @@ public:
DEFORMED, // Deformed within bound, not solid
INVISIBLE, // Visible or not in the scene?
SHADOW_CASTER, // Item cast shadows
LAYERED, // Item belongs to one of the layers different from the default layer
META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view
SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it
FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
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,
__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
@ -96,6 +120,12 @@ public:
return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT);
}
// All the bits touching layer bits sets to true
const static uint32_t KEY_LAYER_BITS_MASK;
static uint32_t evalLayerBitsWithKeyBits(uint8_t layer, const uint32_t keyBits) {
return (keyBits & ~KEY_LAYER_BITS_MASK) | (((uint32_t)layer & LAYER_BITS_ALL) << FIRST_LAYER_BIT);
}
// The key is the Flags
Flags _flags;
@ -124,19 +154,24 @@ public:
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); }
Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
Builder& withLayered() { _flags.set(LAYERED); return (*this); }
Builder& withoutShadowCaster() { _flags.reset(SHADOW_CASTER); return (*this); }
Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); }
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& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); }
// Set ALL the tags in one call using the Tag bits
Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); }
Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); }
Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); }
// Convenient standard keys that we will keep on using all over the place
static Builder opaqueShape() { return Builder().withTypeShape(); }
static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
static Builder light() { return Builder().withTypeLight(); }
static Builder background() { return Builder().withViewSpace().withLayered(); }
static Builder background() { return Builder().withViewSpace().withLayer(LAYER_BACKGROUND); }
};
ItemKey(const Builder& builder) : ItemKey(builder._flags) {}
@ -161,9 +196,6 @@ public:
bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
bool isLayered() const { return _flags[LAYERED]; }
bool isSpatial() const { return !isLayered(); }
bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; }
void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); }
@ -173,6 +205,11 @@ public:
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); }
uint8_t getLayer() const { return ((_flags.to_ulong() & KEY_LAYER_BITS_MASK) >> FIRST_LAYER_BIT); }
bool isLayer(uint8_t layer) const { return getLayer() == layer; }
bool isLayered() const { return getLayer() != LAYER_DEFAULT; }
bool isSpatial() const { return !isLayered(); }
// Probably not public, flags used by the scene
bool isSmall() const { return _flags[__SMALLER]; }
void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
@ -230,9 +267,6 @@ public:
Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); }
Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); }
@ -244,6 +278,9 @@ public:
// Set ALL the tags in one call using the Tag bits and the Tag bits touched
Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); }
Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); }
// Convenient standard keys that we will keep on using all over the place
@ -252,9 +289,7 @@ public:
static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
static Builder light() { return Builder().withTypeLight(); }
static Builder meta() { return Builder().withTypeMeta(); }
static Builder background() { return Builder().withViewSpace().withLayered(); }
static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); }
static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); }
static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); }
static Builder nothing() { return Builder().withNothing(); }
};
@ -377,7 +412,6 @@ public:
public:
virtual const ItemKey getKey() const = 0;
virtual const Bound getBound() const = 0;
virtual int getLayer() const = 0;
virtual void render(RenderArgs* args) = 0;
virtual const ShapeKey getShapeKey() const = 0;
@ -422,13 +456,8 @@ public:
// Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace())
const Bound getBound() const { return _payload->getBound(); }
// Get the layer where the item belongs.
int getLayer() const { return _payload->getLayer(); }
static const int LAYER_2D;
static const int LAYER_3D;
static const int LAYER_3D_FRONT;
static const int LAYER_3D_HUD;
// Get the layer where the item belongs, simply reflecting the key.
int getLayer() const { return _key.getLayer(); }
// Render call for the item
void render(RenderArgs* args) const { _payload->render(args); }
@ -478,7 +507,6 @@ inline QDebug operator<<(QDebug debug, const Item& item) {
// Item shared interface supported by the payload
template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); }
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData) { return Item::Bound(); }
template <class T> int payloadGetLayer(const std::shared_ptr<T>& payloadData) { return 0; }
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
// Shape type interface
@ -505,7 +533,6 @@ public:
// Payload general interface
virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); }
virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); }
virtual int getLayer() const override { return payloadGetLayer<T>(_data); }
virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }

View file

@ -48,6 +48,6 @@ bool blockingInvokeMethod(
} }
#define BLOCKING_INVOKE_METHOD(obj, member, ...) \
hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__)
::hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__)
#endif