mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 05:52:38 +02:00
enumerate materials to find textures with types
This commit is contained in:
parent
fcefe3ff81
commit
647377d07a
3 changed files with 191 additions and 85 deletions
|
@ -202,105 +202,190 @@ QString texturePathRelativeToFBX(QUrl fbxURL, QUrl textureURL) {
|
|||
}
|
||||
}
|
||||
|
||||
bool FBXBaker::rewriteAndBakeSceneTextures() {
|
||||
// get a count of the textures used in the scene
|
||||
int numTextures = _scene->GetTextureCount();
|
||||
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()];
|
||||
|
||||
// enumerate the textures in the scene
|
||||
for (int i = 0; i < numTextures; i++) {
|
||||
// grab each file texture
|
||||
FbxFileTexture* fileTexture = FbxCast<FbxFileTexture>(_scene->GetTexture(i));
|
||||
QString bakedTextureFileName { textureFileInfo.baseName() };
|
||||
|
||||
if (fileTexture) {
|
||||
// use QFileInfo to easily split up the existing texture filename into its components
|
||||
QFileInfo textureFileInfo { fileTexture->GetFileName() };
|
||||
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);
|
||||
}
|
||||
|
||||
// make sure this texture points to something
|
||||
if (!textureFileInfo.filePath().isEmpty()) {
|
||||
bakedTextureFileName += BAKED_TEXTURE_EXT;
|
||||
|
||||
// construct the new baked texture file name and file path
|
||||
// increment the number of name matches
|
||||
++nameMatches;
|
||||
|
||||
// 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()];
|
||||
return bakedTextureFileName;
|
||||
}
|
||||
|
||||
QString bakedTextureFileName { textureFileInfo.baseName() };
|
||||
QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, FbxFileTexture* fileTexture) {
|
||||
QUrl urlToTexture;
|
||||
|
||||
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);
|
||||
}
|
||||
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
|
||||
|
||||
bakedTextureFileName += BAKED_TEXTURE_EXT;
|
||||
|
||||
// increment the number of name matches
|
||||
++nameMatches;
|
||||
|
||||
QString bakedTextureFilePath { _uniqueOutputPath + BAKED_OUTPUT_SUBFOLDER + BAKED_TEXTURE_DIRECTORY + bakedTextureFileName };
|
||||
|
||||
qCDebug(model_baking).noquote() << "Re-mapping" << fileTexture->GetFileName() << "to" << bakedTextureFilePath;
|
||||
|
||||
// write the new filename into the FBX scene
|
||||
fileTexture->SetFileName(bakedTextureFilePath.toLocal8Bit());
|
||||
|
||||
QUrl urlToTexture;
|
||||
|
||||
// add the texture to the list of textures needing to be baked
|
||||
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
|
||||
|
||||
// first check if it the RelativePath to the texture in the FBX was relative
|
||||
QString relativeFileName = fileTexture->GetRelativeFileName();
|
||||
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
||||
// first check if it the RelativePath to the texture in the FBX was relative
|
||||
QString relativeFileName = fileTexture->GetRelativeFileName();
|
||||
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
// it turns out that paths that start with a drive letter and a colon appear to QFileInfo
|
||||
// as a relative path on UNIX systems - we perform a special check here to handle that case
|
||||
bool isAbsolute = relativeFileName[1] == ':' || apparentRelativePath.isAbsolute();
|
||||
// it turns out that paths that start with a drive letter and a colon appear to QFileInfo
|
||||
// as a relative path on UNIX systems - we perform a special check here to handle that case
|
||||
bool isAbsolute = relativeFileName[1] == ':' || apparentRelativePath.isAbsolute();
|
||||
#else
|
||||
bool isAbsolute = apparentRelativePath.isAbsolute();
|
||||
bool isAbsolute = apparentRelativePath.isAbsolute();
|
||||
#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());
|
||||
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 {
|
||||
// simply construct a URL with the relative path to the asset, locally or remotely
|
||||
// and append that to the list of unbaked textures
|
||||
urlToTexture = _fbxURL.resolved(apparentRelativePath.filePath());
|
||||
}
|
||||
}
|
||||
|
||||
return urlToTexture;
|
||||
}
|
||||
|
||||
TextureType textureTypeForMaterialProperty(FbxProperty& property, FbxSurfaceMaterial* material) {
|
||||
// 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
|
||||
|
||||
// grab the hierarchical name for this property and lowercase it for case-insensitive compare
|
||||
auto propertyName = QString(property.GetHierarchicalName()).toLower();
|
||||
|
||||
// figure out the type of the property based on what known value string it matches
|
||||
if ((propertyName.contains("diffuse") && !propertyName.contains("tex_global_diffuse"))
|
||||
|| propertyName.contains("tex_color_map")) {
|
||||
return ALBEDO_TEXTURE;
|
||||
} else if (propertyName.contains("transparentcolor") || propertyName.contains("transparencyfactor")) {
|
||||
return ALBEDO_TEXTURE;
|
||||
} else if (propertyName.contains("bump")) {
|
||||
return BUMP_TEXTURE;
|
||||
} else if (propertyName.contains("normal")) {
|
||||
return NORMAL_TEXTURE;
|
||||
} else if ((propertyName.contains("specular") && !propertyName.contains("tex_global_specular"))
|
||||
|| propertyName.contains("reflection")) {
|
||||
return SPECULAR_TEXTURE;
|
||||
} else if (propertyName.contains("tex_metallic_map")) {
|
||||
return METALLIC_TEXTURE;
|
||||
} else if (propertyName.contains("shininess")) {
|
||||
return GLOSS_TEXTURE;
|
||||
} else if (propertyName.contains("tex_roughness_map")) {
|
||||
return ROUGHNESS_TEXTURE;
|
||||
} else if (propertyName.contains("emissive")) {
|
||||
return EMISSIVE_TEXTURE;
|
||||
} else if (propertyName.contains("ambientcolor")) {
|
||||
return LIGHTMAP_TEXTURE;
|
||||
} else if (propertyName.contains("ambientfactor")) {
|
||||
// we need to check what the ambient factor is, since that tells Interface to process this texture
|
||||
// either as an occlusion texture or a light map
|
||||
auto lambertMaterial = FbxCast<FbxSurfaceLambert>(material);
|
||||
|
||||
if (lambertMaterial->AmbientFactor == 0) {
|
||||
return LIGHTMAP_TEXTURE;
|
||||
} else if (lambertMaterial->AmbientFactor > 0) {
|
||||
return OCCLUSION_TEXTURE;
|
||||
} else {
|
||||
return UNUSED_TEXTURE;
|
||||
}
|
||||
|
||||
} else if (propertyName.contains("tex_ao_map")) {
|
||||
return OCCLUSION_TEXTURE;
|
||||
}
|
||||
|
||||
return UNUSED_TEXTURE;
|
||||
}
|
||||
|
||||
bool FBXBaker::rewriteAndBakeSceneTextures() {
|
||||
|
||||
// enumerate the surface materials to find the textures used in the scene
|
||||
int numMaterials = _scene->GetMaterialCount();
|
||||
for (int i = 0; i < numMaterials; i++) {
|
||||
FbxSurfaceMaterial* material = _scene->GetMaterial(i);
|
||||
|
||||
if (material) {
|
||||
// enumerate the properties of this material to see what texture channels it might have
|
||||
FbxProperty property = material->GetFirstProperty();
|
||||
|
||||
while (property.IsValid()) {
|
||||
// first check if this property has connected textures, if not we don't need to bother with it here
|
||||
if (property.GetSrcObjectCount<FbxTexture>() > 0) {
|
||||
|
||||
// figure out the type of texture from the material property
|
||||
auto textureType = textureTypeForMaterialProperty(property, material);
|
||||
|
||||
if (textureType != UNUSED_TEXTURE) {
|
||||
int numTextures = property.GetSrcObjectCount<FbxFileTexture>();
|
||||
|
||||
for (int j = 0; j < numTextures; j++) {
|
||||
FbxFileTexture* fileTexture = property.GetSrcObject<FbxFileTexture>(j);
|
||||
|
||||
// use QFileInfo to easily split up the existing texture filename into its components
|
||||
QFileInfo textureFileInfo { fileTexture->GetFileName() };
|
||||
|
||||
// make sure this texture points to something
|
||||
if (!textureFileInfo.filePath().isEmpty()) {
|
||||
|
||||
// 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
|
||||
auto bakedTextureFileName = createBakedTextureFileName(textureFileInfo);
|
||||
QString bakedTextureFilePath {
|
||||
_uniqueOutputPath + BAKED_OUTPUT_SUBFOLDER + BAKED_TEXTURE_DIRECTORY + bakedTextureFileName
|
||||
};
|
||||
|
||||
qCDebug(model_baking).noquote() << "Re-mapping" << fileTexture->GetFileName() << "to" << bakedTextureFilePath;
|
||||
|
||||
// write the new filename into the FBX scene
|
||||
fileTexture->SetFileName(bakedTextureFilePath.toLocal8Bit());
|
||||
|
||||
// figure out the URL to this texture, embedded or external
|
||||
auto urlToTexture = getTextureURL(textureFileInfo, fileTexture);
|
||||
|
||||
// add the deduced url to the texture, associated with the resulting baked texture file name,
|
||||
// to our hash of textures needing to be baked
|
||||
_unbakedTextures.insert(urlToTexture, bakedTextureFileName);
|
||||
|
||||
// bake this texture asynchronously
|
||||
bakeTexture(urlToTexture);
|
||||
}
|
||||
} 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 {
|
||||
// simply construct a URL with the relative path to the asset, locally or remotely
|
||||
// and append that to the list of unbaked textures
|
||||
urlToTexture = _fbxURL.resolved(apparentRelativePath.filePath());
|
||||
}
|
||||
}
|
||||
|
||||
// add the deduced url to the texture, associated with the resulting baked texture file name, to our hash
|
||||
_unbakedTextures.insert(urlToTexture, bakedTextureFileName);
|
||||
|
||||
// bake this texture asynchronously
|
||||
bakeTexture(urlToTexture);
|
||||
property = material->GetNextProperty(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,28 @@ namespace fbxsdk {
|
|||
class FbxManager;
|
||||
class FbxProperty;
|
||||
class FbxScene;
|
||||
class FbxTexture;
|
||||
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
|
||||
};
|
||||
|
||||
class TextureBaker;
|
||||
|
||||
class FBXBaker : public QObject {
|
||||
|
@ -49,6 +68,9 @@ private:
|
|||
bool exportScene();
|
||||
bool removeEmbeddedMediaFolder();
|
||||
|
||||
QString createBakedTextureFileName(const QFileInfo& textureFileInfo);
|
||||
QUrl getTextureURL(const QFileInfo& textureFileInfo, fbxsdk::FbxFileTexture* fileTexture);
|
||||
|
||||
void bakeTexture(const QUrl& textureURL);
|
||||
|
||||
QString pathToCopyOfOriginal() const;
|
||||
|
@ -66,8 +88,7 @@ private:
|
|||
|
||||
QHash<QUrl, QString> _unbakedTextures;
|
||||
QHash<QString, int> _textureNameMatchCount;
|
||||
|
||||
QHash<QUrl, QByteArray> _downloadedTextures;
|
||||
QHash<uint64_t, TextureType> _textureTypes;
|
||||
|
||||
std::list<std::unique_ptr<TextureBaker>> _bakingTextures;
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/exp
|
|||
|
||||
Oven::Oven(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_testBake(QUrl("file:///Users/birarda/code/hifi/lod/test-oven/DiscGolfBasket.fbx"), OUTPUT_FOLDER)
|
||||
_testBake(QUrl("file:///Users/birarda/code/hifi/lod/test-oven/Test-Object6.fbx"), OUTPUT_FOLDER)
|
||||
{
|
||||
_testBake.start();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue