From 08a0068aec8e5a484c9e2c10cfcdb74329ac4955 Mon Sep 17 00:00:00 2001 From: Andy Nichols <andy.nichols@qt.io> Date: Fri, 3 Apr 2020 15:49:10 +0200 Subject: [PATCH] Picking: Only generate BVH data for pickable models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I3a84983cbdd50fc0cc3cfec2a1ff156325e99b91 Reviewed-by: Christian Strømme <christian.stromme@qt.io> --- ...rendererimpllayerrenderpreparationdata.cpp | 34 ++++++--- .../qssgrenderbuffermanager.cpp | 73 ++++++++++++------- .../qssgrenderbuffermanager_p.h | 3 + 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/src/runtimerender/rendererimpl/qssgrendererimpllayerrenderpreparationdata.cpp b/src/runtimerender/rendererimpl/qssgrendererimpllayerrenderpreparationdata.cpp index 446a543f4..291f33a57 100644 --- a/src/runtimerender/rendererimpl/qssgrendererimpllayerrenderpreparationdata.cpp +++ b/src/runtimerender/rendererimpl/qssgrendererimpllayerrenderpreparationdata.cpp @@ -657,6 +657,30 @@ bool QSSGLayerRenderPreparationData::prepareModelForRender(QSSGRenderModel &inMo bool subsetDirty = false; + // Completely transparent models cannot be pickable. But models with completely + // transparent materials still are. This allows the artist to control pickability + // in a somewhat fine-grained style. + const bool canModelBePickable = (inModel.globalOpacity > QSSG_RENDER_MINIMUM_RENDER_OPACITY) + && (theModelContext.model.flags.testFlag(QSSGRenderModel::Flag::GloballyPickable)); + if (canModelBePickable) { + // Check if there is BVH data, if not generate it + if (!theMesh->bvh && !inModel.meshPath.isNull()) { + theMesh->bvh = bufferManager->loadMeshBVH(inModel.meshPath); + if (theMesh->bvh) { + for (int i = 0; i < theMesh->bvh->roots.count(); ++i) + theMesh->subsets[i].bvhRoot = theMesh->bvh->roots.at(i); + } + } + } else { + // Check if there is BVH data, if so delete it + if (theMesh->bvh) { + delete theMesh->bvh; + theMesh->bvh = nullptr; + for (auto subset : theMesh->subsets) + subset.bvhRoot = nullptr; + } + } + const QSSGScopedLightsListScope lightsScope(globalLights, lightDirections, sourceLightDirections, inScopedLights); setShaderFeature(QSSGShaderDefines::asString(QSSGShaderDefines::CgLighting), !globalLights.empty()); for (int idx = 0; idx < theMesh->subsets.size(); ++idx) { @@ -672,7 +696,6 @@ bool QSSGLayerRenderPreparationData::prepareModelForRender(QSSGRenderModel &inMo { QSSGRenderSubset &theSubset(theOuterSubset); QSSGRenderableObjectFlags renderableFlags; - renderableFlags.setPickable(false); float subsetOpacity = inModel.globalOpacity; QVector3D theModelCenter(theSubset.bounds.center()); theModelCenter = mat44::transform(inModel.globalTransform, theModelCenter); @@ -685,15 +708,6 @@ bool QSSGLayerRenderPreparationData::prepareModelForRender(QSSGRenderModel &inMo subsetOpacity = 0.0f; } - // For now everything is pickable. Eventually we want to have localPickable and - // globalPickable set on the node during - // updates and have the runtime tell us what is pickable and what is not pickable. - // Completely transparent models cannot be pickable. But models with completely - // transparent materials - // still are. This allows the artist to control pickability in a somewhat - // fine-grained style. - const bool canModelBePickable = (inModel.globalOpacity > QSSG_RENDER_MINIMUM_RENDER_OPACITY) - && (theModelContext.model.flags.testFlag(QSSGRenderModel::Flag::GloballyPickable) || renderableFlags.isPickable()); renderableFlags.setPickable(canModelBePickable); // Casting and Receiving Shadows diff --git a/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp b/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp index 0ad000a84..d53d2c1d1 100644 --- a/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp +++ b/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp @@ -496,15 +496,11 @@ QSSGRenderMesh *QSSGBufferManager::createRenderMesh( ::memcpy(newJoint.localToGlobalBoneSpace, importJoint.m_localToGlobalBoneSpace, 16 * sizeof(float)); } - // Build BVH for Mesh - QSSGMeshBVHBuilder meshBVHBuilder(result.m_mesh); - newMesh->bvh = meshBVHBuilder.buildTree(); - for (quint32 subsetIdx = 0, subsetEnd = result.m_mesh->m_subsets.size(); subsetIdx < subsetEnd; ++subsetIdx) { QSSGRenderSubset subset; const QSSGMeshUtilities::MeshSubset &source(result.m_mesh->m_subsets.index(baseAddress, subsetIdx)); subset.bounds = source.m_bounds; - subset.bvhRoot = newMesh->bvh->roots.at(subsetIdx); + subset.bvhRoot = nullptr; subset.count = source.m_count; subset.offset = source.m_offset; subset.joints = newMesh->joints; @@ -590,27 +586,7 @@ QSSGRenderMesh *QSSGBufferManager::loadMesh(const QSSGRenderMeshPath &inMeshPath return meshItr.value(); // loading new mesh - QSSGMeshUtilities::MultiLoadResult result; - - // check to see if this is a primitive mesh - if (inMeshPath.path.startsWith('#')) - result = loadPrimitive(inMeshPath.path); - - // Attempt a load from the filesystem if this mesh isn't a primitive. - if (result.m_mesh == nullptr) { - QString pathBuilder = inMeshPath.path; - int poundIndex = pathBuilder.lastIndexOf('#'); - int id = 0; - if (poundIndex != -1) { - id = pathBuilder.midRef(poundIndex + 1).toInt(); - pathBuilder = pathBuilder.left(poundIndex); - } - if (!pathBuilder.isEmpty()) { - QSharedPointer<QIODevice> ioStream(inputStreamFactory->getStreamForFile(pathBuilder)); - if (ioStream) - result = QSSGMeshUtilities::Mesh::loadMulti(*ioStream, id); - } - } + QSSGMeshUtilities::MultiLoadResult result = loadMeshData(inMeshPath); if (result.m_mesh == nullptr) { qCWarning(WARNING, "Failed to load mesh: %s", qPrintable(inMeshPath.path)); @@ -642,6 +618,51 @@ QSSGRenderMesh *QSSGBufferManager::loadCustomMesh(const QSSGRenderMeshPath &inSo return nullptr; } +QSSGMeshBVH *QSSGBufferManager::loadMeshBVH(const QSSGRenderMeshPath &inSourcePath) +{ + // loading new mesh + QSSGMeshUtilities::MultiLoadResult result = loadMeshData(inSourcePath); + + if (result.m_mesh == nullptr) { + qCWarning(WARNING, "Failed to load mesh: %s", qPrintable(inSourcePath.path)); + return nullptr; + } + + // Build BVH for Mesh + QSSGMeshBVHBuilder meshBVHBuilder(result.m_mesh); + auto bvh = meshBVHBuilder.buildTree(); + + ::free(result.m_mesh); + return bvh; +} + +QSSGMeshUtilities::MultiLoadResult QSSGBufferManager::loadMeshData(const QSSGRenderMeshPath &inMeshPath) const +{ + // loading new mesh + QSSGMeshUtilities::MultiLoadResult result; + + // check to see if this is a primitive mesh + if (inMeshPath.path.startsWith('#')) + result = loadPrimitive(inMeshPath.path); + + // Attempt a load from the filesystem if this mesh isn't a primitive. + if (result.m_mesh == nullptr) { + QString pathBuilder = inMeshPath.path; + int poundIndex = pathBuilder.lastIndexOf('#'); + int id = 0; + if (poundIndex != -1) { + id = pathBuilder.midRef(poundIndex + 1).toInt(); + pathBuilder = pathBuilder.left(poundIndex); + } + if (!pathBuilder.isEmpty()) { + QSharedPointer<QIODevice> ioStream(inputStreamFactory->getStreamForFile(pathBuilder)); + if (ioStream) + result = QSSGMeshUtilities::Mesh::loadMulti(*ioStream, id); + } + } + return result; +} + QSSGRenderMesh *QSSGBufferManager::createMesh(const QString &inSourcePath, quint8 *inVertData, quint32 inNumVerts, quint32 inVertStride, quint32 *inIndexData, quint32 inIndexCount, QSSGBounds3 inBounds) { QString sourcePath = inSourcePath; diff --git a/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h b/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h index 9fb1ef17d..8cdc67f28 100644 --- a/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h +++ b/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h @@ -57,6 +57,7 @@ struct QSSGRenderMesh; struct QSSGLoadedTexture; class QSSGRenderContext; class QSSGInputStreamFactory; +struct QSSGMeshBVH; namespace QSSGMeshUtilities { struct MultiLoadResult; } @@ -136,6 +137,8 @@ public: QSSGRenderMesh *loadCustomMesh(const QSSGRenderMeshPath &inSourcePath, QSSGMeshUtilities::Mesh *mesh, bool update = false); + QSSGMeshBVH *loadMeshBVH(const QSSGRenderMeshPath &inSourcePath); + QSSGMeshUtilities::MultiLoadResult loadMeshData(const QSSGRenderMeshPath &inSourcePath) const; QSSGRenderMesh *createMesh(const QString &inSourcePath, quint8 *inVertData, -- GitLab