diff --git a/src/runtimerender/rendererimpl/qssgrendererimpllayerrenderpreparationdata.cpp b/src/runtimerender/rendererimpl/qssgrendererimpllayerrenderpreparationdata.cpp index 446a543f45d26c0c1d60052edfb5631e87270e48..291f33a578fd899422e8bfd094e636e0a2f3ba3a 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 0ad000a84ee137b5aca66d2f974fc4b6f5a37970..d53d2c1d1dffe7743c8eee11b95be5fce84989ec 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 9fb1ef17dcc05dcb5ab96db0d969ba544c45d2be..8cdc67f2871c8b30985f050117a4148610ab2e1a 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,