259 lines · 10.6 KB · C++
RawDownload
////  FBXSerializer_Material.cpp//  libraries/model-serializers/src////  Created by Sam Gateau on 8/27/2015.//  Copyright 2015 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "FBXSerializer.h" #include <iostream>#include <memory> #include <QBuffer>#include <QIODevice>#include <QStringList>#include <QTextStream>#include <QtDebug>#include <QtEndian>#include <QFileInfo>#include <QJsonDocument>#include <QJsonObject> #include <hfm/ModelFormatLogging.h> HFMTexture FBXSerializer::getTexture(const QString& textureID, const QString& materialID) {    HFMTexture texture;    const hifi::ByteArray& filepath = _textureFilepaths.value(textureID);    texture.content = _textureContent.value(filepath);     if (texture.content.isEmpty()) { // the content is not inlined        texture.filename = _textureFilenames.value(textureID);    } else { // use supplied filepath for inlined content        texture.filename = filepath;    }     texture.id = textureID;    texture.name = _textureNames.value(textureID);    texture.transform.setIdentity();    texture.texcoordSet = 0;    if (_textureParams.contains(textureID)) {        auto p = _textureParams.value(textureID);         texture.transform.postTranslate(p.translation);        texture.transform.postRotate(glm::quat(glm::radians(p.rotation)));         auto scaling = p.scaling;        // Protect from bad scaling which should never happen        if (scaling.x == 0.0f) {            scaling.x = 1.0f;        }        if (scaling.y == 0.0f) {            scaling.y = 1.0f;        }        if (scaling.z == 0.0f) {            scaling.z = 1.0f;        }        texture.transform.postScale(scaling);         // FIXME: FBX files do not support multiple texcoordSets        // texture.texcoordSet = ??;         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;} void FBXSerializer::consolidateHFMMaterials() {    for (QHash<QString, HFMMaterial>::iterator it = _hfmMaterials.begin(); it != _hfmMaterials.end(); it++) {        HFMMaterial& material = (*it);         // Maya is the exporting the shading model and we are trying to use it        bool isMaterialLambert = (material.shadingModel.toLower() == "lambert");         // the pure material associated with this part        HFMTexture diffuseTexture;        HFMTexture diffuseFactorTexture;        QString diffuseTextureID = diffuseTextures.value(material.materialID);        QString diffuseFactorTextureID = diffuseFactorTextures.value(material.materialID);         // If both factor and color textures are specified, the texture bound to DiffuseColor wins        if (!diffuseFactorTextureID.isNull() || !diffuseTextureID.isNull()) {            if (!diffuseFactorTextureID.isNull() && diffuseTextureID.isNull()) {                diffuseTextureID = diffuseFactorTextureID;                // If the diffuseTextureID comes from the Texture bound to DiffuseFactor, we know it s exported from maya                // And the DiffuseFactor is forced to 0.5 by Maya which is bad                // So we need to force it to 1.0                material.diffuseFactor = 1.0;            }             diffuseTexture = getTexture(diffuseTextureID, material.materialID);             // FBX files generated by 3DSMax have an intermediate texture parent, apparently            foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {                if (_textureFilenames.contains(childTextureID)) {                    diffuseTexture = getTexture(diffuseTextureID, material.materialID);                }            }             material.albedoTexture = diffuseTexture;        }         HFMTexture transparentTexture;        QString transparentTextureID = transparentTextures.value(material.materialID);        // If PBS Material, systematically bind the albedo texture as transparency texture and check for the alpha channel        if (material.isPBSMaterial) {            transparentTextureID = diffuseTextureID;        }        if (!transparentTextureID.isNull()) {            transparentTexture = getTexture(transparentTextureID, material.materialID);            material.opacityTexture = transparentTexture;        }         HFMTexture normalTexture;        QString bumpTextureID = bumpTextures.value(material.materialID);        QString normalTextureID = normalTextures.value(material.materialID);        if (!normalTextureID.isNull()) {            normalTexture = getTexture(normalTextureID, material.materialID);            normalTexture.isBumpmap = false;             material.normalTexture = normalTexture;        } else if (!bumpTextureID.isNull()) {            normalTexture = getTexture(bumpTextureID, material.materialID);            normalTexture.isBumpmap = true;             material.normalTexture = normalTexture;        }         HFMTexture specularTexture;        QString specularTextureID = specularTextures.value(material.materialID);        if (!specularTextureID.isNull()) {            specularTexture = getTexture(specularTextureID, material.materialID);            material.specularTexture = specularTexture;        }         HFMTexture metallicTexture;        QString metallicTextureID = metallicTextures.value(material.materialID);        if (!metallicTextureID.isNull()) {            metallicTexture = getTexture(metallicTextureID, material.materialID);            material.metallicTexture = metallicTexture;        }         HFMTexture roughnessTexture;        QString roughnessTextureID = roughnessTextures.value(material.materialID);        if (!roughnessTextureID.isNull()) {            roughnessTexture = getTexture(roughnessTextureID, material.materialID);            material.roughnessTexture = roughnessTexture;        }         HFMTexture shininessTexture;        QString shininessTextureID = shininessTextures.value(material.materialID);        if (!shininessTextureID.isNull()) {            shininessTexture = getTexture(shininessTextureID, material.materialID);            material.glossTexture = shininessTexture;        }         HFMTexture emissiveTexture;        QString emissiveTextureID = emissiveTextures.value(material.materialID);        if (!emissiveTextureID.isNull()) {            emissiveTexture = getTexture(emissiveTextureID, material.materialID);            material.emissiveTexture = emissiveTexture;             if (isMaterialLambert) {                // If the emissiveTextureID comes from the Texture bound to Emissive when material is lambert, we know it s exported from maya                // And the EMissiveColor is forced to 0.5 by Maya which is bad                // So we need to force it to 1.0                material.emissiveColor = vec3(1.0);            }        }         HFMTexture occlusionTexture;        QString occlusionTextureID = occlusionTextures.value(material.materialID);        if (occlusionTextureID.isNull()) {            // 2nd chance            // For blender we use the ambient factor texture as AOMap ONLY if the ambientFactor value is > 0.0            if (material.ambientFactor > 0.0f) {                occlusionTextureID = ambientFactorTextures.value(material.materialID);            }        }         if (!occlusionTextureID.isNull()) {            occlusionTexture = getTexture(occlusionTextureID, material.materialID);            material.occlusionTexture = occlusionTexture;        }         glm::vec2 lightmapParams(0.f, 1.f);        lightmapParams.x = _lightmapOffset;        lightmapParams.y = _lightmapLevel;         HFMTexture ambientTexture;        QString ambientTextureID = ambientTextures.value(material.materialID);        if (ambientTextureID.isNull()) {            // 2nd chance            // For blender we use the ambient factor texture as Lightmap ONLY if the ambientFactor value is set to 0            if (material.ambientFactor == 0.0f) {                ambientTextureID = ambientFactorTextures.value(material.materialID);            }        }         if (_loadLightmaps && !ambientTextureID.isNull()) {            ambientTexture = getTexture(ambientTextureID, material.materialID);            material.lightmapTexture = ambientTexture;            material.lightmapParams = lightmapParams;        }         // Finally create the true material representation        material._material = std::make_shared<graphics::Material>();         // Emissive color is the mix of emissiveColor with emissiveFactor        auto emissive = material.emissiveColor * (isMaterialLambert ? 1.0f : material.emissiveFactor); // In lambert there is not emissiveFactor        material._material->setEmissive(emissive);         // Final diffuse color is the mix of diffuseColor with diffuseFactor        auto diffuse = material.diffuseColor * material.diffuseFactor;        material._material->setAlbedo(diffuse);         if (material.isPBSMaterial) {            // Blender sets shininess for PBS            if (material.roughness > 0.0f) {                material._material->setRoughness(material.roughness);            } else {                material._material->setRoughness(graphics::Material::shininessToRoughness(material.shininess));            }            material._material->setMetallic(material.metallic);        } else {            material._material->setRoughness(graphics::Material::shininessToRoughness(material.shininess));            float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z));            material._material->setMetallic(metallic);             if (isMaterialLambert) {                if (!material._material->getKey().isAlbedo()) {                    // switch emissive to material albedo as we tag the material to unlit                    material._material->setUnlit(true);                    material._material->setAlbedo(emissive);                     if (!material.emissiveTexture.isNull()) {                        material.albedoTexture = material.emissiveTexture;                    }                }            }        }        qCDebug(modelformat) << " fbx material Name:" << material.name;         if (material.opacity <= 0.0f) {            material._material->setOpacity(1.0f);        } else {            material._material->setOpacity(material.opacity);        }    }}