mirror of
https://github.com/lubosz/overte.git
synced 2025-04-26 17:15:37 +02:00
Merge pull request #12158 from sethalves/cauterize-head-av-entities-1
don't draw head-descendant entitys with 1st-person camera
This commit is contained in:
commit
b3250ff4b6
33 changed files with 258 additions and 85 deletions
interface/src
libraries
avatars-renderer/src/avatars-renderer
entities-renderer/src
RenderableEntityItem.cppRenderableEntityItem.hRenderableModelEntityItem.cppRenderableParticleEffectEntityItem.cppRenderablePolyLineEntityItem.cppRenderableZoneEntityItem.cpp
entities/src
render-utils/src
AnimDebugDraw.cppCauterizedModel.cppLightPayload.cppMeshPartPayload.cppMeshPartPayload.hModel.cppModel.hRenderShadowTask.cppRenderShadowTask.hRenderViewTask.cppRenderViewTask.h
render/src/render
|
@ -2294,7 +2294,7 @@ void Application::initializeGL() {
|
|||
#ifndef Q_OS_ANDROID
|
||||
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
|
||||
#endif
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
|
||||
|
||||
#ifdef Q_OS_OSX
|
||||
DeadlockWatchdogThread::resume();
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
|
||||
|
||||
void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
if (!isDeferred) {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
|
@ -205,7 +206,7 @@ public:
|
|||
|
||||
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
if (!isDeferred) {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include <recording/Frame.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <trackers/FaceTracker.h>
|
||||
#include <RenderableModelEntityItem.h>
|
||||
|
||||
#include "MyHead.h"
|
||||
#include "MySkeletonModel.h"
|
||||
|
@ -503,11 +504,42 @@ void MyAvatar::updateEyeContactTarget(float deltaTime) {
|
|||
extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
|
||||
extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||
|
||||
void MyAvatar::beParentOfChild(SpatiallyNestablePointer newChild) const {
|
||||
_cauterizationNeedsUpdate = true;
|
||||
SpatiallyNestable::beParentOfChild(newChild);
|
||||
}
|
||||
|
||||
void MyAvatar::forgetChild(SpatiallyNestablePointer newChild) const {
|
||||
_cauterizationNeedsUpdate = true;
|
||||
SpatiallyNestable::forgetChild(newChild);
|
||||
}
|
||||
|
||||
void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) {
|
||||
if (object->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
entity->setCauterized(!_prevShouldDrawHead);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::simulate(float deltaTime) {
|
||||
PerformanceTimer perfTimer("simulate");
|
||||
|
||||
animateScaleChanges(deltaTime);
|
||||
|
||||
if (_cauterizationNeedsUpdate) {
|
||||
const std::unordered_set<int>& headBoneSet = _skeletonModel->getCauterizeBoneSet();
|
||||
forEachChild([&](SpatiallyNestablePointer object) {
|
||||
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
|
||||
if (isChildOfHead) {
|
||||
updateChildCauterization(object);
|
||||
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
updateChildCauterization(descendant);
|
||||
});
|
||||
}
|
||||
});
|
||||
_cauterizationNeedsUpdate = false;
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("transform");
|
||||
bool stepAction = false;
|
||||
|
@ -1067,7 +1099,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
|
|||
}
|
||||
|
||||
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
||||
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene());
|
||||
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
|
||||
|
@ -1417,8 +1449,9 @@ void MyAvatar::clearJointsData() {
|
|||
|
||||
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
|
||||
_headBoneSet.clear();
|
||||
_cauterizationNeedsUpdate = true;
|
||||
emit skeletonChanged();
|
||||
|
||||
}
|
||||
|
@ -1762,7 +1795,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
|||
|
||||
void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) {
|
||||
if (model->isActive() && model->isRenderable()) {
|
||||
model->setVisibleInScene(visible, scene);
|
||||
model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1790,6 +1823,8 @@ void MyAvatar::initHeadBones() {
|
|||
}
|
||||
q.pop();
|
||||
}
|
||||
|
||||
_cauterizationNeedsUpdate = true;
|
||||
}
|
||||
|
||||
QUrl MyAvatar::getAnimGraphOverrideUrl() const {
|
||||
|
@ -1860,6 +1895,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
|
||||
initAnimGraph();
|
||||
_isAnimatingScale = true;
|
||||
_cauterizationNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
|
||||
|
@ -1948,6 +1984,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
|||
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
|
||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||
_cauterizationNeedsUpdate = true;
|
||||
_skeletonModel->setEnableCauterization(!shouldDrawHead);
|
||||
|
||||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
|
@ -1957,7 +1994,8 @@ void MyAvatar::preDisplaySide(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) {
|
||||
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
|
||||
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
|
||||
render::ItemKey::TAG_BITS_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -633,6 +633,11 @@ signals:
|
|||
private slots:
|
||||
void leaveDomain();
|
||||
|
||||
|
||||
protected:
|
||||
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
|
||||
virtual void forgetChild(SpatiallyNestablePointer newChild) const override;
|
||||
|
||||
private:
|
||||
|
||||
bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut);
|
||||
|
@ -812,6 +817,8 @@ private:
|
|||
bool _enableDebugDrawIKChains { false };
|
||||
bool _enableDebugDrawDetailedCollision { false };
|
||||
|
||||
mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state?
|
||||
|
||||
AudioListenerMode _audioListenerMode;
|
||||
glm::vec3 _customListenPosition;
|
||||
glm::quat _customListenOrientation;
|
||||
|
@ -849,6 +856,8 @@ private:
|
|||
// height of user in sensor space, when standing erect.
|
||||
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
|
||||
|
||||
void updateChildCauterization(SpatiallyNestablePointer object);
|
||||
|
||||
// max unscaled forward movement speed
|
||||
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
|
||||
};
|
||||
|
|
|
@ -86,7 +86,8 @@ void ModelOverlay::update(float deltatime) {
|
|||
}
|
||||
if (_visibleDirty) {
|
||||
_visibleDirty = false;
|
||||
_model->setVisibleInScene(getVisible(), scene);
|
||||
// don't show overlays in mirrors
|
||||
_model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0);
|
||||
}
|
||||
if (_drawInFrontDirty) {
|
||||
_drawInFrontDirty = false;
|
||||
|
@ -120,8 +121,10 @@ void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::Scene
|
|||
}
|
||||
|
||||
void ModelOverlay::setVisible(bool visible) {
|
||||
Overlay::setVisible(visible);
|
||||
_visibleDirty = true;
|
||||
if (visible != getVisible()) {
|
||||
Overlay::setVisible(visible);
|
||||
_visibleDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setDrawInFront(bool drawInFront) {
|
||||
|
|
|
@ -106,7 +106,7 @@ private:
|
|||
bool _jointMappingCompleted { false };
|
||||
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
|
||||
|
||||
bool _visibleDirty { false };
|
||||
bool _visibleDirty { true };
|
||||
bool _drawInFrontDirty { false };
|
||||
bool _drawInHUDDirty { false };
|
||||
|
||||
|
|
|
@ -44,6 +44,13 @@ namespace render {
|
|||
} else {
|
||||
builder.withViewSpace();
|
||||
}
|
||||
|
||||
if (!overlay->getVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
builder.withTagBits(render::ItemKey::TAG_BITS_0); // Only draw overlays in main view
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
|
|
|
@ -50,7 +50,7 @@ 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();
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1);
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
|
||||
return static_pointer_cast<Avatar>(avatar)->getBounds();
|
||||
|
|
|
@ -159,10 +159,10 @@ Item::Bound EntityRenderer::getBound() {
|
|||
|
||||
ItemKey EntityRenderer::getKey() {
|
||||
if (isTransparent()) {
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta();
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
}
|
||||
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta();
|
||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
}
|
||||
|
||||
uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
||||
|
@ -185,7 +185,12 @@ void EntityRenderer::render(RenderArgs* args) {
|
|||
emit requestRenderUpdate();
|
||||
}
|
||||
|
||||
if (_visible) {
|
||||
auto& renderMode = args->_renderMode;
|
||||
bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE &&
|
||||
renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE &&
|
||||
_cauterized);
|
||||
|
||||
if (_visible && !cauterized) {
|
||||
doRender(args);
|
||||
}
|
||||
}
|
||||
|
@ -366,6 +371,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
|
||||
_moving = entity->isMovingRelativeToParent();
|
||||
_visible = entity->getVisible();
|
||||
_cauterized = entity->getCauterized();
|
||||
_needsRenderUpdate = false;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ protected:
|
|||
bool _isFading{ _entitiesShouldFadeFunction() };
|
||||
bool _prevIsTransparent { false };
|
||||
bool _visible { false };
|
||||
bool _cauterized { false };
|
||||
bool _moving { false };
|
||||
bool _needsRenderUpdate { false };
|
||||
// Only touched on the rendering thread
|
||||
|
|
|
@ -1013,9 +1013,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
|
|||
|
||||
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
||||
if (didVisualGeometryRequestSucceed) {
|
||||
_itemKey = ItemKey::Builder().withTypeMeta();
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
} else {
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape();
|
||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1334,11 +1334,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
entity->updateModelBounds();
|
||||
entity->stopModelOverrideIfNoParent();
|
||||
|
||||
if (model->isVisible() != _visible) {
|
||||
// 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
|
||||
|
||||
if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
|
||||
// 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);
|
||||
model->setVisibleInScene(_visible, scene, viewTaskBits);
|
||||
}
|
||||
// TODO? early exit here when not visible?
|
||||
|
||||
|
|
|
@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
|
|||
|
||||
ItemKey ParticleEffectEntityRenderer::getKey() {
|
||||
if (_visible) {
|
||||
return ItemKey::Builder::transparentShape();
|
||||
return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
} else {
|
||||
return ItemKey::Builder().withInvisible().build();
|
||||
return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
|
|||
}
|
||||
|
||||
ItemKey PolyLineEntityRenderer::getKey() {
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta();
|
||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
}
|
||||
|
||||
ShapeKey PolyLineEntityRenderer::getShapeKey() {
|
||||
|
|
|
@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
|
||||
|
||||
ItemKey ZoneEntityRenderer::getKey() {
|
||||
return ItemKey::Builder().withTypeMeta().build();
|
||||
return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
|
||||
}
|
||||
|
||||
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
|
|
|
@ -470,6 +470,9 @@ public:
|
|||
static QString _marketplacePublicKey;
|
||||
static void retrieveMarketplacePublicKey();
|
||||
|
||||
void setCauterized(bool value) { _cauterized = value; }
|
||||
bool getCauterized() const { return _cauterized; }
|
||||
|
||||
signals:
|
||||
void requestRenderUpdate();
|
||||
|
||||
|
@ -623,6 +626,7 @@ protected:
|
|||
quint64 _lastUpdatedAccelerationTimestamp { 0 };
|
||||
quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
|
||||
|
||||
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
|
||||
};
|
||||
|
||||
#endif // hifi_EntityItem_h
|
||||
|
|
|
@ -67,7 +67,7 @@ public:
|
|||
typedef render::Payload<AnimDebugDrawData> AnimDebugDrawPayload;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()); }
|
||||
template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); }
|
||||
template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; }
|
||||
template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) {
|
||||
data->render(args);
|
||||
|
|
|
@ -249,7 +249,7 @@ void CauterizedModel::updateRenderItems() {
|
|||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
|
||||
});
|
||||
|
|
|
@ -18,9 +18,13 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeLight();
|
||||
if (!payload || !payload->isVisible()) {
|
||||
builder.withInvisible();
|
||||
builder.withTagBits(ItemKey::TAG_BITS_ALL);
|
||||
if (payload) {
|
||||
if (!payload->isVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -87,6 +91,7 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload) {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeLight();
|
||||
builder.withTagBits(ItemKey::TAG_BITS_ALL);
|
||||
if (!payload || !payload->isVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
|
|
@ -71,10 +71,20 @@ void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) {
|
|||
_drawMaterial = drawMaterial;
|
||||
}
|
||||
|
||||
ItemKey MeshPartPayload::getKey() const {
|
||||
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
||||
if (!isVisible) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
builder.withTagBits(tagBits);
|
||||
|
||||
if (isLayered) {
|
||||
builder.withLayered();
|
||||
}
|
||||
|
||||
if (_drawMaterial) {
|
||||
auto matKey = _drawMaterial->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
|
@ -82,7 +92,11 @@ ItemKey MeshPartPayload::getKey() const {
|
|||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
_itemKey = builder.build();
|
||||
}
|
||||
|
||||
ItemKey MeshPartPayload::getKey() const {
|
||||
return _itemKey;
|
||||
}
|
||||
|
||||
Item::Bound MeshPartPayload::getBound() const {
|
||||
|
@ -389,7 +403,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
|
|||
_worldBound.transform(boundTransform);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
|
||||
void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
||||
|
@ -397,6 +411,8 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
|
|||
builder.withInvisible();
|
||||
}
|
||||
|
||||
builder.withTagBits(tagBits);
|
||||
|
||||
if (isLayered) {
|
||||
builder.withLayered();
|
||||
}
|
||||
|
@ -415,10 +431,6 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
|
|||
_itemKey = builder.build();
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
return _itemKey;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
|
||||
if (isLayeredInFront) {
|
||||
_layer = Item::LAYER_3D_FRONT;
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
typedef render::Payload<MeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits);
|
||||
|
||||
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
|
||||
|
||||
virtual void notifyLocationChanged() {}
|
||||
|
@ -70,6 +72,9 @@ public:
|
|||
size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; }
|
||||
int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; }
|
||||
bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; }
|
||||
|
||||
protected:
|
||||
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
|
@ -94,16 +99,15 @@ public:
|
|||
using TransformType = glm::mat4;
|
||||
#endif
|
||||
|
||||
void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override;
|
||||
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms);
|
||||
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
|
||||
|
||||
// Render Item interface
|
||||
render::ItemKey getKey() const override;
|
||||
int getLayer() const;
|
||||
render::ShapeKey getShapeKey() const override; // shape interface
|
||||
void render(RenderArgs* args) override;
|
||||
|
||||
void setKey(bool isVisible, bool isLayered);
|
||||
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
|
||||
void setShapeKey(bool invalidateShapeKey, bool isWireframe);
|
||||
|
||||
|
@ -126,7 +130,6 @@ private:
|
|||
void initCache(const ModelPointer& model);
|
||||
|
||||
gpu::BufferPointer _blendedVertexBuffer;
|
||||
render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
|
||||
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
|
||||
int _layer { render::Item::LAYER_3D };
|
||||
};
|
||||
|
|
|
@ -268,6 +268,7 @@ void Model::updateRenderItems() {
|
|||
|
||||
bool isWireframe = self->isWireframe();
|
||||
bool isVisible = self->isVisible();
|
||||
uint8_t viewTagBits = self->getViewTagBits();
|
||||
bool isLayeredInFront = self->isLayeredInFront();
|
||||
bool isLayeredInHUD = self->isLayeredInHUD();
|
||||
|
||||
|
@ -280,8 +281,10 @@ void Model::updateRenderItems() {
|
|||
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey,
|
||||
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms,
|
||||
invalidatePayloadShapeKey, isWireframe, isVisible,
|
||||
viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateClusterBuffer(clusterTransforms);
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
|
@ -297,7 +300,7 @@ void Model::updateRenderItems() {
|
|||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
|
||||
});
|
||||
|
@ -681,22 +684,25 @@ void Model::calculateTriangleSets() {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) {
|
||||
if (_isVisible != isVisible) {
|
||||
void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits) {
|
||||
if (_isVisible != isVisible || _viewTagBits != viewTagBits) {
|
||||
_isVisible = isVisible;
|
||||
_viewTagBits = viewTagBits;
|
||||
|
||||
bool isLayeredInFront = _isLayeredInFront;
|
||||
bool isLayeredInHUD = _isLayeredInHUD;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
|
@ -709,18 +715,21 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer&
|
|||
_isLayeredInFront = isLayeredInFront;
|
||||
|
||||
bool isVisible = _isVisible;
|
||||
uint8_t viewTagBits = _viewTagBits;
|
||||
bool isLayeredInHUD = _isLayeredInHUD;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
|
@ -733,18 +742,21 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce
|
|||
_isLayeredInHUD = isLayeredInHUD;
|
||||
|
||||
bool isVisible = _isVisible;
|
||||
uint8_t viewTagBits = _viewTagBits;
|
||||
bool isLayeredInFront = _isLayeredInFront;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
// new Scene/Engine rendering support
|
||||
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene);
|
||||
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits);
|
||||
void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
|
||||
void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
|
||||
bool needsFixupInScene() const;
|
||||
|
@ -104,6 +104,7 @@ public:
|
|||
bool isRenderable() const;
|
||||
|
||||
bool isVisible() const { return _isVisible; }
|
||||
uint8_t getViewTagBits() const { return _viewTagBits; }
|
||||
|
||||
bool isLayeredInFront() const { return _isLayeredInFront; }
|
||||
bool isLayeredInHUD() const { return _isLayeredInHUD; }
|
||||
|
@ -396,6 +397,7 @@ protected:
|
|||
|
||||
QUrl _url;
|
||||
bool _isVisible;
|
||||
uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL };
|
||||
|
||||
gpu::Buffers _blendedVertexBuffers;
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
|
|||
});
|
||||
}
|
||||
|
||||
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {
|
||||
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
|
||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; };
|
||||
|
||||
// Prepare the ShapePipeline
|
||||
|
@ -216,7 +216,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
task.addJob<RenderShadowSetup>("ShadowSetup");
|
||||
|
||||
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
|
||||
const auto setupOutput = task.addJob<RenderShadowCascadeSetup>("ShadowCascadeSetup", i);
|
||||
const auto setupOutput = task.addJob<RenderShadowCascadeSetup>("ShadowCascadeSetup", i, tagBits, tagMask);
|
||||
const auto shadowFilter = setupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
|
||||
|
||||
// CPU jobs:
|
||||
|
@ -264,7 +264,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
|
|||
|
||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
||||
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask);
|
||||
|
||||
globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
using JobModel = render::Task::Model<RenderShadowTask, Config>;
|
||||
|
||||
RenderShadowTask() {}
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender);
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
|
||||
|
||||
void configure(const Config& configuration);
|
||||
};
|
||||
|
@ -67,12 +67,14 @@ public:
|
|||
using Outputs = render::VaryingSet3<RenderArgs::RenderMode, render::ItemFilter, float>;
|
||||
using JobModel = render::Job::ModelO<RenderShadowCascadeSetup, Outputs>;
|
||||
|
||||
RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {}
|
||||
RenderShadowCascadeSetup(unsigned int cascadeIndex, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) : _cascadeIndex{ cascadeIndex }, _tagBits(tagBits), _tagMask(tagMask) {}
|
||||
void run(const render::RenderContextPointer& renderContext, Outputs& output);
|
||||
|
||||
private:
|
||||
|
||||
unsigned int _cascadeIndex;
|
||||
uint8_t _tagBits{ 0x00 };
|
||||
uint8_t _tagMask{ 0x00 };
|
||||
};
|
||||
|
||||
class RenderShadowCascadeTeardown {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "RenderDeferredTask.h"
|
||||
#include "RenderForwardTask.h"
|
||||
|
||||
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits, uint8_t tagMask) {
|
||||
// auto items = input.get<Input>();
|
||||
|
||||
// Shadows use an orthographic projection because they are linked to sunlights
|
||||
|
@ -28,9 +28,9 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
|
|||
const auto threshold = 1e-3f;
|
||||
return relativeBoundRadius > threshold;
|
||||
return true;
|
||||
});
|
||||
}, tagBits, tagMask);
|
||||
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
|
||||
if (isDeferred) {
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
|
||||
RenderViewTask() {}
|
||||
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred);
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
|
|||
details._rendered += (int)outItems.size();
|
||||
}
|
||||
|
||||
void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBounds& outItems) {
|
||||
void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
auto& scene = renderContext->_scene;
|
||||
|
@ -72,7 +72,9 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBo
|
|||
outItems.reserve(items.size());
|
||||
for (auto& id : items) {
|
||||
auto& item = scene->getItem(id);
|
||||
outItems.emplace_back(ItemBound(id, item.getBound()));
|
||||
if (filter.test(item.getKey())) {
|
||||
outItems.emplace_back(ItemBound(id, item.getBound()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ namespace render {
|
|||
|
||||
class FetchNonspatialItems {
|
||||
public:
|
||||
using JobModel = Job::ModelO<FetchNonspatialItems, ItemBounds>;
|
||||
void run(const RenderContextPointer& renderContext, ItemBounds& outItems);
|
||||
using JobModel = Job::ModelIO<FetchNonspatialItems, ItemFilter, ItemBounds>;
|
||||
void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems);
|
||||
};
|
||||
|
||||
class FetchSpatialTreeConfig : public Job::Config {
|
||||
|
|
|
@ -34,6 +34,21 @@ 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;
|
||||
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -38,25 +38,62 @@ class Context;
|
|||
// Key is the KEY to filter Items and create specialized lists
|
||||
class ItemKey {
|
||||
public:
|
||||
enum FlagBit {
|
||||
// 8 tags are available to organize the items and filter them against as fields of the ItemKey.
|
||||
// TAG & TAG_BITS are defined from several bits in the Key.
|
||||
// An Item can be tagged and filtering can rely on the tags to keep or exclude items
|
||||
// ItemKey are not taged by default
|
||||
enum Tag : uint8_t {
|
||||
TAG_0 = 0, // 8 Tags
|
||||
TAG_1,
|
||||
TAG_2,
|
||||
TAG_3,
|
||||
TAG_4,
|
||||
TAG_5,
|
||||
TAG_6,
|
||||
TAG_7,
|
||||
|
||||
NUM_TAGS
|
||||
};
|
||||
// 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_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...
|
||||
VIEW_SPACE, // Transformed in view space, and not in world space
|
||||
DYNAMIC, // Dynamic and bound will change unlike static item
|
||||
DEFORMED, // Deformed within bound, not solid
|
||||
INVISIBLE, // Visible or not? could be just here to cast shadow
|
||||
INVISIBLE, // Visible or not in the scene?
|
||||
SHADOW_CASTER, // Item cast shadows
|
||||
PICKABLE, // Item can be picked/selected
|
||||
LAYERED, // Item belongs to one of the layers different from the default layer
|
||||
|
||||
SMALLER,
|
||||
FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
|
||||
LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
|
||||
|
||||
__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
|
||||
};
|
||||
typedef std::bitset<NUM_FLAGS> Flags;
|
||||
|
||||
// All the bits touching tag bits sets to true
|
||||
const static uint32_t KEY_TAG_BITS_MASK;
|
||||
static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) {
|
||||
return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT);
|
||||
}
|
||||
|
||||
// The key is the Flags
|
||||
Flags _flags;
|
||||
|
||||
|
@ -84,9 +121,12 @@ public:
|
|||
Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
|
||||
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
|
||||
Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
|
||||
Builder& withPickable() { _flags.set(PICKABLE); return (*this); }
|
||||
Builder& withLayered() { _flags.set(LAYERED); 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); }
|
||||
|
||||
// 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(); }
|
||||
|
@ -116,14 +156,15 @@ public:
|
|||
|
||||
bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
|
||||
|
||||
bool isPickable() const { return _flags[PICKABLE]; }
|
||||
|
||||
bool isLayered() const { return _flags[LAYERED]; }
|
||||
bool isSpatial() const { return !isLayered(); }
|
||||
|
||||
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); }
|
||||
|
||||
// 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)); }
|
||||
bool isSmall() const { return _flags[__SMALLER]; }
|
||||
void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
|
||||
|
||||
bool operator==(const ItemKey& key) { return (_flags == key._flags); }
|
||||
bool operator!=(const ItemKey& key) { return (_flags != key._flags); }
|
||||
|
@ -177,11 +218,14 @@ 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& withPickable() { _value.set(ItemKey::PICKABLE); _mask.set(ItemKey::PICKABLE); 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& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
|
||||
Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
|
||||
// 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& withNothing() { _value.reset(); _mask.reset(); return (*this); }
|
||||
|
||||
// Convenient standard keys that we will keep on using all over the place
|
||||
|
|
|
@ -17,19 +17,21 @@
|
|||
|
||||
using namespace render;
|
||||
|
||||
void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor) {
|
||||
void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
|
||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
||||
|
||||
// CPU jobs:
|
||||
// Fetch and cull the items from the scene
|
||||
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
||||
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withTagBits(tagBits, tagMask);
|
||||
const auto spatialFilter = render::Varying(filter);
|
||||
const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
|
||||
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
|
||||
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
|
||||
|
||||
// Overlays are not culled
|
||||
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection");
|
||||
const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withTagBits(tagBits, tagMask);
|
||||
const auto nonspatialFilter = render::Varying(overlayfilter);
|
||||
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection", nonspatialFilter);
|
||||
|
||||
// Multi filter visible items into different buckets
|
||||
const int NUM_SPATIAL_FILTERS = 4;
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
|
||||
RenderFetchCullSortTask() {}
|
||||
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
|
||||
};
|
||||
|
||||
#endif // hifi_RenderFetchCullSortTask_h
|
||||
|
|
Loading…
Reference in a new issue