//// 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); } }}
//
// 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);
}
}
}