mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-10 04:18:28 +02:00
Update baker library with many style improvements
This commit is contained in:
parent
57b943ae98
commit
70c35f84b5
15 changed files with 84 additions and 113 deletions
|
@ -223,11 +223,13 @@ void FBXBaker::rewriteAndBakeSceneModels() {
|
||||||
auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false);
|
auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false);
|
||||||
|
|
||||||
// Callback to get MaterialID
|
// Callback to get MaterialID
|
||||||
getMaterialIDCallback materialIDcallback = [=](int partIndex) {return extractedMesh.partMaterialTextures[partIndex].first;};
|
GetMaterialIDCallback materialIDcallback = [&extractedMesh](int partIndex) {
|
||||||
|
return extractedMesh.partMaterialTextures[partIndex].first;
|
||||||
|
};
|
||||||
|
|
||||||
// Compress mesh information and store in dracoMeshNode
|
// Compress mesh information and store in dracoMeshNode
|
||||||
FBXNode dracoMeshNode;
|
FBXNode dracoMeshNode;
|
||||||
bool success = this->compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback);
|
bool success = compressMesh(extractedMesh.mesh, hasDeformers, dracoMeshNode, materialIDcallback);
|
||||||
|
|
||||||
// if bake fails - return, if there were errors and continue, if there were warnings.
|
// if bake fails - return, if there were errors and continue, if there were warnings.
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -314,23 +316,20 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
||||||
for (FBXNode& textureChild : object->children) {
|
for (FBXNode& textureChild : object->children) {
|
||||||
|
|
||||||
if (textureChild.name == "RelativeFilename") {
|
if (textureChild.name == "RelativeFilename") {
|
||||||
QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() };
|
QString fbxTextureFileName { textureChild.properties.at(0).toString() };
|
||||||
|
|
||||||
// Callback to get texture type
|
// Callback to get texture type
|
||||||
getTextureTypeCallback textureTypeCallback = [=]() {
|
// grab the ID for this texture so we can figure out the
|
||||||
// grab the ID for this texture so we can figure out the
|
// texture type from the loaded materials
|
||||||
// texture type from the loaded materials
|
auto textureID { object->properties[0].toString() };
|
||||||
auto textureID{ object->properties[0].toByteArray() };
|
auto textureType = textureTypes[textureID];
|
||||||
auto textureType = textureTypes[textureID];
|
|
||||||
return textureType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compress the texture information and return the new filename to be added into the FBX scene
|
// Compress the texture information and return the new filename to be added into the FBX scene
|
||||||
QByteArray* bakedTextureFile = this->compressTexture(fbxTextureFileName, textureTypeCallback);
|
auto bakedTextureFile = compressTexture(fbxTextureFileName, textureType);
|
||||||
|
|
||||||
// If no errors or warnings have occurred during texture compression add the filename to the FBX scene
|
// If no errors or warnings have occurred during texture compression add the filename to the FBX scene
|
||||||
if (bakedTextureFile) {
|
if (!bakedTextureFile.isNull()) {
|
||||||
textureChild.properties[0] = *bakedTextureFile;
|
textureChild.properties[0] = bakedTextureFile;
|
||||||
} else {
|
} else {
|
||||||
// if bake fails - return, if there were errors and continue, if there were warnings.
|
// if bake fails - return, if there were errors and continue, if there were warnings.
|
||||||
if (hasErrors()) {
|
if (hasErrors()) {
|
||||||
|
|
|
@ -35,9 +35,6 @@ class FBXBaker : public ModelBaker {
|
||||||
public:
|
public:
|
||||||
using ModelBaker::ModelBaker;
|
using ModelBaker::ModelBaker;
|
||||||
|
|
||||||
QUrl getFBXUrl() const { return _modelURL; }
|
|
||||||
QString getBakedFBXFilePath() const { return _bakedModelFilePath; }
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void bake() override;
|
virtual void bake() override;
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ void ModelBaker::abort() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback) {
|
bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback) {
|
||||||
if (mesh.wasCompressed) {
|
if (mesh.wasCompressed) {
|
||||||
handleError("Cannot re-bake a file that contains compressed mesh");
|
handleError("Cannot re-bake a file that contains compressed mesh");
|
||||||
return false;
|
return false;
|
||||||
|
@ -106,12 +106,12 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes
|
||||||
bool hasPerFaceMaterials = (materialIDCallback) ? (mesh.parts.size() > 1 || materialIDCallback(0) != 0 ) : true;
|
bool hasPerFaceMaterials = (materialIDCallback) ? (mesh.parts.size() > 1 || materialIDCallback(0) != 0 ) : true;
|
||||||
bool needsOriginalIndices{ hasDeformers };
|
bool needsOriginalIndices{ hasDeformers };
|
||||||
|
|
||||||
int normalsAttributeID{ -1 };
|
int normalsAttributeID { -1 };
|
||||||
int colorsAttributeID{ -1 };
|
int colorsAttributeID { -1 };
|
||||||
int texCoordsAttributeID{ -1 };
|
int texCoordsAttributeID { -1 };
|
||||||
int texCoords1AttributeID{ -1 };
|
int texCoords1AttributeID { -1 };
|
||||||
int faceMaterialAttributeID{ -1 };
|
int faceMaterialAttributeID { -1 };
|
||||||
int originalIndexAttributeID{ -1 };
|
int originalIndexAttributeID { -1 };
|
||||||
|
|
||||||
const int positionAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::POSITION,
|
const int positionAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::POSITION,
|
||||||
3, draco::DT_FLOAT32);
|
3, draco::DT_FLOAT32);
|
||||||
|
@ -244,14 +244,7 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers,FBXNode& dracoMes
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTextureTypeCallback textureTypeCallback) {
|
QString ModelBaker::compressTexture(QString modelTextureFileName, image::TextureUsage::Type textureType) {
|
||||||
static QByteArray textureChild;
|
|
||||||
QByteArray textureContent = "";
|
|
||||||
image::TextureUsage::Type textureType = image::TextureUsage::Type::DEFAULT_TEXTURE;
|
|
||||||
|
|
||||||
if (textureTypeCallback) {
|
|
||||||
textureType = textureTypeCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") };
|
QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") };
|
||||||
|
|
||||||
|
@ -259,18 +252,20 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
||||||
// re-baking a model that already references baked textures
|
// re-baking a model that already references baked textures
|
||||||
// this is an error - return from here
|
// this is an error - return from here
|
||||||
handleError("Cannot re-bake a file that already references compressed textures");
|
handleError("Cannot re-bake a file that already references compressed textures");
|
||||||
return nullptr;
|
return QString::null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextureBaker::getSupportedFormats().contains(modelTextureFileInfo.suffix())) {
|
if (!TextureBaker::getSupportedFormats().contains(modelTextureFileInfo.suffix())) {
|
||||||
// this is a texture format we don't bake, skip it
|
// this is a texture format we don't bake, skip it
|
||||||
handleWarning(modelTextureFileName + " is not a bakeable texture format");
|
handleWarning(modelTextureFileName + " is not a bakeable texture format");
|
||||||
return nullptr;
|
return QString::null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure this texture points to something and isn't one we've already re-mapped
|
// make sure this texture points to something and isn't one we've already re-mapped
|
||||||
|
QString textureChild { QString::null };
|
||||||
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
||||||
// check if this was an embedded texture that we already have in-memory content for
|
// check if this was an embedded texture that we already have in-memory content for
|
||||||
|
QByteArray textureContent;
|
||||||
|
|
||||||
// figure out the URL to this texture, embedded or external
|
// figure out the URL to this texture, embedded or external
|
||||||
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
||||||
|
@ -296,7 +291,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
||||||
_bakedOutputDir + "/" + bakedTextureFileName
|
_bakedOutputDir + "/" + bakedTextureFileName
|
||||||
};
|
};
|
||||||
|
|
||||||
textureChild = bakedTextureFileName.toLocal8Bit();
|
textureChild = bakedTextureFileName;
|
||||||
|
|
||||||
if (!_bakingTextures.contains(urlToTexture)) {
|
if (!_bakingTextures.contains(urlToTexture)) {
|
||||||
_outputFiles.push_back(bakedTextureFilePath);
|
_outputFiles.push_back(bakedTextureFilePath);
|
||||||
|
@ -306,11 +301,11 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &textureChild;
|
return textureChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType,
|
void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType,
|
||||||
const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) {
|
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
|
// start a bake for this texture and add it to our list to keep track of
|
||||||
QSharedPointer<TextureBaker> bakingTexture{
|
QSharedPointer<TextureBaker> bakingTexture{
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
#include <FBX.h>
|
#include <FBX.h>
|
||||||
|
|
||||||
using TextureBakerThreadGetter = std::function<QThread*()>;
|
using TextureBakerThreadGetter = std::function<QThread*()>;
|
||||||
using getMaterialIDCallback = std::function <int(int)>;
|
using GetMaterialIDCallback = std::function <int(int)>;
|
||||||
using getTextureTypeCallback = std::function<image::TextureUsage::Type()>;
|
|
||||||
|
|
||||||
class ModelBaker : public Baker {
|
class ModelBaker : public Baker {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -37,10 +36,13 @@ public:
|
||||||
ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "");
|
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "");
|
||||||
virtual ~ModelBaker();
|
virtual ~ModelBaker();
|
||||||
bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL);
|
bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback = nullptr);
|
||||||
QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL);
|
QString compressTexture(QString textureFileName, image::TextureUsage::Type = image::TextureUsage::Type::DEFAULT_TEXTURE);
|
||||||
virtual void setWasAborted(bool wasAborted) override;
|
virtual void setWasAborted(bool wasAborted) override;
|
||||||
|
|
||||||
|
QUrl getModelURL() const { return _modelURL; }
|
||||||
|
QString getBakedModelFilePath() const { return _bakedModelFilePath; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void abort() override;
|
virtual void abort() override;
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ void OBJBaker::bakeOBJ() {
|
||||||
|
|
||||||
bool combineParts = true; // set true so that OBJReader reads material info from material library
|
bool combineParts = true; // set true so that OBJReader reads material info from material library
|
||||||
OBJReader reader;
|
OBJReader reader;
|
||||||
FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL);
|
auto geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL);
|
||||||
|
|
||||||
// Write OBJ Data as FBX tree nodes
|
// Write OBJ Data as FBX tree nodes
|
||||||
FBXNode rootNode;
|
FBXNode rootNode;
|
||||||
|
@ -211,7 +211,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
// Compress the mesh information and store in dracoNode
|
// Compress the mesh information and store in dracoNode
|
||||||
bool hasDeformers = false; // No concept of deformers for an OBJ
|
bool hasDeformers = false; // No concept of deformers for an OBJ
|
||||||
FBXNode dracoNode;
|
FBXNode dracoNode;
|
||||||
this->compressMesh(geometry.meshes[0], hasDeformers, dracoNode);
|
compressMesh(geometry.meshes[0], hasDeformers, dracoNode);
|
||||||
geometryNode.children.append(dracoNode);
|
geometryNode.children.append(dracoNode);
|
||||||
|
|
||||||
// Generating Object node's child - Model node
|
// Generating Object node's child - Model node
|
||||||
|
@ -219,11 +219,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
modelNode.name = MODEL_NODE_NAME;
|
modelNode.name = MODEL_NODE_NAME;
|
||||||
{
|
{
|
||||||
_modelID = _nodeID++;
|
_modelID = _nodeID++;
|
||||||
modelNode.properties = {
|
modelNode.properties = { _nodeID, MODEL_NODE_NAME, MESH };
|
||||||
_nodeID,
|
|
||||||
MODEL_NODE_NAME,
|
|
||||||
MESH
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_objectNode.children = { geometryNode, modelNode };
|
_objectNode.children = { geometryNode, modelNode };
|
||||||
|
@ -253,7 +249,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
FBXMaterial currentMaterial = geometry.materials[material];
|
FBXMaterial currentMaterial = geometry.materials[material];
|
||||||
if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) {
|
if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) {
|
||||||
_textureID = _nodeID;
|
_textureID = _nodeID;
|
||||||
_mapTextureMaterial.push_back(QPair<qlonglong, int>(_textureID, i));
|
_mapTextureMaterial.emplace_back(_textureID, i);
|
||||||
|
|
||||||
FBXNode textureNode;
|
FBXNode textureNode;
|
||||||
{
|
{
|
||||||
|
@ -277,18 +273,15 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
|
|
||||||
QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename;
|
QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename;
|
||||||
|
|
||||||
// Callback to get Texture content and type
|
auto textureType = (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE;
|
||||||
getTextureTypeCallback textureContentTypeCallback = [=]() {
|
|
||||||
return (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node
|
// Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node
|
||||||
QByteArray* textureFile = this->compressTexture(textureFileName, textureContentTypeCallback);
|
auto textureFile = compressTexture(textureFileName, textureType);
|
||||||
if (!textureFile) {
|
if (textureFile.isNull()) {
|
||||||
// Baking failed return
|
// Baking failed return
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
relativeFilenameNode.properties = { *textureFile };
|
relativeFilenameNode.properties = { textureFile };
|
||||||
|
|
||||||
textureNode.children = { textureNameNode, relativeFilenameNode };
|
textureNode.children = { textureNameNode, relativeFilenameNode };
|
||||||
|
|
||||||
|
@ -303,27 +296,19 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
// connect Geometry to Model
|
// connect Geometry to Model
|
||||||
FBXNode cNode;
|
FBXNode cNode;
|
||||||
cNode.name = C_NODE_NAME;
|
cNode.name = C_NODE_NAME;
|
||||||
cNode.properties = {
|
cNode.properties = { CONNECTIONS_NODE_PROPERTY, _geometryID, _modelID };
|
||||||
CONNECTIONS_NODE_PROPERTY,
|
|
||||||
_geometryID,
|
|
||||||
_modelID
|
|
||||||
};
|
|
||||||
connectionsNode.children = { cNode };
|
connectionsNode.children = { cNode };
|
||||||
|
|
||||||
// connect all materials to model
|
// connect all materials to model
|
||||||
for (auto& materialID : _materialIDs) {
|
for (auto& materialID : _materialIDs) {
|
||||||
FBXNode cNode;
|
FBXNode cNode;
|
||||||
cNode.name = C_NODE_NAME;
|
cNode.name = C_NODE_NAME;
|
||||||
cNode.properties = {
|
cNode.properties = { CONNECTIONS_NODE_PROPERTY, materialID, _modelID };
|
||||||
CONNECTIONS_NODE_PROPERTY,
|
|
||||||
materialID,
|
|
||||||
_modelID
|
|
||||||
};
|
|
||||||
connectionsNode.children.append(cNode);
|
connectionsNode.children.append(cNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect textures to materials
|
// Connect textures to materials
|
||||||
for (auto& texMat : _mapTextureMaterial) {
|
for (const auto& texMat : _mapTextureMaterial) {
|
||||||
FBXNode cAmbientNode;
|
FBXNode cAmbientNode;
|
||||||
cAmbientNode.name = C_NODE_NAME;
|
cAmbientNode.name = C_NODE_NAME;
|
||||||
cAmbientNode.properties = {
|
cAmbientNode.properties = {
|
||||||
|
@ -353,11 +338,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) {
|
void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) {
|
||||||
auto materialID = _nodeID++;
|
auto materialID = _nodeID++;
|
||||||
_materialIDs.push_back(materialID);
|
_materialIDs.push_back(materialID);
|
||||||
materialNode.properties = {
|
materialNode.properties = { materialID, material, MESH };
|
||||||
materialID,
|
|
||||||
material,
|
|
||||||
MESH
|
|
||||||
};
|
|
||||||
|
|
||||||
FBXMaterial currentMaterial = geometry.materials[material];
|
FBXMaterial currentMaterial = geometry.materials[material];
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
|
|
||||||
using TextureBakerThreadGetter = std::function<QThread*()>;
|
using TextureBakerThreadGetter = std::function<QThread*()>;
|
||||||
|
|
||||||
|
using TextureID = int64_t;
|
||||||
|
using MaterialID = int64_t;
|
||||||
|
|
||||||
class OBJBaker : public ModelBaker {
|
class OBJBaker : public ModelBaker {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -43,9 +46,9 @@ private:
|
||||||
qlonglong _nodeID = 0;
|
qlonglong _nodeID = 0;
|
||||||
qlonglong _geometryID;
|
qlonglong _geometryID;
|
||||||
qlonglong _modelID;
|
qlonglong _modelID;
|
||||||
std::vector<qlonglong> _materialIDs;
|
std::vector<MaterialID> _materialIDs;
|
||||||
qlonglong _textureID;
|
qlonglong _textureID;
|
||||||
std::vector<QPair<qlonglong, int>> _mapTextureMaterial;
|
std::vector<std::pair<TextureID, int>> _mapTextureMaterial;
|
||||||
FBXNode _objectNode;
|
FBXNode _objectNode;
|
||||||
};
|
};
|
||||||
#endif // hifi_OBJBaker_h
|
#endif // hifi_OBJBaker_h
|
||||||
|
|
|
@ -490,13 +490,13 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
||||||
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
||||||
QBuffer buffer { &model };
|
QBuffer buffer { &model };
|
||||||
buffer.open(QIODevice::ReadOnly);
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
FBXGeometry* geometryPtr = new FBXGeometry();
|
auto geometryPtr { std::make_shared<FBXGeometry>() };
|
||||||
FBXGeometry& geometry = *geometryPtr;
|
FBXGeometry& geometry { *geometryPtr };
|
||||||
OBJTokenizer tokenizer { &buffer };
|
OBJTokenizer tokenizer { &buffer };
|
||||||
float scaleGuess = 1.0f;
|
float scaleGuess = 1.0f;
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ public:
|
||||||
QString currentMaterialName;
|
QString currentMaterialName;
|
||||||
QHash<QString, OBJMaterial> materials;
|
QHash<QString, OBJMaterial> materials;
|
||||||
|
|
||||||
FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
FBXGeometry::Pointer readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
|
|
|
@ -186,11 +186,11 @@ void GeometryReader::run() {
|
||||||
throw QString("empty geometry, possibly due to an unsupported FBX version");
|
throw QString("empty geometry, possibly due to an unsupported FBX version");
|
||||||
}
|
}
|
||||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||||
fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url));
|
fbxGeometry = OBJReader().readOBJ(_data, _mapping, _combineParts, _url);
|
||||||
} else if (_url.path().toLower().endsWith(".obj.gz")) {
|
} else if (_url.path().toLower().endsWith(".obj.gz")) {
|
||||||
QByteArray uncompressedData;
|
QByteArray uncompressedData;
|
||||||
if (gunzip(_data, uncompressedData)){
|
if (gunzip(_data, uncompressedData)){
|
||||||
fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url));
|
fbxGeometry = OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url);
|
||||||
} else {
|
} else {
|
||||||
throw QString("failed to decompress .obj.gz" );
|
throw QString("failed to decompress .obj.gz" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,11 +304,11 @@ void DomainBaker::handleFinishedModelBaker() {
|
||||||
if (baker) {
|
if (baker) {
|
||||||
if (!baker->hasErrors()) {
|
if (!baker->hasErrors()) {
|
||||||
// this FBXBaker is done and everything went according to plan
|
// this FBXBaker is done and everything went according to plan
|
||||||
qDebug() << "Re-writing entity references to" << baker->getFBXUrl();
|
qDebug() << "Re-writing entity references to" << baker->getModelURL();
|
||||||
|
|
||||||
// enumerate the QJsonRef values for the URL of this FBX from our multi hash of
|
// enumerate the QJsonRef values for the URL of this FBX from our multi hash of
|
||||||
// entity objects needing a URL re-write
|
// entity objects needing a URL re-write
|
||||||
for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getFBXUrl())) {
|
for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getModelURL())) {
|
||||||
|
|
||||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||||
auto entity = entityValue.toObject();
|
auto entity = entityValue.toObject();
|
||||||
|
@ -317,7 +317,7 @@ void DomainBaker::handleFinishedModelBaker() {
|
||||||
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
|
||||||
auto relativeFBXFilePath = baker->getBakedFBXFilePath().remove(_contentOutputPath);
|
auto relativeFBXFilePath = baker->getBakedModelFilePath().remove(_contentOutputPath);
|
||||||
if (relativeFBXFilePath.startsWith("/")) {
|
if (relativeFBXFilePath.startsWith("/")) {
|
||||||
relativeFBXFilePath = relativeFBXFilePath.right(relativeFBXFilePath.length() - 1);
|
relativeFBXFilePath = relativeFBXFilePath.right(relativeFBXFilePath.length() - 1);
|
||||||
}
|
}
|
||||||
|
@ -370,10 +370,10 @@ void DomainBaker::handleFinishedModelBaker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
_entitiesNeedingRewrite.remove(baker->getFBXUrl());
|
_entitiesNeedingRewrite.remove(baker->getModelURL());
|
||||||
|
|
||||||
// drop our shared pointer to this baker so that it gets cleaned up
|
// drop our shared pointer to this baker so that it gets cleaned up
|
||||||
_modelBakers.remove(baker->getFBXUrl());
|
_modelBakers.remove(baker->getModelURL());
|
||||||
|
|
||||||
// emit progress to tell listeners how many models we have baked
|
// emit progress to tell listeners how many models we have baked
|
||||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||||
|
|
|
@ -42,5 +42,5 @@ void BakeWidget::cancelButtonClicked() {
|
||||||
auto stackedWidget = qobject_cast<QStackedWidget*>(parentWidget());
|
auto stackedWidget = qobject_cast<QStackedWidget*>(parentWidget());
|
||||||
stackedWidget->removeWidget(this);
|
stackedWidget->removeWidget(this);
|
||||||
|
|
||||||
this->deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,31 +204,30 @@ void ModelBakeWidget::bakeButtonClicked() {
|
||||||
bakedOutputDirectory.mkdir(".");
|
bakedOutputDirectory.mkdir(".");
|
||||||
originalOutputDirectory.mkdir(".");
|
originalOutputDirectory.mkdir(".");
|
||||||
|
|
||||||
|
std::unique_ptr<Baker> baker;
|
||||||
|
auto getWorkerThreadCallback = []() -> QThread* {
|
||||||
|
return qApp->getNextWorkerThread();
|
||||||
|
};
|
||||||
// everything seems to be in place, kick off a bake for this model now
|
// everything seems to be in place, kick off a bake for this model now
|
||||||
if (modelToBakeURL.fileName().endsWith(".fbx")) {
|
if (modelToBakeURL.fileName().endsWith(".fbx")) {
|
||||||
_baker = std::unique_ptr<FBXBaker>{
|
baker.reset(new FBXBaker(modelToBakeURL, getWorkerThreadCallback, bakedOutputDirectory.absolutePath(),
|
||||||
new FBXBaker(modelToBakeURL, []() -> QThread* {
|
originalOutputDirectory.absolutePath()));
|
||||||
return qApp->getNextWorkerThread();
|
|
||||||
}, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath())
|
|
||||||
};
|
|
||||||
_isFBX = true;
|
|
||||||
} else if (modelToBakeURL.fileName().endsWith(".obj")) {
|
} else if (modelToBakeURL.fileName().endsWith(".obj")) {
|
||||||
_baker = std::unique_ptr<OBJBaker>{
|
baker.reset(new OBJBaker(modelToBakeURL, getWorkerThreadCallback, bakedOutputDirectory.absolutePath(),
|
||||||
new OBJBaker(modelToBakeURL, []() -> QThread* {
|
originalOutputDirectory.absolutePath()));
|
||||||
return qApp->getNextWorkerThread();
|
} else {
|
||||||
}, bakedOutputDirectory.absolutePath(), originalOutputDirectory.absolutePath())
|
qWarning() << "Unknown model type: " << modelToBakeURL.fileName());
|
||||||
};
|
continue;
|
||||||
_isOBJ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// move the baker to the FBX/OBJ baker thread
|
// move the baker to the FBX/OBJ baker thread
|
||||||
_baker->moveToThread(qApp->getNextWorkerThread());
|
baker->moveToThread(qApp->getNextWorkerThread());
|
||||||
|
|
||||||
// invoke the bake method on the baker thread
|
// invoke the bake method on the baker thread
|
||||||
QMetaObject::invokeMethod(_baker.get(), "bake");
|
QMetaObject::invokeMethod(baker.get(), "bake");
|
||||||
|
|
||||||
// make sure we hear about the results of this baker when it is done
|
// make sure we hear about the results of this baker when it is done
|
||||||
connect(_baker.get(), &Baker::finished, this, &ModelBakeWidget::handleFinishedBaker);
|
connect(baker.get(), &Baker::finished, this, &ModelBakeWidget::handleFinishedBaker);
|
||||||
|
|
||||||
// add a pending row to the results window to show that this bake is in process
|
// add a pending row to the results window to show that this bake is in process
|
||||||
auto resultsWindow = qApp->getMainWindow()->showResultsWindow();
|
auto resultsWindow = qApp->getMainWindow()->showResultsWindow();
|
||||||
|
@ -236,16 +235,15 @@ void ModelBakeWidget::bakeButtonClicked() {
|
||||||
|
|
||||||
// keep a unique_ptr to this baker
|
// keep a unique_ptr to this baker
|
||||||
// and remember the row that represents it in the results table
|
// and remember the row that represents it in the results table
|
||||||
_bakers.emplace_back(std::move(_baker), resultsRow);
|
_bakers.emplace_back(std::move(baker), resultsRow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBakeWidget::handleFinishedBaker() {
|
void ModelBakeWidget::handleFinishedBaker() {
|
||||||
Baker* baker;
|
Baker* baker = dynamic_cast<Baker*>(sender());
|
||||||
if (_isFBX) {
|
if (!baker) {
|
||||||
baker = qobject_cast<FBXBaker*>(sender());
|
qWarning() << "Received signal from unexpected sender";
|
||||||
} else if (_isOBJ) {
|
return;
|
||||||
baker = qobject_cast<OBJBaker*>(sender());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the results of this bake to the results window
|
// add the results of this bake to the results window
|
||||||
|
|
|
@ -49,9 +49,6 @@ private:
|
||||||
Setting::Handle<QString> _modelStartDirectory;
|
Setting::Handle<QString> _modelStartDirectory;
|
||||||
|
|
||||||
std::unique_ptr<Baker> _baker;
|
std::unique_ptr<Baker> _baker;
|
||||||
|
|
||||||
bool _isOBJ = false;
|
|
||||||
bool _isFBX = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ModelBakeWidget_h
|
#endif // hifi_ModelBakeWidget_h
|
||||||
|
|
|
@ -46,7 +46,7 @@ ResultsWindow* OvenMainWindow::showResultsWindow(bool shouldRaise) {
|
||||||
_resultsWindow->show();
|
_resultsWindow->show();
|
||||||
|
|
||||||
// place the results window initially below our window
|
// place the results window initially below our window
|
||||||
_resultsWindow->move(_resultsWindow->x(), this->frameGeometry().bottom());
|
_resultsWindow->move(_resultsWindow->x(), frameGeometry().bottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
// show the results window and make sure it is in front
|
// show the results window and make sure it is in front
|
||||||
|
|
|
@ -41,18 +41,17 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
QByteArray fbxContents = fbx.readAll();
|
QByteArray fbxContents = fbx.readAll();
|
||||||
FBXGeometry* geom;
|
FBXGeometry::Pointer geom;
|
||||||
if (filename.toLower().endsWith(".obj")) {
|
if (filename.toLower().endsWith(".obj")) {
|
||||||
bool combineParts = false;
|
bool combineParts = false;
|
||||||
geom = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts);
|
geom = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts);
|
||||||
} else if (filename.toLower().endsWith(".fbx")) {
|
} else if (filename.toLower().endsWith(".fbx")) {
|
||||||
geom = readFBX(fbxContents, QVariantHash(), filename);
|
geom.reset(readFBX(fbxContents, QVariantHash(), filename));
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "file has unknown extension" << filename;
|
qWarning() << "file has unknown extension" << filename;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = *geom;
|
result = *geom;
|
||||||
delete geom;
|
|
||||||
|
|
||||||
reSortFBXGeometryMeshes(result);
|
reSortFBXGeometryMeshes(result);
|
||||||
} catch (const QString& error) {
|
} catch (const QString& error) {
|
||||||
|
|
Loading…
Reference in a new issue