fix cauterization of entities that are children of MyAvatar's head

This commit is contained in:
SamGondelman 2019-04-08 19:48:11 -07:00
parent 759d59c709
commit 27338c3639
16 changed files with 96 additions and 63 deletions

View file

@ -818,20 +818,8 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
if (_cauterizationNeedsUpdate) {
_cauterizationNeedsUpdate = false;
// Redisplay cauterized entities that are no longer children of the avatar.
auto cauterizedChild = _cauterizedChildrenOfHead.begin();
if (cauterizedChild != _cauterizedChildrenOfHead.end()) {
auto children = getChildren();
while (cauterizedChild != _cauterizedChildrenOfHead.end()) {
if (!children.contains(*cauterizedChild)) {
updateChildCauterization(*cauterizedChild, false);
cauterizedChild = _cauterizedChildrenOfHead.erase(cauterizedChild);
} else {
++cauterizedChild;
}
}
}
auto objectsToUncauterize = _cauterizedChildrenOfHead;
_cauterizedChildrenOfHead.clear();
// Update cauterization of entities that are children of the avatar.
auto headBoneSet = _skeletonModel->getCauterizeBoneSet();
forEachChild([&](SpatiallyNestablePointer object) {
@ -843,15 +831,19 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
updateChildCauterization(descendant, !_prevShouldDrawHead);
});
_cauterizedChildrenOfHead.insert(object);
} else if (_cauterizedChildrenOfHead.find(object) != _cauterizedChildrenOfHead.end()) {
// Redisplay cauterized children that are not longer children of the head.
updateChildCauterization(object, false);
objectsToUncauterize.erase(object);
} else if (objectsToUncauterize.find(object) == objectsToUncauterize.end()) {
objectsToUncauterize.insert(object);
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
updateChildCauterization(descendant, false);
objectsToUncauterize.insert(descendant);
});
_cauterizedChildrenOfHead.erase(object);
}
});
// Redisplay cauterized entities that are no longer children of the avatar.
for (auto cauterizedChild = objectsToUncauterize.begin(); cauterizedChild != objectsToUncauterize.end(); cauterizedChild++) {
updateChildCauterization(*cauterizedChild, false);
}
}
{

View file

@ -166,7 +166,10 @@ ShapeKey EntityRenderer::getShapeKey() {
}
render::hifi::Tag EntityRenderer::getTagMask() const {
return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
render::hifi::Tag mask = render::hifi::TAG_NONE;
mask = (render::hifi::Tag)(mask | (!_cauterized * render::hifi::TAG_MAIN_VIEW));
mask = (render::hifi::Tag)(mask | (_isVisibleInSecondaryCamera * render::hifi::TAG_SECONDARY_VIEW));
return mask;
}
render::hifi::Layer EntityRenderer::getHifiRenderLayer() const {
@ -215,12 +218,7 @@ void EntityRenderer::render(RenderArgs* args) {
emit requestRenderUpdate();
}
auto& renderMode = args->_renderMode;
bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE &&
renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE &&
_cauterized);
if (_visible && !cauterized) {
if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) {
doRender(args);
}
}

View file

@ -1066,13 +1066,6 @@ ItemKey ModelEntityRenderer::getKey() {
return _itemKey;
}
render::hifi::Tag ModelEntityRenderer::getTagMask() const {
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
return _cauterized ?
(_isVisibleInSecondaryCamera ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE) :
Parent::getTagMask(); // calculate which views to be shown in
}
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
if (_model) {
auto metaSubItems = _model->fetchRenderItemIDs();
@ -1409,6 +1402,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model->setVisibleInScene(_visible, scene);
}
if (model->isCauterized() != _cauterized) {
model->setCauterized(_cauterized, scene);
}
render::hifi::Tag tagMask = getTagMask();
if (model->getTagMask() != tagMask) {
model->setTagMask(tagMask, scene);

View file

@ -161,8 +161,6 @@ protected:
virtual void doRender(RenderArgs* args) override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
render::hifi::Tag getTagMask() const override;
void setIsVisibleInSecondaryCamera(bool value) override;
void setRenderLayer(RenderLayer value) override;
void setPrimitiveMode(PrimitiveMode value) override;

View file

@ -3007,6 +3007,26 @@ void EntityItem::setPrimitiveMode(PrimitiveMode value) {
}
}
bool EntityItem::getCauterized() const {
return resultWithReadLock<bool>([&] {
return _cauterized;
});
}
void EntityItem::setCauterized(bool value) {
bool changed = false;
withWriteLock([&] {
if (_cauterized != value) {
changed = true;
_cauterized = value;
}
});
if (changed) {
emit requestRenderUpdate();
}
}
bool EntityItem::getIgnorePickIntersection() const {
return resultWithReadLock<bool>([&] {
return _ignorePickIntersection;

View file

@ -303,6 +303,9 @@ public:
bool getCanCastShadow() const;
void setCanCastShadow(bool value);
void setCauterized(bool value);
bool getCauterized() const;
inline bool isVisible() const { return getVisible(); }
inline bool isInvisible() const { return !getVisible(); }
@ -530,9 +533,6 @@ public:
static QString _marketplacePublicKey;
static void retrieveMarketplacePublicKey();
void setCauterized(bool value) { _cauterized = value; }
bool getCauterized() const { return _cauterized; }
float getBoundingRadius() const { return _boundingRadius; }
void setSpaceIndex(int32_t index);
int32_t getSpaceIndex() const { return _spaceIndex; }

View file

@ -416,7 +416,7 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMo
void ModelMeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
if (!args) {
if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) {
return;
}

View file

@ -107,6 +107,7 @@ public:
void render(RenderArgs* args) override;
void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning);
void setCauterized(bool cauterized) { _cauterized = cauterized; }
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) override;
@ -138,6 +139,8 @@ private:
gpu::BufferPointer _meshBlendshapeBuffer;
int _meshNumVertices;
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
bool _cauterized { false };
};
namespace render {

View file

@ -224,6 +224,7 @@ void Model::updateRenderItems() {
PrimitiveMode primitiveMode = self->getPrimitiveMode();
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
bool cauterized = self->isCauterized();
render::Transaction transaction;
for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
@ -237,7 +238,7 @@ void Model::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions);
} else {
@ -261,6 +262,7 @@ void Model::updateRenderItems() {
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
data.setCauterized(cauterized);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
@ -922,6 +924,23 @@ bool Model::isGroupCulled() const {
return _renderItemKeyGlobalFlags.isSubMetaCulled();
}
void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) {
if (Model::isCauterized() != cauterized) {
_cauterized = cauterized;
if (!scene) {
_needsFixupInScene = true;
return;
}
render::Transaction transaction;
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [cauterized](ModelMeshPartPayload& data) {
data.setCauterized(cauterized);
});
}
scene->enqueueTransaction(transaction);
}
}
const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
return _renderItemKeyGlobalFlags;
}

View file

@ -126,6 +126,9 @@ public:
void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr);
bool isCauterized() const { return _cauterized; }
void setCauterized(bool value, const render::ScenePointer& scene);
// 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;
@ -502,6 +505,7 @@ protected:
// For this to work, a Meta RI must exists and knows about the RIs of this Model.
//
render::ItemKey _renderItemKeyGlobalFlags;
bool _cauterized { false };
bool shouldInvalidatePayloadShapeKey(int meshIndex);

View file

@ -23,9 +23,9 @@ namespace render {
// 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_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
};

View file

@ -58,10 +58,6 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
}
// FIXME: calling this here before the zones/lights are drawn during the deferred/forward passes means we're actually using the frames from the previous draw
// Fetch the current frame stacks from all the stages
// Starting with the Light Frame genreated in previous tasks
const auto setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup", input);
const auto queryResolution = setupOutput.getN<RenderShadowSetup::Output>(1);
const auto shadowFrame = setupOutput.getN<RenderShadowSetup::Output>(3);
@ -99,7 +95,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
char jobName[64];
sprintf(jobName, "ShadowCascadeSetup%d", i);
const auto cascadeSetupOutput = task.addJob<RenderShadowCascadeSetup>(jobName, shadowFrame, i, tagBits, tagMask);
const auto cascadeSetupOutput = task.addJob<RenderShadowCascadeSetup>(jobName, shadowFrame, i, shadowCasterReceiverFilter);
const auto shadowFilter = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(0);
auto antiFrustum = render::Varying(ViewFrustumPointer());
cascadeFrustums[i] = cascadeSetupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
@ -452,8 +448,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
const auto globalShadow = shadowFrame->_objects[0];
if (globalShadow && _cascadeIndex < globalShadow->getCascadeCount()) {
// Second item filter is to filter items to keep in shadow frustum computation (here we need to keep shadow receivers)
output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask);
output.edit0() = _filter;
// Set the keylight render args
auto& cascade = globalShadow->getCascade(_cascadeIndex);
@ -551,7 +546,6 @@ void CullShadowBounds::run(const render::RenderContextPointer& renderContext, co
assert(lightStage);
const auto globalLightDir = currentKeyLight->getDirection();
auto castersFilter = render::ItemFilter::Builder(filter).withShadowCaster().build();
const auto& receiversFilter = filter;
for (auto& inItems : inShapes) {
auto key = inItems.first;
@ -570,7 +564,7 @@ void CullShadowBounds::run(const render::RenderContextPointer& renderContext, co
if (castersFilter.test(shapeKey)) {
outItems->second.emplace_back(item);
outBounds += item.bound;
} else if (receiversFilter.test(shapeKey)) {
} else {
// Receivers are not rendered but they still increase the bounds of the shadow scene
// although only in the direction of the light direction so as to have a correct far
// distance without decreasing the near distance.
@ -585,7 +579,7 @@ void CullShadowBounds::run(const render::RenderContextPointer& renderContext, co
if (castersFilter.test(shapeKey)) {
outItems->second.emplace_back(item);
outBounds += item.bound;
} else if (receiversFilter.test(shapeKey)) {
} else {
// Receivers are not rendered but they still increase the bounds of the shadow scene
// although only in the direction of the light direction so as to have a correct far
// distance without decreasing the near distance.

View file

@ -134,15 +134,13 @@ public:
using Outputs = render::VaryingSet3<render::ItemFilter, ViewFrustumPointer, RenderShadowTask::CullFunctor>;
using JobModel = render::Job::ModelIO<RenderShadowCascadeSetup, Inputs, Outputs>;
RenderShadowCascadeSetup(unsigned int cascadeIndex, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) :
_cascadeIndex(cascadeIndex), _tagBits(tagBits), _tagMask(tagMask) {}
RenderShadowCascadeSetup(unsigned int cascadeIndex, render::ItemFilter filter) : _cascadeIndex(cascadeIndex), _filter(filter) {}
void run(const render::RenderContextPointer& renderContext, const Inputs& input, Outputs& output);
private:
unsigned int _cascadeIndex;
uint8_t _tagBits { 0x00 };
uint8_t _tagMask { 0x00 };
render::ItemFilter _filter;
};
class RenderShadowCascadeTeardown {

View file

@ -61,7 +61,7 @@ namespace render {
class Args {
public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE };
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE };
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
enum DebugFlags {
RENDER_DEBUG_NONE = 0,

View file

@ -39,7 +39,7 @@ public:
RenderFetchCullSortTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask);
};
#endif // hifi_RenderFetchCullSortTask_h

View file

@ -68,19 +68,28 @@ const QUuid SpatiallyNestable::getParentID() const {
void SpatiallyNestable::setParentID(const QUuid& parentID) {
bumpAncestorChainRenderableVersion();
bool success = false;
auto parent = getParentPointer(success);
bool parentChanged = false;
_idLock.withWriteLock([&] {
if (_parentID != parentID) {
parentChanged = true;
_parentID = parentID;
_parentKnowsMe = false;
}
});
if (parentChanged && success && parent) {
parent->recalculateChildCauterization();
}
if (!_parentKnowsMe) {
bool success = false;
auto parent = getParentPointer(success);
success = false;
parent = getParentPointer(success);
if (success && parent) {
bumpAncestorChainRenderableVersion();
parent->updateQueryAACube();
parent->recalculateChildCauterization();
}
}
}
@ -175,8 +184,9 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const {
void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) {
_parentJointIndex = parentJointIndex;
auto parent = _parent.lock();
if (parent) {
bool success = false;
auto parent = getParentPointer(success);
if (success && parent) {
parent->recalculateChildCauterization();
}
}