mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 07:23:39 +02:00
add basic Oven QCoreApplication, start to output results
This commit is contained in:
parent
711938fb3d
commit
1b30afa03e
6 changed files with 182 additions and 28 deletions
|
@ -2,6 +2,8 @@ set(TARGET_NAME model-baking)
|
||||||
|
|
||||||
setup_hifi_library()
|
setup_hifi_library()
|
||||||
|
|
||||||
|
link_hifi_libraries(networking)
|
||||||
|
|
||||||
find_package(FBXSDK REQUIRED)
|
find_package(FBXSDK REQUIRED)
|
||||||
target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES})
|
||||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${FBX_INCLUDE_DIR})
|
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${FBX_INCLUDE_DIR})
|
||||||
|
|
|
@ -10,33 +10,117 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <fbxsdk.h>
|
#include <fbxsdk.h>
|
||||||
#include <fbxsdk/scene/shading/fbxlayeredtexture.h>
|
|
||||||
|
|
||||||
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
#include <QThread>
|
|
||||||
|
#include <NetworkAccessManager.h>
|
||||||
|
|
||||||
#include "FBXBaker.h"
|
#include "FBXBaker.h"
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(model_baking, "hifi.model-baking");
|
Q_LOGGING_CATEGORY(model_baking, "hifi.model-baking");
|
||||||
|
|
||||||
FBXBaker::FBXBaker(QUrl fbxPath) :
|
FBXBaker::FBXBaker(QUrl fbxURL, QString baseOutputPath) :
|
||||||
_fbxPath(fbxPath)
|
_fbxURL(fbxURL),
|
||||||
|
_baseOutputPath(baseOutputPath)
|
||||||
{
|
{
|
||||||
// create an FBX SDK manager
|
// create an FBX SDK manager
|
||||||
_sdkManager = FbxManager::Create();
|
_sdkManager = FbxManager::Create();
|
||||||
|
|
||||||
|
// grab the name of the FBX from the URL, this is used for folder output names
|
||||||
|
auto fileName = fbxURL.fileName();
|
||||||
|
_fbxName = fileName.left(fileName.indexOf('.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXBaker::~FBXBaker() {
|
FBXBaker::~FBXBaker() {
|
||||||
_sdkManager->Destroy();
|
_sdkManager->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FBXBaker::start() {
|
void FBXBaker::start() {
|
||||||
|
// setup the output folder for the results of this bake
|
||||||
|
if (!setupOutputFolder()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// check if the FBX is local or first needs to be downloaded
|
// check if the FBX is local or first needs to be downloaded
|
||||||
if (_fbxPath.isLocalFile()) {
|
if (_fbxURL.isLocalFile()) {
|
||||||
// local file, bake now
|
// load up the local file
|
||||||
|
QFile localFBX { _fbxURL.toLocalFile() };
|
||||||
|
|
||||||
|
// make a copy in the output folder
|
||||||
|
localFBX.copy(_uniqueOutputPath + _fbxURL.fileName());
|
||||||
|
|
||||||
|
// start the bake now that we have everything in place
|
||||||
bake();
|
bake();
|
||||||
} else {
|
} else {
|
||||||
// remote file, kick off a download
|
// remote file, kick off a download
|
||||||
|
auto& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
|
||||||
|
QNetworkRequest networkRequest;
|
||||||
|
|
||||||
|
// setup the request to follow re-directs and always hit the network
|
||||||
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
|
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||||
|
|
||||||
|
networkRequest.setUrl(_fbxURL);
|
||||||
|
|
||||||
|
qCDebug(model_baking) << "Downloading" << _fbxURL;
|
||||||
|
|
||||||
|
auto networkReply = networkAccessManager.get(networkRequest);
|
||||||
|
connect(networkReply, &QNetworkReply::finished, this, &FBXBaker::handleFBXNetworkReply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FBXBaker::setupOutputFolder() {
|
||||||
|
// construct the output path using the name of the fbx and the base output path
|
||||||
|
_uniqueOutputPath = _baseOutputPath + "/" + _fbxName + "/";
|
||||||
|
|
||||||
|
// make sure there isn't already an output directory using the same name
|
||||||
|
int iteration = 0;
|
||||||
|
|
||||||
|
while (QDir(_uniqueOutputPath).exists()) {
|
||||||
|
_uniqueOutputPath = _baseOutputPath + "/" + _fbxName + "-" + QString::number(++iteration) + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(model_baking) << "Creating FBX output folder" << _uniqueOutputPath;
|
||||||
|
|
||||||
|
// attempt to make the output folder
|
||||||
|
if (!QDir().mkdir(_uniqueOutputPath)) {
|
||||||
|
qCWarning(model_baking) << "Failed to created FBX output folder" << _uniqueOutputPath;
|
||||||
|
|
||||||
|
emit finished();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBXBaker::handleFBXNetworkReply() {
|
||||||
|
QNetworkReply* requestReply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
if (requestReply->error() == QNetworkReply::NoError) {
|
||||||
|
qCDebug(model_baking) << "Downloaded" << _fbxURL;
|
||||||
|
|
||||||
|
// grab the contents of the reply and make a copy in the output folder
|
||||||
|
QFile copyOfOriginal(_uniqueOutputPath + _fbxURL.fileName());
|
||||||
|
|
||||||
|
qDebug(model_baking) << "Writing copy of original FBX to" << copyOfOriginal.fileName();
|
||||||
|
|
||||||
|
if (!copyOfOriginal.open(QIODevice::WriteOnly) || (copyOfOriginal.write(requestReply->readAll()) == -1)) {
|
||||||
|
|
||||||
|
// add an error to the error list for this FBX stating that a duplicate of the original could not be made
|
||||||
|
emit finished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close that file now that we are done writing to it
|
||||||
|
copyOfOriginal.close();
|
||||||
|
|
||||||
|
// kick off the bake process now that everything is ready to go
|
||||||
|
bake();
|
||||||
|
} else {
|
||||||
|
qDebug() << "ERROR DOWNLOADING FBX" << requestReply->errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,25 +130,31 @@ void FBXBaker::bake() {
|
||||||
// (3) export the FBX with re-written texture references
|
// (3) export the FBX with re-written texture references
|
||||||
// (4) enumerate the collected texture paths and bake the textures
|
// (4) enumerate the collected texture paths and bake the textures
|
||||||
|
|
||||||
|
qCDebug(model_baking) << "Baking" << _fbxURL;
|
||||||
|
|
||||||
// a failure at any step along the way stops the chain
|
// a failure at any step along the way stops the chain
|
||||||
importScene() && rewriteAndCollectSceneTextures() && exportScene() && bakeTextures();
|
importScene() && rewriteAndCollectSceneTextures() && exportScene() && bakeTextures();
|
||||||
|
|
||||||
// emit a signal saying that we are done, with whatever errors were produced
|
// emit a signal saying that we are done, with whatever errors were produced
|
||||||
emit finished(_errorList);
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FBXBaker::importScene() {
|
bool FBXBaker::importScene() {
|
||||||
// create an FBX SDK importer
|
// create an FBX SDK importer
|
||||||
FbxImporter* importer = FbxImporter::Create(_sdkManager, "");
|
FbxImporter* importer = FbxImporter::Create(_sdkManager, "");
|
||||||
|
|
||||||
// import the FBX file at the given path
|
// import the copy of the original FBX file
|
||||||
bool importStatus = importer->Initialize(_fbxPath.toLocalFile().toLocal8Bit().data());
|
QString originalCopyPath = _uniqueOutputPath + _fbxURL.fileName();
|
||||||
|
bool importStatus = importer->Initialize(originalCopyPath.toLocal8Bit().data());
|
||||||
|
|
||||||
if (!importStatus) {
|
if (!importStatus) {
|
||||||
// failed to initialize importer, print an error and return
|
// failed to initialize importer, print an error and return
|
||||||
qCDebug(model_baking) << "Failed to import FBX file at" << _fbxPath << "- error:" << importer->GetStatus().GetErrorString();
|
qCCritical(model_baking) << "Failed to import FBX file at" << _fbxURL
|
||||||
|
<< "- error:" << importer->GetStatus().GetErrorString();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
qCDebug(model_baking) << "Imported" << _fbxURL << "to FbxScene";
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup a new scene to hold the imported file
|
// setup a new scene to hold the imported file
|
||||||
|
@ -82,8 +172,6 @@ bool FBXBaker::importScene() {
|
||||||
static const QString BAKED_TEXTURE_DIRECTORY = "textures";
|
static const QString BAKED_TEXTURE_DIRECTORY = "textures";
|
||||||
static const QString BAKED_TEXTURE_EXT = ".ktx";
|
static const QString BAKED_TEXTURE_EXT = ".ktx";
|
||||||
|
|
||||||
static const QString EXPORT_PATH { "/Users/birarda/code/hifi/lod/test-oven/export/DiscGolfBasket.ktx.fbx" };
|
|
||||||
|
|
||||||
bool FBXBaker::rewriteAndCollectSceneTextures() {
|
bool FBXBaker::rewriteAndCollectSceneTextures() {
|
||||||
// get a count of the textures used in the scene
|
// get a count of the textures used in the scene
|
||||||
int numTextures = _scene->GetTextureCount();
|
int numTextures = _scene->GetTextureCount();
|
||||||
|
@ -102,7 +190,7 @@ bool FBXBaker::rewriteAndCollectSceneTextures() {
|
||||||
|
|
||||||
// construct the new baked texture file name and file path
|
// construct the new baked texture file name and file path
|
||||||
QString bakedTextureFileName { textureFileInfo.baseName() + BAKED_TEXTURE_EXT };
|
QString bakedTextureFileName { textureFileInfo.baseName() + BAKED_TEXTURE_EXT };
|
||||||
QString bakedTextureFilePath { QFileInfo(EXPORT_PATH).absolutePath() + "/textures/" + bakedTextureFileName };
|
QString bakedTextureFilePath { _uniqueOutputPath + "ktx/" + bakedTextureFileName };
|
||||||
|
|
||||||
qCDebug(model_baking).noquote() << "Re-mapping" << fileTexture->GetFileName() << "to" << bakedTextureFilePath;
|
qCDebug(model_baking).noquote() << "Re-mapping" << fileTexture->GetFileName() << "to" << bakedTextureFilePath;
|
||||||
|
|
||||||
|
@ -127,12 +215,13 @@ bool FBXBaker::exportScene() {
|
||||||
// setup the exporter
|
// setup the exporter
|
||||||
FbxExporter* exporter = FbxExporter::Create(_sdkManager, "");
|
FbxExporter* exporter = FbxExporter::Create(_sdkManager, "");
|
||||||
|
|
||||||
bool exportStatus = exporter->Initialize(EXPORT_PATH.toLocal8Bit().data());
|
auto rewrittenFBXPath = _uniqueOutputPath + _fbxName + ".ktx.fbx";
|
||||||
|
bool exportStatus = exporter->Initialize(rewrittenFBXPath.toLocal8Bit().data());
|
||||||
|
|
||||||
if (!exportStatus) {
|
if (!exportStatus) {
|
||||||
// failed to initialize exporter, print an error and return
|
// failed to initialize exporter, print an error and return
|
||||||
qCDebug(model_baking) << "Failed to export FBX file at" << _fbxPath
|
qCCritical(model_baking) << "Failed to export FBX file at" << _fbxURL
|
||||||
<< "to" << EXPORT_PATH << "- error:" << exporter->GetStatus().GetErrorString();
|
<< "to" << rewrittenFBXPath << "- error:" << exporter->GetStatus().GetErrorString();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +229,8 @@ bool FBXBaker::exportScene() {
|
||||||
// export the scene
|
// export the scene
|
||||||
exporter->Export(_scene);
|
exporter->Export(_scene);
|
||||||
|
|
||||||
|
qCDebug(model_baking) << "Exported" << _fbxURL << "with re-written paths to" << rewrittenFBXPath;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,10 @@
|
||||||
#ifndef hifi_FBXBaker_h
|
#ifndef hifi_FBXBaker_h
|
||||||
#define hifi_FBXBaker_h
|
#define hifi_FBXBaker_h
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QtCore/QDir>
|
||||||
#include <QUrl>
|
#include <QtCore/QLoggingCategory>
|
||||||
|
#include <QtCore/QUrl>
|
||||||
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(model_baking)
|
Q_DECLARE_LOGGING_CATEGORY(model_baking)
|
||||||
|
|
||||||
|
@ -27,23 +29,33 @@ namespace fbxsdk {
|
||||||
class FBXBaker : public QObject {
|
class FBXBaker : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FBXBaker(QUrl fbxPath);
|
FBXBaker(QUrl fbxURL, QString baseOutputPath);
|
||||||
~FBXBaker();
|
~FBXBaker();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(QStringList errorList);
|
void finished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleFBXNetworkReply();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void bake();
|
void bake();
|
||||||
|
|
||||||
|
bool setupOutputFolder();
|
||||||
bool importScene();
|
bool importScene();
|
||||||
bool rewriteAndCollectSceneTextures();
|
bool rewriteAndCollectSceneTextures();
|
||||||
bool exportScene();
|
bool exportScene();
|
||||||
bool bakeTextures();
|
bool bakeTextures();
|
||||||
bool bakeTexture();
|
bool bakeTexture();
|
||||||
|
|
||||||
QUrl _fbxPath;
|
QUrl _fbxURL;
|
||||||
|
QString _fbxName;
|
||||||
|
|
||||||
|
QString _baseOutputPath;
|
||||||
|
QString _uniqueOutputPath;
|
||||||
|
|
||||||
fbxsdk::FbxManager* _sdkManager;
|
fbxsdk::FbxManager* _sdkManager;
|
||||||
fbxsdk::FbxScene* _scene { nullptr };
|
fbxsdk::FbxScene* _scene { nullptr };
|
||||||
|
|
||||||
|
|
23
tools/oven/src/Oven.cpp
Normal file
23
tools/oven/src/Oven.cpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Oven.cpp
|
||||||
|
// tools/oven/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 4/5/17.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
|
#include "Oven.h"
|
||||||
|
|
||||||
|
static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export";
|
||||||
|
|
||||||
|
Oven::Oven(int argc, char* argv[]) :
|
||||||
|
QCoreApplication(argc, argv),
|
||||||
|
_testBake(QUrl("file:///Users/birarda/code/hifi/lod/test-oven/DiscGolfBasket.fbx"), OUTPUT_FOLDER)
|
||||||
|
{
|
||||||
|
_testBake.start();
|
||||||
|
}
|
30
tools/oven/src/Oven.h
Normal file
30
tools/oven/src/Oven.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Oven.h
|
||||||
|
// tools/oven/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 4/5/17.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_Oven_h
|
||||||
|
#define hifi_Oven_h
|
||||||
|
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
|
#include <FBXBaker.h>
|
||||||
|
|
||||||
|
class Oven : public QCoreApplication {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Oven(int argc, char* argv[]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FBXBaker _testBake;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_Oven_h
|
|
@ -8,13 +8,9 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
#include <FBXBaker.h>
|
#include "Oven.h"
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, char** argv) {
|
int main (int argc, char** argv) {
|
||||||
|
Oven app(argc, argv);
|
||||||
FBXBaker baker(QUrl("file:///Users/birarda/code/hifi/lod/test-oven/DiscGolfBasket.fbx"));
|
return app.exec();
|
||||||
baker.start();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue