mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 23:09:52 +02:00
call image library for texture baking
This commit is contained in:
parent
429e65888b
commit
49e7ae6dbc
13 changed files with 158 additions and 124 deletions
|
@ -22,6 +22,8 @@
|
||||||
#include "Forward.h"
|
#include "Forward.h"
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
|
|
||||||
|
const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192;
|
||||||
|
|
||||||
namespace ktx {
|
namespace ktx {
|
||||||
class KTX;
|
class KTX;
|
||||||
using KTXUniquePointer = std::unique_ptr<KTX>;
|
using KTXUniquePointer = std::unique_ptr<KTX>;
|
||||||
|
|
|
@ -2,7 +2,7 @@ set(TARGET_NAME model-baking)
|
||||||
|
|
||||||
setup_hifi_library(Concurrent)
|
setup_hifi_library(Concurrent)
|
||||||
|
|
||||||
link_hifi_libraries(networking)
|
link_hifi_libraries(networking image gpu shared ktx)
|
||||||
|
|
||||||
find_package(FBXSDK REQUIRED)
|
find_package(FBXSDK REQUIRED)
|
||||||
target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES})
|
||||||
|
|
|
@ -19,7 +19,7 @@ void Baker::handleError(const QString& error) {
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Baker::appendErrors(const QStringList& errors) {
|
void Baker::handleErrors(const QStringList& errors) {
|
||||||
// we're appending errors, presumably from a baking operation we called
|
// we're appending errors, presumably from a baking operation we called
|
||||||
// add those to our list and emit that we are finished
|
// add those to our list and emit that we are finished
|
||||||
_errorList.append(errors);
|
_errorList.append(errors);
|
||||||
|
|
|
@ -33,8 +33,7 @@ protected:
|
||||||
void handleError(const QString& error);
|
void handleError(const QString& error);
|
||||||
void handleWarning(const QString& warning);
|
void handleWarning(const QString& warning);
|
||||||
|
|
||||||
void appendErrors(const QStringList& errors);
|
void handleErrors(const QStringList& errors);
|
||||||
void appendWarnings(const QStringList& warnings) { _warningList << warnings; }
|
|
||||||
|
|
||||||
QStringList _errorList;
|
QStringList _errorList;
|
||||||
QStringList _warningList;
|
QStringList _warningList;
|
||||||
|
|
|
@ -207,8 +207,6 @@ void FBXBaker::importScene() {
|
||||||
importer->Destroy();
|
importer->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString BAKED_TEXTURE_EXT = ".ktx";
|
|
||||||
|
|
||||||
QString texturePathRelativeToFBX(QUrl fbxURL, QUrl textureURL) {
|
QString texturePathRelativeToFBX(QUrl fbxURL, QUrl textureURL) {
|
||||||
auto fbxPath = fbxURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment);
|
auto fbxPath = fbxURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||||
auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment);
|
auto texturePath = textureURL.toString(QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||||
|
@ -256,49 +254,25 @@ QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, FbxFileTexture* f
|
||||||
QString relativeFileName = fileTexture->GetRelativeFileName();
|
QString relativeFileName = fileTexture->GetRelativeFileName();
|
||||||
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
// this is a relative file path which will require different handling
|
||||||
// it turns out that paths that start with a drive letter and a colon appear to QFileInfo
|
// depending on the location of the original FBX
|
||||||
// as a relative path on UNIX systems - we perform a special check here to handle that case
|
if (_fbxURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) {
|
||||||
bool isAbsolute = relativeFileName[1] == ':' || apparentRelativePath.isAbsolute();
|
// the absolute path we ran into for the texture in the FBX exists on this machine
|
||||||
#else
|
// so use that file
|
||||||
bool isAbsolute = apparentRelativePath.isAbsolute();
|
urlToTexture = QUrl::fromLocalFile(apparentRelativePath.absoluteFilePath());
|
||||||
#endif
|
|
||||||
|
|
||||||
if (isAbsolute) {
|
|
||||||
// this is a relative file path which will require different handling
|
|
||||||
// depending on the location of the original FBX
|
|
||||||
if (_fbxURL.isLocalFile()) {
|
|
||||||
// since the loaded FBX is loaded, first check if we actually have the texture locally
|
|
||||||
// at the absolute path
|
|
||||||
if (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());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// the original FBX was remote and downloaded
|
|
||||||
|
|
||||||
// since this "relative" texture path is actually absolute, we have to assume it is beside the FBX
|
|
||||||
// which matches the behaviour of Interface
|
|
||||||
|
|
||||||
// append that path to our list of unbaked textures
|
|
||||||
urlToTexture = _fbxURL.resolved(apparentRelativePath.fileName());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// simply construct a URL with the relative path to the asset, locally or remotely
|
// we didn't find the texture on this machine at the absolute path
|
||||||
// and append that to the list of unbaked textures
|
// so assume that it is right beside the FBX to match the behaviour of interface
|
||||||
urlToTexture = _fbxURL.resolved(apparentRelativePath.filePath());
|
urlToTexture = _fbxURL.resolved(apparentRelativePath.fileName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return urlToTexture;
|
return urlToTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureType textureTypeForMaterialProperty(FbxProperty& property, FbxSurfaceMaterial* material) {
|
gpu::TextureType textureTypeForMaterialProperty(FbxProperty& property, FbxSurfaceMaterial* material) {
|
||||||
|
using namespace gpu;
|
||||||
|
|
||||||
// this is a property we know has a texture, we need to match it to a High Fidelity known texture type
|
// this is a property we know has a texture, we need to match it to a High Fidelity known texture type
|
||||||
// since that information is passed to the baking process
|
// since that information is passed to the baking process
|
||||||
|
|
||||||
|
@ -366,7 +340,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
||||||
// figure out the type of texture from the material property
|
// figure out the type of texture from the material property
|
||||||
auto textureType = textureTypeForMaterialProperty(property, material);
|
auto textureType = textureTypeForMaterialProperty(property, material);
|
||||||
|
|
||||||
if (textureType != UNUSED_TEXTURE) {
|
if (textureType != gpu::UNUSED_TEXTURE) {
|
||||||
int numTextures = property.GetSrcObjectCount<FbxFileTexture>();
|
int numTextures = property.GetSrcObjectCount<FbxFileTexture>();
|
||||||
|
|
||||||
for (int j = 0; j < numTextures; j++) {
|
for (int j = 0; j < numTextures; j++) {
|
||||||
|
@ -401,7 +375,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
||||||
_unbakedTextures.insert(urlToTexture, bakedTextureFileName);
|
_unbakedTextures.insert(urlToTexture, bakedTextureFileName);
|
||||||
|
|
||||||
// bake this texture asynchronously
|
// bake this texture asynchronously
|
||||||
bakeTexture(urlToTexture);
|
bakeTexture(urlToTexture, textureType, bakedTextureFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,63 +388,91 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXBaker::bakeTexture(const QUrl& textureURL) {
|
void FBXBaker::bakeTexture(const QUrl& textureURL, gpu::TextureType textureType, const QString& destinationFilePath) {
|
||||||
// start a bake for this texture and add it to our list to keep track of
|
// start a bake for this texture and add it to our list to keep track of
|
||||||
QSharedPointer<TextureBaker> bakingTexture { new TextureBaker(textureURL), &TextureBaker::deleteLater };
|
QSharedPointer<TextureBaker> bakingTexture {
|
||||||
|
new TextureBaker(textureURL, textureType, destinationFilePath),
|
||||||
|
&TextureBaker::deleteLater
|
||||||
|
};
|
||||||
|
|
||||||
|
// make sure we hear when the baking texture is done
|
||||||
connect(bakingTexture.data(), &Baker::finished, this, &FBXBaker::handleBakedTexture);
|
connect(bakingTexture.data(), &Baker::finished, this, &FBXBaker::handleBakedTexture);
|
||||||
|
|
||||||
QtConcurrent::run(bakingTexture.data(), &TextureBaker::bake);
|
// keep a shared pointer to the baking texture
|
||||||
|
|
||||||
_bakingTextures.insert(bakingTexture);
|
_bakingTextures.insert(bakingTexture);
|
||||||
|
|
||||||
|
// start baking the texture on our thread pool
|
||||||
|
QtConcurrent::run(bakingTexture.data(), &TextureBaker::bake);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXBaker::handleBakedTexture() {
|
void FBXBaker::handleBakedTexture() {
|
||||||
TextureBaker* bakedTexture = qobject_cast<TextureBaker*>(sender());
|
TextureBaker* bakedTexture = qobject_cast<TextureBaker*>(sender());
|
||||||
|
|
||||||
// make sure we haven't already run into errors, and that this is a valid texture
|
// make sure we haven't already run into errors, and that this is a valid texture
|
||||||
if (!hasErrors() && bakedTexture) {
|
if (bakedTexture) {
|
||||||
if (!bakedTexture->hasErrors()) {
|
if (!hasErrors()) {
|
||||||
// use the path to the texture being baked to determine if this was an embedded or a linked texture
|
if (!bakedTexture->hasErrors()) {
|
||||||
|
if (_copyOriginals) {
|
||||||
|
// we've been asked to make copies of the originals, so we need to make copies of this if it is a linked texture
|
||||||
|
|
||||||
// it is embeddded if the texure being baked was inside the original output folder
|
// use the path to the texture being baked to determine if this was an embedded or a linked texture
|
||||||
// since that is where the FBX SDK places the .fbm folder it generates when importing the FBX
|
|
||||||
|
|
||||||
auto originalOutputFolder = QUrl::fromLocalFile(_uniqueOutputPath + ORIGINAL_OUTPUT_SUBFOLDER);
|
// it is embeddded if the texure being baked was inside the original output folder
|
||||||
|
// since that is where the FBX SDK places the .fbm folder it generates when importing the FBX
|
||||||
|
|
||||||
if (!originalOutputFolder.isParentOf(bakedTexture->getTextureURL())) {
|
auto originalOutputFolder = QUrl::fromLocalFile(_uniqueOutputPath + ORIGINAL_OUTPUT_SUBFOLDER);
|
||||||
// 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();
|
if (!originalOutputFolder.isParentOf(bakedTexture->getTextureURL())) {
|
||||||
|
// for linked textures we want to save a copy of original texture beside the original FBX
|
||||||
|
|
||||||
// check if we have a relative path to use for the texture
|
qCDebug(model_baking) << "Saving original texture for" << bakedTexture->getTextureURL();
|
||||||
auto relativeTexturePath = texturePathRelativeToFBX(_fbxURL, bakedTexture->getTextureURL());
|
|
||||||
|
|
||||||
QFile originalTextureFile {
|
// check if we have a relative path to use for the texture
|
||||||
_uniqueOutputPath + ORIGINAL_OUTPUT_SUBFOLDER + relativeTexturePath + bakedTexture->getTextureURL().fileName()
|
auto relativeTexturePath = texturePathRelativeToFBX(_fbxURL, bakedTexture->getTextureURL());
|
||||||
};
|
|
||||||
|
|
||||||
if (relativeTexturePath.length() > 0) {
|
QFile originalTextureFile {
|
||||||
// make the folders needed by the relative path
|
_uniqueOutputPath + ORIGINAL_OUTPUT_SUBFOLDER + 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) {
|
|
||||||
qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName()
|
// now that this texture has been baked and handled, we can remove that TextureBaker from our list
|
||||||
<< "for" << _fbxURL;
|
_unbakedTextures.remove(bakedTexture->getTextureURL());
|
||||||
} else {
|
|
||||||
handleError("Could not save original external texture " + originalTextureFile.fileName()
|
checkIfTexturesFinished();
|
||||||
+ " for " + _fbxURL.toString());
|
} else {
|
||||||
return;
|
// 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
|
||||||
|
_unbakedTextures.remove(bakedTexture->getTextureURL());
|
||||||
|
|
||||||
|
checkIfTexturesFinished();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// now that this texture has been baked and handled, we can remove that TextureBaker from our list
|
// 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
|
||||||
_unbakedTextures.remove(bakedTexture->getTextureURL());
|
_unbakedTextures.remove(bakedTexture->getTextureURL());
|
||||||
|
|
||||||
checkIfTexturesFinished();
|
checkIfTexturesFinished();
|
||||||
} else {
|
|
||||||
// there was an error baking this texture - add it to our list of errors and stop processing this FBX
|
|
||||||
appendErrors(bakedTexture->getErrors());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,23 +518,27 @@ void FBXBaker::possiblyCleanupOriginals() {
|
||||||
void FBXBaker::checkIfTexturesFinished() {
|
void FBXBaker::checkIfTexturesFinished() {
|
||||||
// check if we're done everything we need to do for this FBX
|
// check if we're done everything we need to do for this FBX
|
||||||
// and emit our finished signal if we're done
|
// and emit our finished signal if we're done
|
||||||
|
|
||||||
if (_unbakedTextures.isEmpty()) {
|
if (_unbakedTextures.isEmpty()) {
|
||||||
// remove the embedded media folder that the FBX SDK produces when reading the original
|
// remove the embedded media folder that the FBX SDK produces when reading the original
|
||||||
removeEmbeddedMediaFolder();
|
removeEmbeddedMediaFolder();
|
||||||
|
|
||||||
if (hasErrors()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup the originals if we weren't asked to keep them around
|
// cleanup the originals if we weren't asked to keep them around
|
||||||
possiblyCleanupOriginals();
|
possiblyCleanupOriginals();
|
||||||
|
|
||||||
if (hasErrors()) {
|
if (hasErrors()) {
|
||||||
return;
|
// if we're checking for completion but we have errors
|
||||||
}
|
// that means one or more of our texture baking operations failed
|
||||||
|
|
||||||
qCDebug(model_baking) << "Finished baking" << _fbxURL;
|
if (_pendingErrorEmission) {
|
||||||
|
emit finished();
|
||||||
emit finished();
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
qCDebug(model_baking) << "Finished baking" << _fbxURL;
|
||||||
|
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "Baker.h"
|
#include "Baker.h"
|
||||||
#include "TextureBaker.h"
|
#include "TextureBaker.h"
|
||||||
|
|
||||||
|
#include <gpu/Texture.h>
|
||||||
|
|
||||||
namespace fbxsdk {
|
namespace fbxsdk {
|
||||||
class FbxManager;
|
class FbxManager;
|
||||||
class FbxProperty;
|
class FbxProperty;
|
||||||
|
@ -27,25 +29,6 @@ namespace fbxsdk {
|
||||||
class FbxFileTexture;
|
class FbxFileTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextureType {
|
|
||||||
DEFAULT_TEXTURE,
|
|
||||||
STRICT_TEXTURE,
|
|
||||||
ALBEDO_TEXTURE,
|
|
||||||
NORMAL_TEXTURE,
|
|
||||||
BUMP_TEXTURE,
|
|
||||||
SPECULAR_TEXTURE,
|
|
||||||
METALLIC_TEXTURE = SPECULAR_TEXTURE, // for now spec and metallic texture are the same, converted to grey
|
|
||||||
ROUGHNESS_TEXTURE,
|
|
||||||
GLOSS_TEXTURE,
|
|
||||||
EMISSIVE_TEXTURE,
|
|
||||||
CUBE_TEXTURE,
|
|
||||||
OCCLUSION_TEXTURE,
|
|
||||||
SCATTERING_TEXTURE = OCCLUSION_TEXTURE,
|
|
||||||
LIGHTMAP_TEXTURE,
|
|
||||||
CUSTOM_TEXTURE,
|
|
||||||
UNUSED_TEXTURE = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
static const QString BAKED_FBX_EXTENSION = ".baked.fbx";
|
static const QString BAKED_FBX_EXTENSION = ".baked.fbx";
|
||||||
using FBXSDKManagerUniquePointer = std::unique_ptr<fbxsdk::FbxManager, std::function<void (fbxsdk::FbxManager *)>>;
|
using FBXSDKManagerUniquePointer = std::unique_ptr<fbxsdk::FbxManager, std::function<void (fbxsdk::FbxManager *)>>;
|
||||||
|
|
||||||
|
@ -89,7 +72,7 @@ private:
|
||||||
QString createBakedTextureFileName(const QFileInfo& textureFileInfo);
|
QString createBakedTextureFileName(const QFileInfo& textureFileInfo);
|
||||||
QUrl getTextureURL(const QFileInfo& textureFileInfo, fbxsdk::FbxFileTexture* fileTexture);
|
QUrl getTextureURL(const QFileInfo& textureFileInfo, fbxsdk::FbxFileTexture* fileTexture);
|
||||||
|
|
||||||
void bakeTexture(const QUrl& textureURL);
|
void bakeTexture(const QUrl& textureURL, gpu::TextureType textureType, const QString& destinationFilePath);
|
||||||
|
|
||||||
QString pathToCopyOfOriginal() const;
|
QString pathToCopyOfOriginal() const;
|
||||||
|
|
||||||
|
@ -103,18 +86,15 @@ private:
|
||||||
static FBXSDKManagerUniquePointer _sdkManager;
|
static FBXSDKManagerUniquePointer _sdkManager;
|
||||||
fbxsdk::FbxScene* _scene { nullptr };
|
fbxsdk::FbxScene* _scene { nullptr };
|
||||||
|
|
||||||
QStringList _errorList;
|
|
||||||
|
|
||||||
QHash<QUrl, QString> _unbakedTextures;
|
QHash<QUrl, QString> _unbakedTextures;
|
||||||
QHash<QString, int> _textureNameMatchCount;
|
QHash<QString, int> _textureNameMatchCount;
|
||||||
QHash<uint64_t, TextureType> _textureTypes;
|
|
||||||
|
|
||||||
QSet<QSharedPointer<TextureBaker>> _bakingTextures;
|
QSet<QSharedPointer<TextureBaker>> _bakingTextures;
|
||||||
QFutureSynchronizer<void> _textureBakeSynchronizer;
|
QFutureSynchronizer<void> _textureBakeSynchronizer;
|
||||||
|
|
||||||
bool _copyOriginals { true };
|
bool _copyOriginals { true };
|
||||||
|
|
||||||
bool _finishedNonTextureOperations { false };
|
bool _pendingErrorEmission { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_FBXBaker_h
|
#endif // hifi_FBXBaker_h
|
||||||
|
|
|
@ -9,20 +9,27 @@
|
||||||
// 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 <QtCore/QDir>
|
||||||
#include <QtCore/QEventLoop>
|
#include <QtCore/QEventLoop>
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
|
#include <image/Image.h>
|
||||||
|
#include <ktx/KTX.h>
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
|
|
||||||
#include "ModelBakingLoggingCategory.h"
|
#include "ModelBakingLoggingCategory.h"
|
||||||
|
|
||||||
#include "TextureBaker.h"
|
#include "TextureBaker.h"
|
||||||
|
|
||||||
TextureBaker::TextureBaker(const QUrl& textureURL) :
|
const QString BAKED_TEXTURE_EXT = ".ktx";
|
||||||
_textureURL(textureURL)
|
|
||||||
|
TextureBaker::TextureBaker(const QUrl& textureURL, gpu::TextureType textureType, const QString& destinationFilePath) :
|
||||||
|
_textureURL(textureURL),
|
||||||
|
_textureType(textureType),
|
||||||
|
_destinationFilePath(destinationFilePath)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureBaker::bake() {
|
void TextureBaker::bake() {
|
||||||
|
@ -35,6 +42,14 @@ void TextureBaker::bake() {
|
||||||
|
|
||||||
qCDebug(model_baking) << "Baking texture at" << _textureURL;
|
qCDebug(model_baking) << "Baking texture at" << _textureURL;
|
||||||
|
|
||||||
|
processTexture();
|
||||||
|
|
||||||
|
if (hasErrors()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(model_baking) << "Baked texture at" << _textureURL;
|
||||||
|
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +98,33 @@ void TextureBaker::handleTextureNetworkReply(QNetworkReply* requestReply) {
|
||||||
_originalTexture = requestReply->readAll();
|
_originalTexture = requestReply->readAll();
|
||||||
} else {
|
} else {
|
||||||
// add an error to our list stating that this texture could not be downloaded
|
// add an error to our list stating that this texture could not be downloaded
|
||||||
qCDebug(model_baking) << "Error downloading texture" << requestReply->errorString();
|
handleError("Error downloading " + _textureURL.toString() + " - " + requestReply->errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureBaker::processTexture() {
|
||||||
|
auto processedTexture = image::processImage(_originalTexture, _textureURL.toString().toStdString(),
|
||||||
|
ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType);
|
||||||
|
|
||||||
|
if (!processedTexture) {
|
||||||
|
handleError("Could not process texture " + _textureURL.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto memKTX = gpu::Texture::serialize(*processedTexture);
|
||||||
|
|
||||||
|
if (!memKTX) {
|
||||||
|
handleError("Could not serialize " + _textureURL.toString() + " to KTX");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* data = reinterpret_cast<const char*>(memKTX->_storage->data());
|
||||||
|
const size_t length = memKTX->_storage->size();
|
||||||
|
|
||||||
|
// attempt to write the baked texture to the destination file path
|
||||||
|
QFile bakedTextureFile { _destinationFilePath };
|
||||||
|
|
||||||
|
if (!bakedTextureFile.open(QIODevice::WriteOnly) || bakedTextureFile.write(data, length) == -1) {
|
||||||
|
handleError("Could not write baked texture for " + _textureURL.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,19 @@
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
#include <QtCore/QRunnable>
|
||||||
|
|
||||||
|
#include <gpu/Texture.h>
|
||||||
|
|
||||||
#include "Baker.h"
|
#include "Baker.h"
|
||||||
|
|
||||||
|
extern const QString BAKED_TEXTURE_EXT;
|
||||||
|
|
||||||
class TextureBaker : public Baker {
|
class TextureBaker : public Baker {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextureBaker(const QUrl& textureURL);
|
TextureBaker(const QUrl& textureURL, gpu::TextureType textureType, const QString& destinationFilePath);
|
||||||
|
|
||||||
void bake();
|
void bake();
|
||||||
|
|
||||||
|
@ -33,8 +38,13 @@ private:
|
||||||
void loadTexture();
|
void loadTexture();
|
||||||
void handleTextureNetworkReply(QNetworkReply* requestReply);
|
void handleTextureNetworkReply(QNetworkReply* requestReply);
|
||||||
|
|
||||||
|
void processTexture();
|
||||||
|
|
||||||
QUrl _textureURL;
|
QUrl _textureURL;
|
||||||
QByteArray _originalTexture;
|
QByteArray _originalTexture;
|
||||||
|
gpu::TextureType _textureType;
|
||||||
|
|
||||||
|
QString _destinationFilePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_TextureBaker_h
|
#endif // hifi_TextureBaker_h
|
||||||
|
|
|
@ -27,8 +27,6 @@
|
||||||
|
|
||||||
#include "KTXCache.h"
|
#include "KTXCache.h"
|
||||||
|
|
||||||
const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192;
|
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
class Batch;
|
class Batch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ Q_LOGGING_CATEGORY(trace_simulation_physics_detail, "trace.simulation.physics.de
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool tracingEnabled() {
|
static bool tracingEnabled() {
|
||||||
return DependencyManager::get<tracing::Tracer>()->isEnabled();
|
return DependencyManager::isSet<tracing::Tracer>() && DependencyManager::get<tracing::Tracer>()->isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
Duration::Duration(const QLoggingCategory& category, const QString& name, uint32_t argbColor, uint64_t payload, const QVariantMap& baseArgs) : _name(name), _category(category) {
|
Duration::Duration(const QLoggingCategory& category, const QString& name, uint32_t argbColor, uint64_t payload, const QVariantMap& baseArgs) : _name(name), _category(category) {
|
||||||
|
|
|
@ -2,4 +2,4 @@ set(TARGET_NAME oven)
|
||||||
|
|
||||||
setup_hifi_project(Widgets Gui Concurrent)
|
setup_hifi_project(Widgets Gui Concurrent)
|
||||||
|
|
||||||
link_hifi_libraries(model-baking shared)
|
link_hifi_libraries(model-baking shared image gpu ktx)
|
||||||
|
|
|
@ -236,7 +236,7 @@ void DomainBaker::handleFinishedBaker() {
|
||||||
QUrl oldModelURL { entity[ENTITY_MODEL_URL_KEY].toString() };
|
QUrl oldModelURL { entity[ENTITY_MODEL_URL_KEY].toString() };
|
||||||
|
|
||||||
// setup a new URL using the prefix we were passed
|
// setup a new URL using the prefix we were passed
|
||||||
QUrl newModelURL = _destinationPath.resolved(baker->getBakedFBXRelativePath().mid(1));
|
QUrl newModelURL = _destinationPath.resolved(baker->getBakedFBXRelativePath());
|
||||||
|
|
||||||
// copy the fragment and query from the old model URL
|
// copy the fragment and query from the old model URL
|
||||||
newModelURL.setQuery(oldModelURL.query());
|
newModelURL.setQuery(oldModelURL.query());
|
||||||
|
@ -251,7 +251,7 @@ void DomainBaker::handleFinishedBaker() {
|
||||||
} else {
|
} else {
|
||||||
// this model failed to bake - this doesn't fail the entire bake but we need to add
|
// this model failed to bake - this doesn't fail the entire bake but we need to add
|
||||||
// the errors from the model to our errors
|
// the errors from the model to our errors
|
||||||
appendWarnings(baker->getErrors());
|
_warningList << baker->getErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the baked URL from the multi hash of entities needing a re-write
|
// remove the baked URL from the multi hash of entities needing a re-write
|
||||||
|
|
|
@ -160,9 +160,6 @@ void DomainBakeWidget::chooseFileButtonClicked() {
|
||||||
|
|
||||||
// save the directory containing this entities file so we can default to it next time we show the file dialog
|
// save the directory containing this entities file so we can default to it next time we show the file dialog
|
||||||
_browseStartDirectory.set(directoryOfEntitiesFile);
|
_browseStartDirectory.set(directoryOfEntitiesFile);
|
||||||
|
|
||||||
// if our output directory is not yet set, set it to the directory of this entities file
|
|
||||||
_outputDirLineEdit->setText(directoryOfEntitiesFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue