Merge pull request #11663 from AndrewMeadows/shape-sharing

fix incorrect collision shape sharing for some ModelEntityItem configurations
This commit is contained in:
Brad Hefta-Gaub 2017-10-24 21:04:57 -07:00 committed by GitHub
commit ef78711b7b
4 changed files with 77 additions and 41 deletions

View file

@ -695,12 +695,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) {
const void* key = static_cast<const void*>(shape);
if (_collisionMeshKey != key) {
if (_collisionMeshKey) {
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
_collisionMeshKey = key;
// toggle _showCollisionGeometry forces re-evaluation later
_showCollisionGeometry = !_showCollisionGeometry;
emit requestCollisionGeometryUpdate();
}
}
@ -1103,6 +1099,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
if (model->getRenderItemsNeedUpdate()) {
return true;
}
if (_needsCollisionGeometryUpdate) {
return true;
}
}
return Parent::needsRenderUpdate();
}
@ -1169,6 +1169,15 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
return false;
}
void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
if (key != _collisionMeshKey) {
if (_collisionMeshKey) {
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
_collisionMeshKey = key;
}
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (_hasModel != entity->hasModel()) {
@ -1201,6 +1210,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model = std::make_shared<Model>(nullptr, entity.get());
connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::requestRenderUpdate);
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
model->init();
entity->setModel(model);
@ -1259,6 +1269,26 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
// TODO? early exit here when not visible?
if (_needsCollisionGeometryUpdate) {
setCollisionMeshKey(entity->getCollisionMeshKey());
_needsCollisionGeometryUpdate = false;
ShapeType type = entity->getShapeType();
if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
// NOTE: it is OK if _collisionMeshKey is nullptr
model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
// NOTE: the model will render the collisionGeometry if it has one
_model->setCollisionMesh(mesh);
} else {
if (_collisionMeshKey) {
// release mesh
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
// clear model's collision geometry
model::MeshPointer mesh = nullptr;
_model->setCollisionMesh(mesh);
}
}
{
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) {
@ -1297,6 +1327,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
}
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
_needsCollisionGeometryUpdate = true;
emit requestRenderUpdate();
}
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
void ModelEntityRenderer::doRender(RenderArgs* args) {
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
@ -1327,28 +1362,11 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
// Remap textures for the next frame to avoid flicker
// remapTextures();
#if 0
// update whether the model should be showing collision mesh (this may flag for fixupInScene)
bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS);
if (showingCollisionGeometry != _showCollisionGeometry) {
ShapeType type = _entity->getShapeType();
_showCollisionGeometry = showingCollisionGeometry;
if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
// NOTE: it is OK if _collisionMeshKey is nullptr
model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
// NOTE: the model will render the collisionGeometry if it has one
_model->setCollisionMesh(mesh);
} else {
// release mesh
if (_collisionMeshKey) {
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
// clear model's collision geometry
model::MeshPointer mesh = nullptr;
_model->setCollisionMesh(mesh);
}
bool showCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS);
if (showCollisionGeometry != _showCollisionGeometry) {
_showCollisionGeometry = showCollisionGeometry;
flagForCollisionGeometryUpdate();
}
#endif
}
void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) {

View file

@ -50,6 +50,8 @@ private:
};
class RenderableModelEntityItem : public ModelEntityWrapper {
Q_OBJECT
friend class render::entities::ModelEntityRenderer;
using Parent = ModelEntityWrapper;
public:
@ -105,6 +107,10 @@ public:
virtual QStringList getJointNames() const override;
bool getMeshes(MeshProxyList& result) override;
const void* getCollisionMeshKey() const { return _collisionMeshKey; }
signals:
void requestCollisionGeometryUpdate();
private:
bool needsUpdateModelBounds() const;
@ -117,7 +123,6 @@ private:
QVariantMap _originalTextures;
bool _dimensionsInitialized { true };
bool _needsJointSimulation { false };
bool _showCollisionGeometry { false };
const void* _collisionMeshKey { nullptr };
};
@ -141,6 +146,8 @@ protected:
virtual bool needsRenderUpdate() const override;
virtual void doRender(RenderArgs* args) override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
void flagForCollisionGeometryUpdate();
void setCollisionMeshKey(const void* key);
private:
void animate(const TypedEntityPointer& entity);
@ -163,6 +170,7 @@ private:
bool _needsJointSimulation{ false };
bool _showCollisionGeometry{ false };
bool _needsCollisionGeometryUpdate{ false };
const void* _collisionMeshKey{ nullptr };
// used on client side

View file

@ -235,7 +235,6 @@ void Model::updateRenderItems() {
self->updateClusterMatrices();
Transform modelTransform = self->getTransform();
Transform physicsTransform = modelTransform;
modelTransform.setScale(glm::vec3(1.0f));
uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
@ -259,13 +258,12 @@ void Model::updateRenderItems() {
});
}
// collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset
Transform collisionMeshOffset;
collisionMeshOffset.setIdentity();
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
transaction.updateItem<MeshPartPayload>(itemID, [physicsTransform, collisionMeshOffset](MeshPartPayload& data) {
transaction.updateItem<MeshPartPayload>(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) {
// update the model transform for this render item.
data.updateTransform(physicsTransform, collisionMeshOffset);
data.updateTransform(modelTransform, collisionMeshOffset);
});
}

View file

@ -46,6 +46,8 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
}
break;
case SHAPE_TYPE_COMPOUND:
case SHAPE_TYPE_SIMPLE_HULL:
case SHAPE_TYPE_SIMPLE_COMPOUND:
case SHAPE_TYPE_STATIC_MESH:
_url = QUrl(url);
break;
@ -250,16 +252,26 @@ const DoubleHashKey& ShapeInfo::getHash() const {
}
_doubleHashKey.setHash2(hash);
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_STATIC_MESH) {
QString url = _url.toString();
if (!url.isEmpty()) {
// fold the urlHash into both parts
QByteArray baUrl = url.toLocal8Bit();
const char *cUrl = baUrl.data();
uint32_t urlHash = qChecksum(cUrl, baUrl.count());
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash);
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash);
}
QString url = _url.toString();
if (!url.isEmpty()) {
// fold the urlHash into both parts
QByteArray baUrl = url.toLocal8Bit();
uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size());
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash);
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash);
}
uint32_t numHulls = 0;
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) {
numHulls = (uint32_t)_pointCollection.size();
} else if (_type == SHAPE_TYPE_SIMPLE_HULL) {
numHulls = 1;
}
if (numHulls > 0) {
hash = DoubleHashKey::hashFunction(numHulls, primeIndex++);
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ hash);
hash = DoubleHashKey::hashFunction2(numHulls);
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ hash);
}
}
return _doubleHashKey;