Merge pull request #14679 from sabrina-shanman/bug_uv-scale

(case 20096) Fix missing support for UV scaling parameters in FBX files
This commit is contained in:
Adam Smith 2019-01-25 16:21:15 -08:00 committed by GitHub
commit e648ce38c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 40 deletions

View file

@ -755,17 +755,17 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
} else if (subobject.name == "Texture_Alpha_Source" && subobject.properties.length() >= TEXTURE_ALPHA_SOURCE_MIN_SIZE) { } else if (subobject.name == "Texture_Alpha_Source" && subobject.properties.length() >= TEXTURE_ALPHA_SOURCE_MIN_SIZE) {
tex.assign<uint8_t>(tex.alphaSource, subobject.properties.at(0).value<int>()); tex.assign<uint8_t>(tex.alphaSource, subobject.properties.at(0).value<int>());
} else if (subobject.name == "ModelUVTranslation" && subobject.properties.length() >= MODEL_UV_TRANSLATION_MIN_SIZE) { } else if (subobject.name == "ModelUVTranslation" && subobject.properties.length() >= MODEL_UV_TRANSLATION_MIN_SIZE) {
tex.assign(tex.UVTranslation, glm::vec2(subobject.properties.at(0).value<double>(), auto newTranslation = glm::vec3(subobject.properties.at(0).value<double>(), subobject.properties.at(1).value<double>(), 0.0);
subobject.properties.at(1).value<double>())); tex.assign(tex.translation, tex.translation + newTranslation);
} else if (subobject.name == "ModelUVScaling" && subobject.properties.length() >= MODEL_UV_SCALING_MIN_SIZE) { } else if (subobject.name == "ModelUVScaling" && subobject.properties.length() >= MODEL_UV_SCALING_MIN_SIZE) {
tex.assign(tex.UVScaling, glm::vec2(subobject.properties.at(0).value<double>(), auto newScaling = glm::vec3(subobject.properties.at(0).value<double>(), subobject.properties.at(1).value<double>(), 1.0);
subobject.properties.at(1).value<double>())); if (newScaling.x == 0.0f) {
if (tex.UVScaling.x == 0.0f) { newScaling.x = 1.0f;
tex.UVScaling.x = 1.0f;
} }
if (tex.UVScaling.y == 0.0f) { if (newScaling.y == 0.0f) {
tex.UVScaling.y = 1.0f; newScaling.y = 1.0f;
} }
tex.assign(tex.scaling, tex.scaling * newScaling);
} else if (subobject.name == "Cropping" && subobject.properties.length() >= CROPPING_MIN_SIZE) { } else if (subobject.name == "Cropping" && subobject.properties.length() >= CROPPING_MIN_SIZE) {
tex.assign(tex.cropping, glm::vec4(subobject.properties.at(0).value<int>(), tex.assign(tex.cropping, glm::vec4(subobject.properties.at(0).value<int>(),
subobject.properties.at(1).value<int>(), subobject.properties.at(1).value<int>(),
@ -793,20 +793,21 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
} else if (property.properties.at(0) == USE_MATERIAL) { } else if (property.properties.at(0) == USE_MATERIAL) {
tex.assign<bool>(tex.useMaterial, property.properties.at(index).value<int>()); tex.assign<bool>(tex.useMaterial, property.properties.at(index).value<int>());
} else if (property.properties.at(0) == TRANSLATION) { } else if (property.properties.at(0) == TRANSLATION) {
tex.assign(tex.translation, getVec3(property.properties, index)); tex.assign(tex.translation, tex.translation + getVec3(property.properties, index));
} else if (property.properties.at(0) == ROTATION) { } else if (property.properties.at(0) == ROTATION) {
tex.assign(tex.rotation, getVec3(property.properties, index)); tex.assign(tex.rotation, getVec3(property.properties, index));
} else if (property.properties.at(0) == SCALING) { } else if (property.properties.at(0) == SCALING) {
tex.assign(tex.scaling, getVec3(property.properties, index)); auto newScaling = getVec3(property.properties, index);
if (tex.scaling.x == 0.0f) { if (newScaling.x == 0.0f) {
tex.scaling.x = 1.0f; newScaling.x = 1.0f;
} }
if (tex.scaling.y == 0.0f) { if (newScaling.y == 0.0f) {
tex.scaling.y = 1.0f; newScaling.y = 1.0f;
} }
if (tex.scaling.z == 0.0f) { if (newScaling.z == 0.0f) {
tex.scaling.z = 1.0f; newScaling.z = 1.0f;
} }
tex.assign(tex.scaling, tex.scaling * newScaling);
} }
#if defined(DEBUG_FBXSERIALIZER) #if defined(DEBUG_FBXSERIALIZER)
else { else {
@ -851,6 +852,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
} }
} else if (object.name == "Material") { } else if (object.name == "Material") {
HFMMaterial material; HFMMaterial material;
MaterialParam materialParam;
material.name = (object.properties.at(1).toString()); material.name = (object.properties.at(1).toString());
foreach (const FBXNode& subobject, object.children) { foreach (const FBXNode& subobject, object.children) {
bool properties = false; bool properties = false;
@ -895,6 +897,10 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
static const QVariant MAYA_EMISSIVE_INTENSITY = QByteArray("Maya|emissive_intensity"); static const QVariant MAYA_EMISSIVE_INTENSITY = QByteArray("Maya|emissive_intensity");
static const QVariant MAYA_USE_EMISSIVE_MAP = QByteArray("Maya|use_emissive_map"); static const QVariant MAYA_USE_EMISSIVE_MAP = QByteArray("Maya|use_emissive_map");
static const QVariant MAYA_USE_AO_MAP = QByteArray("Maya|use_ao_map"); static const QVariant MAYA_USE_AO_MAP = QByteArray("Maya|use_ao_map");
static const QVariant MAYA_UV_SCALE = QByteArray("Maya|uv_scale");
static const QVariant MAYA_UV_OFFSET = QByteArray("Maya|uv_offset");
static const int MAYA_UV_OFFSET_PROPERTY_LENGTH = 6;
static const int MAYA_UV_SCALE_PROPERTY_LENGTH = 6;
@ -983,6 +989,27 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
material.isPBSMaterial = true; material.isPBSMaterial = true;
material.useOcclusionMap = (bool)property.properties.at(index).value<double>(); material.useOcclusionMap = (bool)property.properties.at(index).value<double>();
} else if (property.properties.at(0) == MAYA_UV_SCALE) {
if (property.properties.size() == MAYA_UV_SCALE_PROPERTY_LENGTH) {
// properties: { "Maya|uv_scale", "Vector2D", "Vector2", nothing, double, double }
glm::vec3 scale = glm::vec3(property.properties.at(4).value<double>(), property.properties.at(5).value<double>(), 1.0);
if (scale.x == 0.0f) {
scale.x = 1.0f;
}
if (scale.y == 0.0f) {
scale.y = 1.0f;
}
if (scale.z == 0.0f) {
scale.z = 1.0f;
}
materialParam.scaling *= scale;
}
} else if (property.properties.at(0) == MAYA_UV_OFFSET) {
if (property.properties.size() == MAYA_UV_OFFSET_PROPERTY_LENGTH) {
// properties: { "Maya|uv_offset", "Vector2D", "Vector2", nothing, double, double }
glm::vec3 translation = glm::vec3(property.properties.at(4).value<double>(), property.properties.at(5).value<double>(), 1.0);
materialParam.translation += translation;
}
} else { } else {
const QString propname = property.properties.at(0).toString(); const QString propname = property.properties.at(0).toString();
unknowns.push_back(propname.toStdString()); unknowns.push_back(propname.toStdString());
@ -1004,6 +1031,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
} }
material.materialID = getID(object.properties); material.materialID = getID(object.properties);
_hfmMaterials.insert(material.materialID, material); _hfmMaterials.insert(material.materialID, material);
_materialParams.insert(material.materialID, materialParam);
} else if (object.name == "NodeAttribute") { } else if (object.name == "NodeAttribute") {
@ -1437,7 +1465,9 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
materialIndex++; materialIndex++;
} else if (_textureFilenames.contains(childID)) { } else if (_textureFilenames.contains(childID)) {
HFMTexture texture = getTexture(childID); // NOTE (Sabrina 2019/01/11): getTextures now takes in the materialID as a second parameter, because FBX material nodes can sometimes have uv transform information (ex: "Maya|uv_scale")
// I'm leaving the second parameter blank right now as this code may never be used.
HFMTexture texture = getTexture(childID, "");
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
int partTexture = extracted.partMaterialTextures.at(j).second; int partTexture = extracted.partMaterialTextures.at(j).second;
if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) { if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) {

View file

@ -37,8 +37,6 @@ class FBXNode;
class TextureParam { class TextureParam {
public: public:
glm::vec2 UVTranslation;
glm::vec2 UVScaling;
glm::vec4 cropping; glm::vec4 cropping;
QString UVSet; QString UVSet;
@ -63,8 +61,6 @@ public:
bool isDefault; bool isDefault;
TextureParam() : TextureParam() :
UVTranslation(0.0f),
UVScaling(1.0f),
cropping(0.0f), cropping(0.0f),
UVSet("map1"), UVSet("map1"),
translation(0.0f), translation(0.0f),
@ -77,8 +73,6 @@ public:
{} {}
TextureParam(const TextureParam& src) : TextureParam(const TextureParam& src) :
UVTranslation(src.UVTranslation),
UVScaling(src.UVScaling),
cropping(src.cropping), cropping(src.cropping),
UVSet(src.UVSet), UVSet(src.UVSet),
translation(src.translation), translation(src.translation),
@ -92,6 +86,22 @@ public:
}; };
class MaterialParam {
public:
glm::vec3 translation;
glm::vec3 scaling;
MaterialParam() :
translation(0.0),
scaling(1.0)
{}
MaterialParam(const MaterialParam& src) :
translation(src.translation),
scaling(src.scaling)
{}
};
class ExtractedMesh; class ExtractedMesh;
class FBXSerializer : public HFMSerializer { class FBXSerializer : public HFMSerializer {
@ -114,7 +124,7 @@ public:
static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate = true); static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate = true);
QHash<QString, ExtractedMesh> meshes; QHash<QString, ExtractedMesh> meshes;
HFMTexture getTexture(const QString& textureID); HFMTexture getTexture(const QString& textureID, const QString& materialID);
QHash<QString, QString> _textureNames; QHash<QString, QString> _textureNames;
// Hashes the original RelativeFilename of textures // Hashes the original RelativeFilename of textures
@ -141,6 +151,7 @@ public:
QHash<QString, QString> occlusionTextures; QHash<QString, QString> occlusionTextures;
QHash<QString, HFMMaterial> _hfmMaterials; QHash<QString, HFMMaterial> _hfmMaterials;
QHash<QString, MaterialParam> _materialParams;
void consolidateHFMMaterials(const QVariantHash& mapping); void consolidateHFMMaterials(const QVariantHash& mapping);

View file

@ -27,7 +27,7 @@
#include <hfm/ModelFormatLogging.h> #include <hfm/ModelFormatLogging.h>
HFMTexture FBXSerializer::getTexture(const QString& textureID) { HFMTexture FBXSerializer::getTexture(const QString& textureID, const QString& materialID) {
HFMTexture texture; HFMTexture texture;
const QByteArray& filepath = _textureFilepaths.value(textureID); const QByteArray& filepath = _textureFilepaths.value(textureID);
texture.content = _textureContent.value(filepath); texture.content = _textureContent.value(filepath);
@ -45,8 +45,8 @@ HFMTexture FBXSerializer::getTexture(const QString& textureID) {
if (_textureParams.contains(textureID)) { if (_textureParams.contains(textureID)) {
auto p = _textureParams.value(textureID); auto p = _textureParams.value(textureID);
texture.transform.setTranslation(p.translation); texture.transform.postTranslate(p.translation);
texture.transform.setRotation(glm::quat(glm::radians(p.rotation))); texture.transform.postRotate(glm::quat(glm::radians(p.rotation)));
auto scaling = p.scaling; auto scaling = p.scaling;
// Protect from bad scaling which should never happen // Protect from bad scaling which should never happen
@ -59,13 +59,19 @@ HFMTexture FBXSerializer::getTexture(const QString& textureID) {
if (scaling.z == 0.0f) { if (scaling.z == 0.0f) {
scaling.z = 1.0f; scaling.z = 1.0f;
} }
texture.transform.setScale(scaling); texture.transform.postScale(scaling);
if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) { if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) {
texture.texcoordSet = 1; texture.texcoordSet = 1;
} }
texture.texcoordSetName = p.UVSet; texture.texcoordSetName = p.UVSet;
} }
auto materialParamItr = _materialParams.find(materialID);
if (materialParamItr != _materialParams.end()) {
auto& materialParam = materialParamItr.value();
texture.transform.postTranslate(materialParam.translation);
texture.transform.postScale(materialParam.scaling);
}
return texture; return texture;
} }
@ -102,12 +108,12 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
material.diffuseFactor = 1.0; material.diffuseFactor = 1.0;
} }
diffuseTexture = getTexture(diffuseTextureID); diffuseTexture = getTexture(diffuseTextureID, material.materialID);
// FBX files generated by 3DSMax have an intermediate texture parent, apparently // FBX files generated by 3DSMax have an intermediate texture parent, apparently
foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) { foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
if (_textureFilenames.contains(childTextureID)) { if (_textureFilenames.contains(childTextureID)) {
diffuseTexture = getTexture(diffuseTextureID); diffuseTexture = getTexture(diffuseTextureID, material.materialID);
} }
} }
@ -122,7 +128,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
transparentTextureID = diffuseTextureID; transparentTextureID = diffuseTextureID;
} }
if (!transparentTextureID.isNull()) { if (!transparentTextureID.isNull()) {
transparentTexture = getTexture(transparentTextureID); transparentTexture = getTexture(transparentTextureID, material.materialID);
material.opacityTexture = transparentTexture; material.opacityTexture = transparentTexture;
detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity()); detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity());
} }
@ -131,13 +137,13 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
QString bumpTextureID = bumpTextures.value(material.materialID); QString bumpTextureID = bumpTextures.value(material.materialID);
QString normalTextureID = normalTextures.value(material.materialID); QString normalTextureID = normalTextures.value(material.materialID);
if (!normalTextureID.isNull()) { if (!normalTextureID.isNull()) {
normalTexture = getTexture(normalTextureID); normalTexture = getTexture(normalTextureID, material.materialID);
normalTexture.isBumpmap = false; normalTexture.isBumpmap = false;
material.normalTexture = normalTexture; material.normalTexture = normalTexture;
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
} else if (!bumpTextureID.isNull()) { } else if (!bumpTextureID.isNull()) {
normalTexture = getTexture(bumpTextureID); normalTexture = getTexture(bumpTextureID, material.materialID);
normalTexture.isBumpmap = true; normalTexture.isBumpmap = true;
material.normalTexture = normalTexture; material.normalTexture = normalTexture;
@ -147,7 +153,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
HFMTexture specularTexture; HFMTexture specularTexture;
QString specularTextureID = specularTextures.value(material.materialID); QString specularTextureID = specularTextures.value(material.materialID);
if (!specularTextureID.isNull()) { if (!specularTextureID.isNull()) {
specularTexture = getTexture(specularTextureID); specularTexture = getTexture(specularTextureID, material.materialID);
detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity()); detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity());
material.specularTexture = specularTexture; material.specularTexture = specularTexture;
} }
@ -155,7 +161,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
HFMTexture metallicTexture; HFMTexture metallicTexture;
QString metallicTextureID = metallicTextures.value(material.materialID); QString metallicTextureID = metallicTextures.value(material.materialID);
if (!metallicTextureID.isNull()) { if (!metallicTextureID.isNull()) {
metallicTexture = getTexture(metallicTextureID); metallicTexture = getTexture(metallicTextureID, material.materialID);
detectDifferentUVs |= (metallicTexture.texcoordSet != 0) || (!metallicTexture.transform.isIdentity()); detectDifferentUVs |= (metallicTexture.texcoordSet != 0) || (!metallicTexture.transform.isIdentity());
material.metallicTexture = metallicTexture; material.metallicTexture = metallicTexture;
} }
@ -163,7 +169,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
HFMTexture roughnessTexture; HFMTexture roughnessTexture;
QString roughnessTextureID = roughnessTextures.value(material.materialID); QString roughnessTextureID = roughnessTextures.value(material.materialID);
if (!roughnessTextureID.isNull()) { if (!roughnessTextureID.isNull()) {
roughnessTexture = getTexture(roughnessTextureID); roughnessTexture = getTexture(roughnessTextureID, material.materialID);
material.roughnessTexture = roughnessTexture; material.roughnessTexture = roughnessTexture;
detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity()); detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity());
} }
@ -171,7 +177,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
HFMTexture shininessTexture; HFMTexture shininessTexture;
QString shininessTextureID = shininessTextures.value(material.materialID); QString shininessTextureID = shininessTextures.value(material.materialID);
if (!shininessTextureID.isNull()) { if (!shininessTextureID.isNull()) {
shininessTexture = getTexture(shininessTextureID); shininessTexture = getTexture(shininessTextureID, material.materialID);
material.glossTexture = shininessTexture; material.glossTexture = shininessTexture;
detectDifferentUVs |= (shininessTexture.texcoordSet != 0) || (!shininessTexture.transform.isIdentity()); detectDifferentUVs |= (shininessTexture.texcoordSet != 0) || (!shininessTexture.transform.isIdentity());
} }
@ -179,7 +185,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
HFMTexture emissiveTexture; HFMTexture emissiveTexture;
QString emissiveTextureID = emissiveTextures.value(material.materialID); QString emissiveTextureID = emissiveTextures.value(material.materialID);
if (!emissiveTextureID.isNull()) { if (!emissiveTextureID.isNull()) {
emissiveTexture = getTexture(emissiveTextureID); emissiveTexture = getTexture(emissiveTextureID, material.materialID);
detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity()); detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
material.emissiveTexture = emissiveTexture; material.emissiveTexture = emissiveTexture;
@ -202,7 +208,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
} }
if (!occlusionTextureID.isNull()) { if (!occlusionTextureID.isNull()) {
occlusionTexture = getTexture(occlusionTextureID); occlusionTexture = getTexture(occlusionTextureID, material.materialID);
detectDifferentUVs |= (occlusionTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity()); detectDifferentUVs |= (occlusionTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
material.occlusionTexture = occlusionTexture; material.occlusionTexture = occlusionTexture;
} }
@ -222,7 +228,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
} }
if (_loadLightmaps && !ambientTextureID.isNull()) { if (_loadLightmaps && !ambientTextureID.isNull()) {
ambientTexture = getTexture(ambientTextureID); ambientTexture = getTexture(ambientTextureID, material.materialID);
detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity()); detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity());
material.lightmapTexture = ambientTexture; material.lightmapTexture = ambientTexture;
material.lightmapParams = lightmapParams; material.lightmapParams = lightmapParams;