diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index e49e015c2d..b835938812 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -33,19 +33,6 @@ #include "FBXBaker.h" -#ifdef _WIN32 -#pragma warning( push ) -#pragma warning( disable : 4267 ) -#endif - -#include -#include - -#ifdef _WIN32 -#pragma warning( pop ) -#endif - - FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : _fbxURL(fbxURL), @@ -254,72 +241,6 @@ void FBXBaker::importScene() { _textureContent = reader._textureContent; } -QString texturePathRelativeToFBX(QUrl fbxURL, QUrl textureURL) { - auto fbxPath = fbxURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); - auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment); - - if (texturePath.startsWith(fbxPath)) { - // texture path is a child of the FBX path, return the texture path without the fbx path - return texturePath.mid(fbxPath.length()); - } else { - // the texture path was not a child of the FBX path, return the empty string - return ""; - } -} - -QString FBXBaker::createBakedTextureFileName(const QFileInfo& textureFileInfo) { - // first make sure we have a unique base name for this texture - // in case another texture referenced by this model has the same base name - auto& nameMatches = _textureNameMatchCount[textureFileInfo.baseName()]; - - QString bakedTextureFileName{ textureFileInfo.completeBaseName() }; - - if (nameMatches > 0) { - // there are already nameMatches texture with this name - // append - and that number to our baked texture file name so that it is unique - bakedTextureFileName += "-" + QString::number(nameMatches); - } - - bakedTextureFileName += BAKED_TEXTURE_EXT; - - // increment the number of name matches - ++nameMatches; - - return bakedTextureFileName; -} - -QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded) { - - QUrl urlToTexture; - - auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/")); - - if (isEmbedded) { - urlToTexture = _fbxURL.toString() + "/" + apparentRelativePath.filePath(); - } else { - if (textureFileInfo.exists() && textureFileInfo.isFile()) { - // set the texture URL to the local texture that we have confirmed exists - urlToTexture = QUrl::fromLocalFile(textureFileInfo.absoluteFilePath()); - } else { - // external texture that we'll need to download or find - - // this is a relative file path which will require different handling - // depending on the location of the original FBX - if (_fbxURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) { - // the absolute path we ran into for the texture in the FBX exists on this machine - // so use that file - urlToTexture = QUrl::fromLocalFile(apparentRelativePath.absoluteFilePath()); - } else { - // we didn't find the texture on this machine at the absolute path - // so assume that it is right beside the FBX to match the behaviour of interface - urlToTexture = _fbxURL.resolved(apparentRelativePath.fileName()); - } - } - } - - return urlToTexture; -} - void FBXBaker::rewriteAndBakeSceneModels() { unsigned int meshIndex = 0; bool hasDeformers{ false }; @@ -343,17 +264,21 @@ void FBXBaker::rewriteAndBakeSceneModels() { // TODO Pull this out of _geometry instead so we don't have to reprocess it auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false); - + // Callback to get MaterialID from FBXBaker in ModelBaker - getMaterialIDCallback materialIDcallback = [extractedMesh](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; + getMaterialIDCallback materialIDcallback = [=](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;}; + // Compress mesh information and store in dracoMeshNode - FBXNode* dracoMeshNode = this->compressMesh(extractedMesh.mesh, hasDeformers, materialIDcallback); - // if dracoMeshNode is null (i.e error occurred while baking), continue iterating through Object node children - if (!dracoMeshNode) { + FBXNode dracoMeshNode; + bool success = this->compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback); + + // if bake fails continue iterating through Object node's children + if (!success) { continue; } - objectChild.children.push_back(*dracoMeshNode); + //objectChild.children.push_back(*dracoMeshNode); + objectChild.children.push_back(dracoMeshNode); static const std::vector nodeNamesToDelete{ // Node data that is packed into the draco mesh @@ -388,7 +313,6 @@ void FBXBaker::rewriteAndBakeSceneModels() { } } - void FBXBaker::rewriteAndBakeSceneTextures() { using namespace image::TextureUsage; QHash textureTypes; @@ -430,99 +354,36 @@ void FBXBaker::rewriteAndBakeSceneTextures() { for (FBXNode& textureChild : object->children) { if (textureChild.name == "RelativeFilename") { - - // use QFileInfo to easily split up the existing texture filename into its components QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; - - // Callback to get texture content and type from FBXBaker in ModelBaker - //auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); - //qCDebug(model_baking) << "TextureContent" << textureContent.size(); - - getTextureContentTypeCallback textureContentTypeCallback = [=]() { - QPair result; - result.first = _textureContent.value(fbxTextureFileName.toLocal8Bit());; - result.second = textureTypes[object->properties[0].toByteArray()]; - return result; - }; + QByteArray textureContent = ""; + QFileInfo fbxTextureFileInfo{ fbxTextureFileName.replace("\\", "/") }; + // Callback to get texture content and type from FBXBaker in ModelBaker + if (!fbxTextureFileInfo.filePath().isEmpty()) { + textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); + } - // Compress the texture information and return the new filename to be added into the FBX scene - QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); - - // If no errors or warnings have occurred during texture compression add the filename to the FBX scene - if (bakedTextureFile) { - textureChild.properties[0] = *bakedTextureFile; - } else { - if (hasErrors()) { - return; - } else if (hasWarnings()) { - continue; - } - } + getTextureContentTypeCallback textureContentTypeCallback = [=]() { + QPair result; + result.first = textureContent;// _textureContent.value(fbxTextureFileName.toLocal8Bit()); + auto textureID{ object->properties[0].toByteArray() }; + auto textureType = textureTypes[textureID]; + result.second = textureType; + return result; + }; + // Compress the texture information and return the new filename to be added into the FBX scene + QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); - //QFileInfo textureFileInfo{ fbxTextureFileName.replace("\\", "/") }; - - //if (hasErrors()) { - // return; - //} - - //if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { - // // re-baking an FBX that already references baked textures is a fail - // // so we add an error and return from here - // handleError("Cannot re-bake a file that references compressed textures"); - - // return; - //} - - //if (!TextureBaker::getSupportedFormats().contains(textureFileInfo.suffix())) { - // // this is a texture format we don't bake, skip it - // handleWarning(fbxTextureFileName + " is not a bakeable texture format"); - // continue; - //} - - //// make sure this texture points to something and isn't one we've already re-mapped - //if (!textureFileInfo.filePath().isEmpty()) { - // // check if this was an embedded texture we have already have in-memory content for - // auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); - - // // figure out the URL to this texture, embedded or external - // qCDebug(model_baking) << "TextureContent" << textureContent.size(); - // auto urlToTexture = getTextureURL(textureFileInfo, fbxTextureFileName, - // !textureContent.isNull()); - - // QString bakedTextureFileName; - // if (_remappedTexturePaths.contains(urlToTexture)) { - // bakedTextureFileName = _remappedTexturePaths[urlToTexture]; - // } else { - // // construct the new baked texture file name and file path - // // ensuring that the baked texture will have a unique name - // // even if there was another texture with the same name at a different path - // bakedTextureFileName = createBakedTextureFileName(textureFileInfo); - // _remappedTexturePaths[urlToTexture] = bakedTextureFileName; - // } - - // qCDebug(model_baking).noquote() << "Re-mapping" << fbxTextureFileName - // << "to" << bakedTextureFileName; - - // QString bakedTextureFilePath{ - // _bakedOutputDir + "/" + bakedTextureFileName - // }; - - // // write the new filename into the FBX scene - // textureChild.properties[0] = bakedTextureFileName.toLocal8Bit(); - - // if (!_bakingTextures.contains(urlToTexture)) { - // _outputFiles.push_back(bakedTextureFilePath); - - // // grab the ID for this texture so we can figure out the - // // texture type from the loaded materials - // QString textureID{ object->properties[0].toByteArray() }; - // auto textureType = textureTypes[textureID]; - - // // bake this texture asynchronously - // bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); - // } - //} + // If no errors or warnings have occurred during texture compression add the filename to the FBX scene + if (bakedTextureFile) { + textureChild.properties[0] = *bakedTextureFile; + } else { + if (hasErrors()) { + return; + } else if (hasWarnings()) { + continue; + } + } } } @@ -539,203 +400,6 @@ void FBXBaker::rewriteAndBakeSceneTextures() { } } -//void FBXBaker::rewriteAndBakeSceneTextures() { -// using namespace image::TextureUsage; -// QHash textureTypes; -// -// // enumerate the materials in the extracted geometry so we can determine the texture type for each texture ID -// for (const auto& material : _geometry->materials) { -// if (material.normalTexture.isBumpmap) { -// textureTypes[material.normalTexture.id] = BUMP_TEXTURE; -// } else { -// textureTypes[material.normalTexture.id] = NORMAL_TEXTURE; -// } -// -// textureTypes[material.albedoTexture.id] = ALBEDO_TEXTURE; -// textureTypes[material.glossTexture.id] = GLOSS_TEXTURE; -// textureTypes[material.roughnessTexture.id] = ROUGHNESS_TEXTURE; -// textureTypes[material.specularTexture.id] = SPECULAR_TEXTURE; -// textureTypes[material.metallicTexture.id] = METALLIC_TEXTURE; -// textureTypes[material.emissiveTexture.id] = EMISSIVE_TEXTURE; -// textureTypes[material.occlusionTexture.id] = OCCLUSION_TEXTURE; -// textureTypes[material.lightmapTexture.id] = LIGHTMAP_TEXTURE; -// } -// -// // enumerate the children of the root node -// for (FBXNode& rootChild : _rootNode.children) { -// -// if (rootChild.name == "Objects") { -// -// // enumerate the objects -// auto object = rootChild.children.begin(); -// while (object != rootChild.children.end()) { -// if (object->name == "Texture") { -// -// // double check that we didn't get an abort while baking the last texture -// if (shouldStop()) { -// return; -// } -// -// // enumerate the texture children -// for (FBXNode& textureChild : object->children) { -// -// if (textureChild.name == "RelativeFilename") { -// QString fbxTextureFileName{ textureChild.properties.at(0).toByteArray() }; -// -// // Callback to get texture content and type from FBXBaker in ModelBaker -// auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); -// qCDebug(model_baking) << "TextureContent" << textureContent; -// -// getTextureContentTypeCallback textureContentTypeCallback = [fbxTextureFileName, textureTypes, object, textureContent]() { -// QPair result; -// result.first = textureContent; -// result.second = textureTypes[object->properties[0].toByteArray()]; -// return result; -// }; -// -// // Compress the texture information and return the new filename to be added into the FBX scene -// QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, _fbxURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback, _originalOutputDir); -// -// // If no errors or warnings have occurred during texture compression add the filename to the FBX scene -// if (bakedTextureFile) { -// textureChild.properties[0] = *bakedTextureFile; -// } else { -// if (hasErrors()) { -// return; -// } else if (hasWarnings()) { -// continue; -// } -// } -// } -// } -// -// ++object; -// -// } else if (object->name == "Video") { -// // this is an embedded texture, we need to remove it from the FBX -// object = rootChild.children.erase(object); -// } else { -// ++object; -// } -// } -// } -// } -//} - -void FBXBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { - // start a bake for this texture and add it to our list to keep track of - QSharedPointer bakingTexture{ - new TextureBaker(textureURL, textureType, outputDir, bakedFilename, textureContent), - &TextureBaker::deleteLater - }; - - // make sure we hear when the baking texture is done or aborted - connect(bakingTexture.data(), &Baker::finished, this, &FBXBaker::handleBakedTexture); - connect(bakingTexture.data(), &TextureBaker::aborted, this, &FBXBaker::handleAbortedTexture); - - // keep a shared pointer to the baking texture - _bakingTextures.insert(textureURL, bakingTexture); - - // start baking the texture on one of our available worker threads - bakingTexture->moveToThread(_textureThreadGetter()); - QMetaObject::invokeMethod(bakingTexture.data(), "bake"); -} - -void FBXBaker::handleBakedTexture() { - TextureBaker* bakedTexture = qobject_cast(sender()); - - // make sure we haven't already run into errors, and that this is a valid texture - if (bakedTexture) { - if (!shouldStop()) { - if (!bakedTexture->hasErrors()) { - if (!_originalOutputDir.isEmpty()) { - // we've been asked to make copies of the originals, so we need to make copies of this if it is a linked texture - - // use the path to the texture being baked to determine if this was an embedded or a linked texture - - // it is embeddded if the texure being baked was inside a folder with the name of the FBX - // since that is the fake URL we provide when baking external textures - - if (!_fbxURL.isParentOf(bakedTexture->getTextureURL())) { - // for linked textures we want to save a copy of original texture beside the original FBX - - qCDebug(model_baking) << "Saving original texture for" << bakedTexture->getTextureURL(); - - // check if we have a relative path to use for the texture - auto relativeTexturePath = texturePathRelativeToFBX(_fbxURL, bakedTexture->getTextureURL()); - - QFile originalTextureFile{ - _originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName() - }; - - if (relativeTexturePath.length() > 0) { - // make the folders needed by the relative path - } - - if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) { - qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName() - << "for" << _fbxURL; - } else { - handleError("Could not save original external texture " + originalTextureFile.fileName() - + " for " + _fbxURL.toString()); - return; - } - } - } - - - // now that this texture has been baked and handled, we can remove that TextureBaker from our hash - _bakingTextures.remove(bakedTexture->getTextureURL()); - - checkIfTexturesFinished(); - } else { - // there was an error baking this texture - add it to our list of errors - _errorList.append(bakedTexture->getErrors()); - - // we don't emit finished yet so that the other textures can finish baking first - _pendingErrorEmission = true; - - // now that this texture has been baked, even though it failed, we can remove that TextureBaker from our list - _bakingTextures.remove(bakedTexture->getTextureURL()); - - // abort any other ongoing texture bakes since we know we'll end up failing - for (auto& bakingTexture : _bakingTextures) { - bakingTexture->abort(); - } - - checkIfTexturesFinished(); - } - } else { - // we have errors to attend to, so we don't do extra processing for this texture - // but we do need to remove that TextureBaker from our list - // and then check if we're done with all textures - _bakingTextures.remove(bakedTexture->getTextureURL()); - - checkIfTexturesFinished(); - } - } -} - -void FBXBaker::handleAbortedTexture() { - // grab the texture bake that was aborted and remove it from our hash since we don't need to track it anymore - TextureBaker* bakedTexture = qobject_cast(sender()); - - if (bakedTexture) { - _bakingTextures.remove(bakedTexture->getTextureURL()); - } - - // since a texture we were baking aborted, our status is also aborted - _shouldAbort.store(true); - - // abort any other ongoing texture bakes since we know we'll end up failing - for (auto& bakingTexture : _bakingTextures) { - bakingTexture->abort(); - } - - checkIfTexturesFinished(); -} - void FBXBaker::exportScene() { // save the relative path to this FBX inside our passed output folder auto fileName = _fbxURL.fileName(); @@ -781,13 +445,3 @@ void FBXBaker::checkIfTexturesFinished() { } } } - -void FBXBaker::setWasAborted(bool wasAborted) { - if (wasAborted != _wasAborted.load()) { - Baker::setWasAborted(wasAborted); - - if (wasAborted) { - qCDebug(model_baking) << "Aborted baking" << _fbxURL; - } - } -} diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index dbb7ab823e..b76d3699b5 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -40,9 +40,7 @@ public: QUrl getFBXUrl() const { return _fbxURL; } QString getBakedFBXFilePath() const { return _bakedFBXFilePath; } - virtual void setWasAborted(bool wasAborted) override; - - public slots: +public slots: virtual void bake() override; virtual void abort() override; @@ -52,8 +50,6 @@ signals: private slots: void bakeSourceCopy(); void handleFBXNetworkReply(); - void handleBakedTexture(); - void handleAbortedTexture(); private: void setupOutputFolder(); @@ -68,12 +64,6 @@ private: void checkIfTexturesFinished(); - QString createBakedTextureFileName(const QFileInfo& textureFileInfo); - QUrl getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded = false); - - void bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDir, - const QString& bakedFilename, const QByteArray& textureContent = QByteArray()); - QUrl _fbxURL; FBXNode _rootNode; diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 1ac27ce570..0770574035 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -12,29 +12,11 @@ #include "ModelBaker.h" #include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - #include #include #include -#include "ModelBakingLoggingCategory.h" -#include "TextureBaker.h" - -#include "FBXBaker.h" - #ifdef _WIN32 #pragma warning( push ) #pragma warning( disable : 4267 ) @@ -51,20 +33,10 @@ ModelBaker::ModelBaker() {} void ModelBaker::bake() {} -//void ModelBaker::abort() { -// Baker::abort(); -// -// // tell our underlying TextureBaker instances to abort -// // the FBXBaker will wait until all are aborted before emitting its own abort signal -// for (auto& textureBaker : _bakingTextures) { -// textureBaker->abort(); -// } -//} - -FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialIDCallback materialIDCallback) { +bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback) { if (mesh.wasCompressed) { handleError("Cannot re-bake a file that contains compressed mesh"); - return nullptr; + return false; } Q_ASSERT(mesh.normals.size() == 0 || mesh.normals.size() == mesh.vertices.size()); @@ -82,7 +54,7 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI } if (numTriangles == 0) { - return nullptr; + return false; } draco::TriangleSoupMeshBuilder meshBuilder; @@ -93,7 +65,7 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI bool hasColors{ mesh.colors.size() > 0 }; bool hasTexCoords{ mesh.texCoords.size() > 0 }; bool hasTexCoords1{ mesh.texCoords1.size() > 0 }; - bool hasPerFaceMaterials; + bool hasPerFaceMaterials;// { mesh.parts.size() > 1 }; if (materialIDCallback) { if (mesh.parts.size() > 1 || materialIDCallback(0) != 0) { hasPerFaceMaterials = true; @@ -101,7 +73,6 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI } else { hasPerFaceMaterials = true; } - bool needsOriginalIndices{ hasDeformers }; int normalsAttributeID{ -1 }; @@ -153,7 +124,6 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI } else { materialID = partIndex; } - auto addFace = [&](QVector& indices, int index, draco::FaceIndex face) { int32_t idx0 = indices[index]; int32_t idx1 = indices[index + 1]; @@ -210,7 +180,7 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI if (!dracoMesh) { handleWarning("Failed to finalize the baking of a draco Geometry node"); - return nullptr; + return false; } // we need to modify unique attribute IDs for custom attributes @@ -237,12 +207,13 @@ FBXNode* ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialI draco::EncoderBuffer buffer; encoder.EncodeMeshToBuffer(*dracoMesh, &buffer); - static FBXNode dracoMeshNode; - dracoMeshNode.name = "DracoMesh"; + FBXNode dracoNode; + dracoNode.name = "DracoMesh"; auto value = QVariant::fromValue(QByteArray(buffer.data(), (int)buffer.size())); - dracoMeshNode.properties.append(value); - - return &dracoMeshNode; + dracoNode.properties.append(value); + + dracoMeshNode = dracoNode; + return true; } QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl modelURL, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, @@ -254,12 +225,16 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model static QByteArray textureChild; QPair textureContentType; + QByteArray textureContent; + image::TextureUsage::Type textureType; // grab the ID for this texture so we can figure out the // texture type from the loaded materials - textureContentType = textureContentTypeCallback(); + if (textureContentTypeCallback) { + textureContentType = textureContentTypeCallback(); + textureContent = textureContentType.first; + textureType = textureContentType.second; + } - QByteArray textureContent = textureContentType.first; - image::TextureUsage::Type textureType = textureContentType.second; QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; @@ -281,9 +256,8 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model // check if this was an embedded texture that we already have in-memory content for // figure out the URL to this texture, embedded or external - //qCDebug(model_baking) << "TextureContent" << !textureContent.isNull(); - auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, - true); + qCDebug(model_baking) << "TextureContent" << !textureContent.isNull(); + auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull()); QString bakedTextureFileName; if (_remappedTexturePaths.contains(urlToTexture)) { @@ -310,7 +284,6 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, QUrl model _outputFiles.push_back(bakedTextureFilePath); // bake this texture asynchronously - qCDebug(model_baking) << "URLHere" << urlToTexture; bakeTexture(urlToTexture, textureType, bakedOutputDir, bakedTextureFileName, textureContent); } } diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index efe6dff874..e132591120 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -35,14 +35,13 @@ class ModelBaker : public Baker{ public: ModelBaker(); - FBXNode* compressMesh(FBXMesh& mesh, bool hasDeformers, getMaterialIDCallback materialIDCallback = NULL); + bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL); QByteArray* compressTexture(QString textureFileName, QUrl modelUrl, QString bakedOutputDir, TextureBakerThreadGetter textureThreadGetter, getTextureContentTypeCallback textureContentTypeCallback = NULL, const QString& originalOutputDir = ""); virtual void setWasAborted(bool wasAborted) override; public slots: virtual void bake() override; - //virtual void abort() override; private slots: void handleBakedTexture(); diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index a0eed5c5a8..1f6d820b8c 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -16,6 +16,8 @@ #include "OBJReader.h" #include "FBXWriter.h" +const double UNIT_SCALE_FACTOR = 100; + OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter, const QString& bakedOutputDir, const QString& originalOutputDir) : _objURL(objURL), @@ -149,7 +151,7 @@ void OBJBaker::startBake() { QByteArray objData = objFile.readAll(); - bool combineParts = true; + bool combineParts = true; // set true so that OBJReader reads material info from material library OBJReader reader; FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _objURL); @@ -211,8 +213,9 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Compress the mesh information and store in dracoNode bool hasDeformers = false; ModelBaker modelBaker; - FBXNode* dracoNode = this->compressMesh(geometry->meshes[0], hasDeformers); - geometryNode.children.append(*dracoNode); + FBXNode dracoNode; + this->compressMesh(geometry->meshes[0], hasDeformers, dracoNode); + geometryNode.children.append(dracoNode); // Generating Object node's child - Model node FBXNode modelNode; @@ -222,7 +225,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Generating Objects node's child - Material node QVector meshParts = geometry->meshes[0].parts; - for (auto p : meshParts) { + for (auto meshPart : meshParts) { FBXNode materialNode; materialNode.name = "Material"; if (geometry->materials.size() == 1) { @@ -230,106 +233,52 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { setMaterialNodeProperties(&materialNode, materialID, geometry); } } else { - setMaterialNodeProperties(&materialNode, p.materialID, geometry); + setMaterialNodeProperties(&materialNode, meshPart.materialID, geometry); } _objectNode.children.append(materialNode); } - // Texture Node + // Generating Texture Node int count = 0; + // iterate through mesh parts and process the associated textures for (int i = 0;i < meshParts.size();i++) { QString material = meshParts[i].materialID; FBXMaterial currentMaterial = geometry->materials[material]; if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) { _textureID = _nodeID; - mapTextureMaterial.push_back(QPair(_textureID, i)); + _mapTextureMaterial.push_back(QPair(_textureID, i)); QVariant property0(_nodeID++); FBXNode textureNode; textureNode.name = "Texture"; textureNode.properties = { property0 }; - + + // Texture node child - TextureName node FBXNode textureNameNode; textureNameNode.name = "TextureName"; QByteArray propertyString = (!currentMaterial.albedoTexture.filename.isEmpty()) ? "Kd" : "Ka"; auto prop0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); textureNameNode.properties = { prop0 }; + // Texture node child - Relative Filename node FBXNode relativeFilenameNode; relativeFilenameNode.name = "RelativeFilename"; QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename; + + // Callback to get Texture content and type getTextureContentTypeCallback textureContentTypeCallback = [=]() { QPair result; result.first = NULL; result.second = (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE; return result; }; + + // Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node QByteArray* textureFile = this->compressTexture(textureFileName, _objURL, _bakedOutputDir, _textureThreadGetter, textureContentTypeCallback,_originalOutputDir); QVariant textureProperty0; textureProperty0 = QVariant::fromValue(QByteArray(textureFile->data(), (int)textureFile->size())); relativeFilenameNode.properties = { textureProperty0 }; - - FBXNode properties70Node; - properties70Node.name = "Properties70"; - - QVariant texProperty0; - QVariant texProperty1; - QVariant texProperty2; - QVariant texProperty3; - QVariant texProperty4; - - double value; - - // Set UseMaterial - FBXNode pUseMaterial; - pUseMaterial.name = "P"; - propertyString = "UseMaterial"; - texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "bool"; - texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - int texVal = 1; - texProperty4 = texVal; - - pUseMaterial.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; - - FBXNode pUVSet; - pUVSet.name = "P"; - propertyString = "UVSet"; - texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "KString"; - texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty4 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - pUVSet.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; - - FBXNode pUseMipMap; - pUseMipMap.name = "P"; - propertyString = "UseMipMap"; - texProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "bool"; - texProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - texProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - - texVal = 1; - texProperty4 = texVal; - - pUseMipMap.properties = { texProperty0, texProperty1, texProperty2, texProperty3, texProperty4 }; - - properties70Node.children = { pUVSet, pUseMaterial, pUseMipMap }; - - textureNode.children = { textureNameNode,relativeFilenameNode, properties70Node }; + textureNode.children = { textureNameNode,relativeFilenameNode }; _objectNode.children.append(textureNode); } @@ -338,7 +287,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { // Generating Connections node FBXNode connectionsNode; connectionsNode.name = "Connections"; - // connect Geometry -> Model + // connect Geometry to Model FBXNode cNode1; cNode1.name = "C"; QByteArray propertyString("OO"); @@ -350,7 +299,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { cNode1.properties = { property0, property1, property2 }; connectionsNode.children = { cNode1}; - // connect materials to model + // connect all materials to model for (int i = 0;i < geometry->materials.size();i++) { FBXNode cNode; cNode.name = "C"; @@ -361,14 +310,14 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { connectionsNode.children.append(cNode); } - // Texture to material - for (int i = 0;i < mapTextureMaterial.size();i++) { + // Connect textures to materials + for (int i = 0;i < _mapTextureMaterial.size();i++) { FBXNode cNode2; cNode2.name = "C"; QByteArray propertyString1("OP"); property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); - property1 = mapTextureMaterial[i].first; - int matID = mapTextureMaterial[i].second; + property1 = _mapTextureMaterial[i].first; + int matID = _mapTextureMaterial[i].second; property2 = _materialIDs[matID]; propertyString1 = "AmbientFactor"; QVariant connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); @@ -379,7 +328,7 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { cNode4.name = "C"; propertyString1 = "OP"; property0 = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); - property1 = mapTextureMaterial[i].first; + property1 = _mapTextureMaterial[i].first; property2 = _materialIDs[matID]; propertyString1 = "DiffuseColor"; connectionProperty = QVariant::fromValue(QByteArray(propertyString1.data(), (int)propertyString1.size())); @@ -388,24 +337,16 @@ void OBJBaker::createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry) { } - // Connect all generated nodes to rootNode + // Make all generated nodes children of rootNode objRoot->children = { globalSettingsNode, _objectNode, connectionsNode }; } void OBJBaker::setProperties(FBXNode* parentNode) { if (parentNode->name == "P") { - QByteArray propertyString("UnitScaleFactor"); - QVariant property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "double"; - QVariant property1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Number"; - QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - QVariant property3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - double unitScaleFactor = 100; - QVariant property4(unitScaleFactor); + std::vector stringProperties{ "UnitScaleFactor", "double", "Number", "" }; + std::vector numericProperties{ UNIT_SCALE_FACTOR }; - parentNode->properties = { property0, property1, property2, property3, property4 }; + setPropertiesList(stringProperties, numericProperties, parentNode->properties); } else if (parentNode->name == "Geometry") { _geometryID = _nodeID; QVariant property0(_nodeID++); @@ -443,91 +384,58 @@ void OBJBaker::setMaterialNodeProperties(FBXNode* materialNode, QString material FBXNode properties70Node; properties70Node.name = "Properties70"; - QVariant materialProperty0; - QVariant materialProperty1; - QVariant materialProperty2; - QVariant materialProperty3; - QVariant materialProperty4; - QVariant materialProperty5; - QVariant materialProperty6; - - double value; - // Set diffuseColor FBXNode pNodeDiffuseColor; pNodeDiffuseColor.name = "P"; - propertyString = "DiffuseColor"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Color"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.diffuseColor[0]; - materialProperty4 = value; - value = (double)currentMaterial.diffuseColor[1]; - materialProperty5 = value; - value = (double)currentMaterial.diffuseColor[2]; - materialProperty6 = value; - pNodeDiffuseColor.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4, materialProperty5, materialProperty6 }; + std::vector stringProperties{ "DiffuseColor", "Color", "", "A" }; + std::vector numericProperties{ currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] }; + setPropertiesList(stringProperties, numericProperties, pNodeDiffuseColor.properties); + properties70Node.children.append(pNodeDiffuseColor); // Set specularColor FBXNode pNodeSpecularColor; pNodeSpecularColor.name = "P"; - propertyString = "SpecularColor"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Color"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.specularColor[0]; - materialProperty4 = value; - value = (double)currentMaterial.specularColor[1]; - materialProperty5 = value; - value = (double)currentMaterial.specularColor[2]; - materialProperty6 = value; - pNodeSpecularColor.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4, materialProperty5, materialProperty6 }; + stringProperties = { "SpecularColor", "Color", "", "A" }; + numericProperties = { currentMaterial.specularColor[0], currentMaterial.specularColor[1], currentMaterial.specularColor[2] }; + setPropertiesList(stringProperties, numericProperties, pNodeSpecularColor.properties); + properties70Node.children.append(pNodeSpecularColor); // Set Shininess FBXNode pNodeShininess; pNodeShininess.name = "P"; - propertyString = "Shininess"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Number"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.shininess; - materialProperty4 = value; - pNodeShininess.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4 }; + stringProperties = { "Shininess", "Number", "", "A" }; + numericProperties = { currentMaterial.shininess }; + setPropertiesList(stringProperties, numericProperties, pNodeShininess.properties); + properties70Node.children.append(pNodeShininess); // Set Opacity FBXNode pNodeOpacity; pNodeOpacity.name = "P"; - propertyString = "Opacity"; - materialProperty0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "Number"; - materialProperty1 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = ""; - materialProperty2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - propertyString = "A"; - materialProperty3 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size())); - value = (double)currentMaterial.opacity; - materialProperty4 = value; - pNodeOpacity.properties = { materialProperty0, materialProperty1, materialProperty2, materialProperty3, materialProperty4 }; + stringProperties = { "Opacity", "Number", "", "A" }; + numericProperties = { currentMaterial.opacity }; + setPropertiesList(stringProperties, numericProperties, pNodeOpacity.properties); + properties70Node.children.append(pNodeOpacity); materialNode->children.append(properties70Node); } + +template +void OBJBaker::setPropertiesList(std::vector stringProperties, std::vector numericProperties, QVariantList& propertiesList) { + foreach(auto stringProperty, stringProperties) { + auto propertyValue = QVariant::fromValue(QByteArray(stringProperty.data(), (int)stringProperty.size())); + propertiesList.append(propertyValue); + } + + foreach(auto numberProperty, numericProperties) { + QVariant propertyValue(numberProperty); + propertiesList.append(propertyValue); + } +} diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index 2d894c6626..d331d3bde1 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -31,7 +31,9 @@ public: void createFBXNodeTree(FBXNode* objRoot, FBXGeometry* geometry); void setProperties(FBXNode * parentNode); void setMaterialNodeProperties(FBXNode* materialNode, QString material, FBXGeometry* geometry); - + template + void setPropertiesList(std::vector stringProperties, std::vector numericProperties, QVariantList& propertiesList); + public slots: virtual void bake() override; @@ -57,7 +59,7 @@ private: qlonglong _modelID; std::vector _materialIDs; qlonglong _textureID; - std::vector> mapTextureMaterial; + std::vector> _mapTextureMaterial; FBXNode _objectNode; }; #endif // hifi_OBJBaker_h diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index d733a23d23..99727b0df6 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -269,4 +269,4 @@ void ModelBakeWidget::handleFinishedBaker() { _bakers.erase(it); } -} \ No newline at end of file +}