From 4a66ec25d0371f694e3aa41f3a0996c24a606651 Mon Sep 17 00:00:00 2001 From: RichardTea <31507749+RichardTea@users.noreply.github.com> Date: Fri, 11 Jun 2021 13:44:52 +0100 Subject: [PATCH] Standardise Clearcoat, Sheen and Transmission Also cleanup glTFv2 defaults, don't import/export if disabled --- code/AssetLib/glTF2/glTF2Exporter.cpp | 236 +++++++++++++++----------- code/AssetLib/glTF2/glTF2Exporter.h | 26 ++- code/AssetLib/glTF2/glTF2Importer.cpp | 39 ++--- code/Common/material.cpp | 12 +- include/assimp/material.h | 77 ++++++++- include/assimp/pbrmaterial.h | 28 +-- test/unit/utglTF2ImportExport.cpp | 15 ++ 7 files changed, 281 insertions(+), 152 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index dfa62372a..3cb3891b0 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -436,11 +436,11 @@ inline void SetSamplerWrap(SamplerWrap& wrap, aiTextureMapMode map) }; } -void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref texture, aiTextureType tt, unsigned int slot) +void glTF2Exporter::GetTexSampler(const aiMaterial& mat, Ref texture, aiTextureType tt, unsigned int slot) { aiString aId; std::string id; - if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) { + if (aiGetMaterialString(&mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) { id = aId.C_Str(); } @@ -455,49 +455,49 @@ void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref texture, a SamplerMagFilter filterMag; SamplerMinFilter filterMin; - if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) { + if (aiGetMaterialInteger(&mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) { SetSamplerWrap(texture->sampler->wrapS, mapU); } - if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) { + if (aiGetMaterialInteger(&mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) { SetSamplerWrap(texture->sampler->wrapT, mapV); } - if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) { + if (aiGetMaterialInteger(&mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) { texture->sampler->magFilter = filterMag; } - if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) { + if (aiGetMaterialInteger(&mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) { texture->sampler->minFilter = filterMin; } aiString name; - if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) { + if (aiGetMaterialString(&mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) { texture->sampler->name = name.C_Str(); } } } -void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot) +void glTF2Exporter::GetMatTexProp(const aiMaterial& mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot) { std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName; - mat->Get(textureKey.c_str(), tt, slot, prop); + mat.Get(textureKey.c_str(), tt, slot, prop); } -void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot) +void glTF2Exporter::GetMatTexProp(const aiMaterial& mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot) { std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName; - mat->Get(textureKey.c_str(), tt, slot, prop); + mat.Get(textureKey.c_str(), tt, slot, prop); } -void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref& texture, aiTextureType tt, unsigned int slot = 0) +void glTF2Exporter::GetMatTex(const aiMaterial& mat, Ref& texture, aiTextureType tt, unsigned int slot = 0) { - if (mat->GetTextureCount(tt) > 0) { + if (mat.GetTextureCount(tt) > 0) { aiString tex; - if (mat->Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { + if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { std::string path = tex.C_Str(); if (path.size() > 0) { @@ -568,7 +568,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref& texture, aiTe } } -void glTF2Exporter::GetMatTex(const aiMaterial* mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0) +void glTF2Exporter::GetMatTex(const aiMaterial& mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0) { Ref& texture = prop.texture; @@ -579,7 +579,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, TextureInfo& prop, aiTextur } } -void glTF2Exporter::GetMatTex(const aiMaterial* mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) +void glTF2Exporter::GetMatTex(const aiMaterial& mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) { Ref& texture = prop.texture; @@ -591,7 +591,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, NormalTextureInfo& prop, ai } } -void glTF2Exporter::GetMatTex(const aiMaterial* mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) +void glTF2Exporter::GetMatTex(const aiMaterial& mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) { Ref& texture = prop.texture; @@ -603,10 +603,10 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, OcclusionTextureInfo& prop, } } -aiReturn glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const char* propName, int type, int idx) +aiReturn glTF2Exporter::GetMatColor(const aiMaterial& mat, vec4& prop, const char* propName, int type, int idx) const { aiColor4D col; - aiReturn result = mat->Get(propName, type, idx, col); + aiReturn result = mat.Get(propName, type, idx, col); if (result == AI_SUCCESS) { prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[3] = col.a; @@ -615,30 +615,109 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const cha return result; } -aiReturn glTF2Exporter::GetMatColor(const aiMaterial* mat, vec3& prop, const char* propName, int type, int idx) +aiReturn glTF2Exporter::GetMatColor(const aiMaterial& mat, vec3& prop, const char* propName, int type, int idx) const { aiColor3D col; - aiReturn result = mat->Get(propName, type, idx, col); + aiReturn result = mat.Get(propName, type, idx, col); if (result == AI_SUCCESS) { - prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; + prop[0] = col.r; + prop[1] = col.g; + prop[2] = col.b; } return result; } +bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) { + bool result = false; + // If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension + // NOTE: This extension is being considered for deprecation (Dec 2020), may be replaced by KHR_material_specular + + if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) { + result = true; + } else { + // Don't have explicit glossiness, convert from pbr roughness or legacy shininess + float shininess; + if (mat.Get(AI_MATKEY_ROUGHNESS_FACTOR, shininess) == AI_SUCCESS) { + pbrSG.glossinessFactor = 1.0f - shininess; // Extension defines this way + } else if (mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) { + pbrSG.glossinessFactor = shininess / 1000; + } + } + + if (GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_COLOR_SPECULAR) == AI_SUCCESS) { + result = true; + } + // Add any appropriate textures + GetMatTex(mat, pbrSG.specularGlossinessTexture, aiTextureType_SPECULAR); + + result == result || pbrSG.specularGlossinessTexture.texture; + + if (result) { + // Likely to always have diffuse + GetMatTex(mat, pbrSG.diffuseTexture, aiTextureType_DIFFUSE); + GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_COLOR_DIFFUSE); + } + + return result; +} + +bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) { + // Return true if got any valid Sheen properties or textures + if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) + return false; + + // Default Sheen color factor {0,0,0} disables Sheen, so do not export + if (sheen.sheenColorFactor == defaultSheenFactor) + return false; + + mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor); + + GetMatTex(mat, sheen.sheenColorTexture, AI_MATKEY_SHEEN_COLOR_TEXTURE); + GetMatTex(mat, sheen.sheenRoughnessTexture, AI_MATKEY_SHEEN_ROUGHNESS_TEXTURE); + + return true; +} + +bool glTF2Exporter::GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat) { + if (mat.Get(AI_MATKEY_CLEARCOAT_FACTOR, clearcoat.clearcoatFactor) != aiReturn_SUCCESS) { + return false; + } + + // Clearcoat factor of zero disables Clearcoat, so do not export + if (clearcoat.clearcoatFactor == 0.0f) + return false; + + mat.Get(AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR, clearcoat.clearcoatRoughnessFactor); + + GetMatTex(mat, clearcoat.clearcoatTexture, AI_MATKEY_CLEARCOAT_TEXTURE); + GetMatTex(mat, clearcoat.clearcoatRoughnessTexture, AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE); + GetMatTex(mat, clearcoat.clearcoatNormalTexture, AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE); + + return true; +} + +bool glTF2Exporter::GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission) { + bool result = mat.Get(AI_MATKEY_TRANSMISSION_FACTOR, transmission.transmissionFactor) == aiReturn_SUCCESS; + GetMatTex(mat, transmission.transmissionTexture, AI_MATKEY_TRANSMISSION_TEXTURE); + return result || transmission.transmissionTexture.texture; +} + void glTF2Exporter::ExportMaterials() { aiString aiName; for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { - const aiMaterial* mat = mScene->mMaterials[i]; + ai_assert(mScene->mMaterials[i] != nullptr); + + const aiMaterial & mat = *(mScene->mMaterials[i]); std::string id = "material_" + ai_to_string(i); Ref m = mAsset->materials.Create(id); std::string name; - if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) { + if (mat.Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) { name = aiName.C_Str(); } name = mAsset->FindUniqueID(name, "material"); @@ -660,20 +739,20 @@ void glTF2Exporter::ExportMaterials() GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE); } - if (mat->Get(AI_MATKEY_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) { + if (mat.Get(AI_MATKEY_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) { //if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0 m->pbrMetallicRoughness.metallicFactor = 0; } // get roughness if source is gltf2 file - if (mat->Get(AI_MATKEY_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor) != AI_SUCCESS) { + if (mat.Get(AI_MATKEY_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor) != AI_SUCCESS) { // otherwise, try to derive and convert from specular + shininess values aiColor4D specularColor; ai_real shininess; if ( - mat->Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && - mat->Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS + mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && + mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS ) { // convert specular color to luminance float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f; @@ -694,17 +773,17 @@ void glTF2Exporter::ExportMaterials() GetMatTex(mat, m->emissiveTexture, aiTextureType_EMISSIVE); GetMatColor(mat, m->emissiveFactor, AI_MATKEY_COLOR_EMISSIVE); - mat->Get(AI_MATKEY_TWOSIDED, m->doubleSided); - mat->Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff); + mat.Get(AI_MATKEY_TWOSIDED, m->doubleSided); + mat.Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff); aiString alphaMode; - if (mat->Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS) { + if (mat.Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS) { m->alphaMode = alphaMode.C_Str(); } else { float opacity; - if (mat->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) { + if (mat.Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) { if (opacity < 1) { m->alphaMode = "BLEND"; m->pbrMetallicRoughness.baseColorFactor[3] *= opacity; @@ -713,86 +792,43 @@ void glTF2Exporter::ExportMaterials() } { - // If has a Specular color, use the KHR_materials_pbrSpecularGlossiness extension + // KHR_materials_pbrSpecularGlossiness extension + // NOTE: This extension is being considered for deprecation (Dec 2020) PbrSpecularGlossiness pbrSG; - if (GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_COLOR_SPECULAR) == AI_SUCCESS) { - if (!mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness) { - mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true; - } - - GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_COLOR_DIFFUSE); - - // If don't have explicit glossiness then convert from roughness or shininess - if (mat->Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) != AI_SUCCESS) { - float shininess; - if (mat->Get(AI_MATKEY_ROUGHNESS_FACTOR, shininess) == AI_SUCCESS) { - pbrSG.glossinessFactor = 1.0f - shininess; // Extension defines this way - } else if (mat->Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) { - pbrSG.glossinessFactor = shininess / 1000; - } - } - - // Add any appropriate textures - GetMatTex(mat, pbrSG.diffuseTexture, aiTextureType_DIFFUSE); - GetMatTex(mat, pbrSG.specularGlossinessTexture, aiTextureType_SPECULAR); - + if (GetMatSpecGloss(mat, pbrSG)) { + mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true; m->pbrSpecularGlossiness = Nullable(pbrSG); } } // glTFv2 is either PBR or Unlit aiShadingMode shadingMode = aiShadingMode_PBR_BRDF; - mat->Get(AI_MATKEY_SHADING_MODEL, shadingMode); + mat.Get(AI_MATKEY_SHADING_MODEL, shadingMode); if (shadingMode == aiShadingMode_Unlit) { mAsset->extensionsUsed.KHR_materials_unlit = true; m->unlit = true; - } + } else { + // These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness + if (!m->pbrSpecularGlossiness.isPresent) { + // Sheen + MaterialSheen sheen; + if (GetMatSheen(mat, sheen)) { + mAsset->extensionsUsed.KHR_materials_sheen = true; + m->materialSheen = Nullable(sheen); + } - bool hasMaterialSheen = false; - mat->Get(AI_MATKEY_GLTF_MATERIAL_SHEEN, hasMaterialSheen); + MaterialClearcoat clearcoat; + if (GetMatClearcoat(mat, clearcoat)) { + mAsset->extensionsUsed.KHR_materials_clearcoat = true; + m->materialClearcoat = Nullable(clearcoat); + } - if (hasMaterialSheen) { - mAsset->extensionsUsed.KHR_materials_sheen = true; - - MaterialSheen sheen; - - GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); - mat->Get(AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor); - GetMatTex(mat, sheen.sheenColorTexture, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); - GetMatTex(mat, sheen.sheenRoughnessTexture, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); - - m->materialSheen = Nullable(sheen); - } - - bool hasMaterialClearcoat = false; - mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT, hasMaterialClearcoat); - - if (hasMaterialClearcoat) { - mAsset->extensionsUsed.KHR_materials_clearcoat= true; - - MaterialClearcoat clearcoat; - - mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR, clearcoat.clearcoatFactor); - mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR, clearcoat.clearcoatRoughnessFactor); - GetMatTex(mat, clearcoat.clearcoatTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); - GetMatTex(mat, clearcoat.clearcoatRoughnessTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); - GetMatTex(mat, clearcoat.clearcoatNormalTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); - - m->materialClearcoat = Nullable(clearcoat); - } - - bool hasMaterialTransmission = false; - mat->Get(AI_MATKEY_GLTF_MATERIAL_TRANSMISSION, hasMaterialTransmission); - - if (hasMaterialTransmission) { - mAsset->extensionsUsed.KHR_materials_transmission = true; - - MaterialTransmission transmission; - - mat->Get(AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR, transmission.transmissionFactor); - GetMatTex(mat, transmission.transmissionTexture, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE); - - m->materialTransmission = Nullable(transmission); + MaterialTransmission transmission; + if (GetMatTransmission(mat, transmission)) { + mAsset->extensionsUsed.KHR_materials_transmission = true; + m->materialTransmission = Nullable(transmission); + } + } } } } diff --git a/code/AssetLib/glTF2/glTF2Exporter.h b/code/AssetLib/glTF2/glTF2Exporter.h index 86497516a..edc85d998 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.h +++ b/code/AssetLib/glTF2/glTF2Exporter.h @@ -72,6 +72,10 @@ namespace glTF2 struct OcclusionTextureInfo; struct Node; struct Texture; + struct PbrSpecularGlossiness; + struct MaterialSheen; + struct MaterialClearcoat; + struct MaterialTransmission; // Vec/matrix types, as raw float arrays typedef float (vec2)[2]; @@ -97,15 +101,19 @@ namespace Assimp protected: void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); - void GetTexSampler(const aiMaterial* mat, glTF2::Ref texture, aiTextureType tt, unsigned int slot); - void GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx); - void GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx); - void GetMatTex(const aiMaterial* mat, glTF2::Ref& texture, aiTextureType tt, unsigned int slot); - void GetMatTex(const aiMaterial* mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot); - void GetMatTex(const aiMaterial* mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot); - void GetMatTex(const aiMaterial* mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot); - aiReturn GetMatColor(const aiMaterial* mat, glTF2::vec4& prop, const char* propName, int type, int idx); - aiReturn GetMatColor(const aiMaterial* mat, glTF2::vec3& prop, const char* propName, int type, int idx); + void GetTexSampler(const aiMaterial& mat, glTF2::Ref texture, aiTextureType tt, unsigned int slot); + void GetMatTexProp(const aiMaterial& mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx); + void GetMatTexProp(const aiMaterial& mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx); + void GetMatTex(const aiMaterial& mat, glTF2::Ref& texture, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial& mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial& mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial& mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot); + aiReturn GetMatColor(const aiMaterial& mat, glTF2::vec4& prop, const char* propName, int type, int idx) const; + aiReturn GetMatColor(const aiMaterial& mat, glTF2::vec3& prop, const char* propName, int type, int idx) const; + bool GetMatSpecGloss(const aiMaterial& mat, glTF2::PbrSpecularGlossiness& pbrSG); + bool GetMatSheen(const aiMaterial& mat, glTF2::MaterialSheen& sheen); + bool GetMatClearcoat(const aiMaterial& mat, glTF2::MaterialClearcoat& clearcoat); + bool GetMatTransmission(const aiMaterial& mat, glTF2::MaterialTransmission& transmission); void ExportMetadata(); void ExportMaterials(); void ExportMeshes(); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index b5ba65857..b0f0955f5 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -291,36 +291,37 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M aimat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); - //KHR_materials_sheen + // KHR_materials_sheen if (mat.materialSheen.isPresent) { MaterialSheen &sheen = mat.materialSheen.value; - - aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN); - SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); - aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); + // Default value {0,0,0} disables Sheen + if (sheen.sheenColorFactor != defaultSheenFactor) { + SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_SHEEN_COLOR_FACTOR); + aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_SHEEN_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_SHEEN_COLOR_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_SHEEN_ROUGHNESS_TEXTURE); + } } - //KHR_materials_clearcoat + // KHR_materials_clearcoat if (mat.materialClearcoat.isPresent) { MaterialClearcoat &clearcoat = mat.materialClearcoat.value; - - aimat->AddProperty(&mat.materialClearcoat.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT); - aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR); - aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); + // Default value 0.0 disables clearcoat + if (clearcoat.clearcoatFactor != 0.0f) { + aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_CLEARCOAT_FACTOR); + aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_CLEARCOAT_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE); + } } - //KHR_materials_transmission + // KHR_materials_transmission if (mat.materialTransmission.isPresent) { MaterialTransmission &transmission = mat.materialTransmission.value; - aimat->AddProperty(&mat.materialTransmission.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION); - aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE); + aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_TRANSMISSION_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_TRANSMISSION_TEXTURE); } return aimat; diff --git a/code/Common/material.cpp b/code/Common/material.cpp index 5230c8b43..6c90e66f0 100644 --- a/code/Common/material.cpp +++ b/code/Common/material.cpp @@ -47,10 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // ------------------------------------------------------------------------------- -const char* TextureTypeToString(aiTextureType in) -{ - switch (in) - { +const char *TextureTypeToString(aiTextureType in) { + switch (in) { case aiTextureType_NONE: return "n/a"; case aiTextureType_DIFFUSE: @@ -87,6 +85,12 @@ const char* TextureTypeToString(aiTextureType in) return "DiffuseRoughness"; case aiTextureType_AMBIENT_OCCLUSION: return "AmbientOcclusion"; + case aiTextureType_SHEEN: + return "Sheen"; + case aiTextureType_CLEARCOAT: + return "Clearcoat"; + case aiTextureType_TRANSMISSION: + return "Transmission"; case aiTextureType_UNKNOWN: return "Unknown"; default: diff --git a/include/assimp/material.h b/include/assimp/material.h index 11cdef1f4..33e39529e 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -144,7 +144,9 @@ enum aiTextureMapMode { enum aiTextureMapping { /** The mapping coordinates are taken from an UV channel. * - * The #AI_MATKEY_UVWSRC key specifies from which UV channel + * #AI_MATKEY_UVWSRC property + * + * Specifies from which UV channel * the texture coordinates are to be taken from (remember, * meshes can have more than one UV channel). */ @@ -292,6 +294,32 @@ enum aiTextureType { aiTextureType_DIFFUSE_ROUGHNESS = 16, aiTextureType_AMBIENT_OCCLUSION = 17, + /** PBR Material Modifiers + * Some modern renderers have further PBR modifiers that may be overlaid + * on top of the 'base' PBR materials for additional realism. + * These use multiple texture maps, so only the base type is directly defined + */ + + /** Sheen + * Generally used to simulate textiles that are covered in a layer of microfibers + * eg velvet + * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_sheen + */ + aiTextureType_SHEEN = 19, + + /** Clearcoat + * Simulates a layer of 'polish' or 'laquer' layered on top of a PBR substrate + * https://autodesk.github.io/standard-surface/#closures/coating + * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat + */ + aiTextureType_CLEARCOAT = 20, + + /** Transmission + * Simulates transmission through the surface + * May include further information such as wall thickness + */ + aiTextureType_TRANSMISSION = 21, + /** Unknown texture * * A texture reference that does not match any of the definitions @@ -314,7 +342,7 @@ ASSIMP_API const char *TextureTypeToString(enum aiTextureType in); // --------------------------------------------------------------------------- /** @brief Defines all shading models supported by the library * - * #AI_MATKEY_SHADING_MODEL + * Property: #AI_MATKEY_SHADING_MODEL * * The list of shading modes has been taken from Blender. * See Blender documentation for more information. The API does @@ -324,6 +352,7 @@ ASSIMP_API const char *TextureTypeToString(enum aiTextureType in); * Again, this value is just a hint. Assimp tries to select the shader whose * most common implementation matches the original rendering results of the * 3D modeler which wrote a particular model as closely as possible. + * */ enum aiShadingMode { /** Flat shading. Shading is done on per-face base, @@ -384,10 +413,11 @@ enum aiShadingMode { * There are multiple methods under this banner, and model files may provide * data for more than one PBR-BRDF method. * Applications should use the set of provided properties to determine which - * of their preferred PBDR methods are available + * of their preferred PBR rendering methods are likely to be available * eg: * - If AI_MATKEY_METALLIC_FACTOR is set, then a Metallic/Roughness is available - * - If AI_MATKEY_COLOR_SPECULAR is set, then a Specular/Glossiness is available + * - If AI_MATKEY_GLOSSINESS_FACTOR is set, then a Specular/Glossiness is available + * Note that some PBR methods allow layering of techniques */ aiShadingMode_PBR_BRDF = 0xb, @@ -942,28 +972,63 @@ extern "C" { // --------------------------------------------------------------------------- // PBR material support +// -------------------- +// Properties defining PBR rendering techniques #define AI_MATKEY_USE_COLOR_MAP "$mat.useColorMap", 0, 0 // Metallic/Roughness Workflow // --------------------------- -// Base color factor. Will be multiplied by final base color texture values if extant +// Base RGBA color factor. Will be multiplied by final base color texture values if extant +// Note: Importers may choose to copy this into AI_MATKEY_COLOR_DIFFUSE for compatibility +// with renderers and formats that do not support Metallic/Roughness PBR #define AI_MATKEY_BASE_COLOR "$clr.base", 0, 0 +#define AI_MATKEY_BASE_COLOR_TEXTURE aiTextureType_BASE_COLOR, 0 #define AI_MATKEY_USE_METALLIC_MAP "$mat.useMetallicMap", 0, 0 // Metallic factor. 0.0 = Full Dielectric, 1.0 = Full Metal #define AI_MATKEY_METALLIC_FACTOR "$mat.metallicFactor", 0, 0 +#define AI_MATKEY_METALLIC_TEXTURE aiTextureType_METALNESS, 0 #define AI_MATKEY_USE_ROUGHNESS_MAP "$mat.useRoughnessMap", 0, 0 // Roughness factor. 0.0 = Perfectly Smooth, 1.0 = Completely Rough #define AI_MATKEY_ROUGHNESS_FACTOR "$mat.roughnessFactor", 0, 0 +#define AI_MATKEY_ROUGHNESS_TEXTURE aiTextureType_DIFFUSE_ROUGHNESS, 0 // Specular/Glossiness Workflow // --------------------------- // Diffuse/Albedo Color. Note: Pure Metals have a diffuse of {0,0,0} // AI_MATKEY_COLOR_DIFFUSE -// Specular Color +// Specular Color. +// Note: Metallic/Roughness may also have a Specular Color // AI_MATKEY_COLOR_SPECULAR +#define AI_MATKEY_SPECULAR_FACTOR "$mat.specularFactor", 0, 0 // Glossiness factor. 0.0 = Completely Rough, 1.0 = Perfectly Smooth #define AI_MATKEY_GLOSSINESS_FACTOR "$mat.glossinessFactor", 0, 0 +// Sheen +// ----- +// Sheen base RGB color. Default {0,0,0} +#define AI_MATKEY_SHEEN_COLOR_FACTOR "$clr.sheen.factor", 0, 0 +// Sheen Roughness Factor. +#define AI_MATKEY_SHEEN_ROUGHNESS_FACTOR "$mat.sheen.roughnessFactor", 0, 0 +#define AI_MATKEY_SHEEN_COLOR_TEXTURE aiTextureType_SHEEN, 0 +#define AI_MATKEY_SHEEN_ROUGHNESS_TEXTURE aiTextureType_SHEEN, 1 + +// Clearcoat +// --------- +#define AI_MATKEY_CLEARCOAT_FACTOR "$clr.clearcoat.factor", 0, 0 +#define AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR "$mat.clearcoat.roughnessFactor", 0, 0 +#define AI_MATKEY_CLEARCOAT_TEXTURE aiTextureType_CLEARCOAT, 0 +#define AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_CLEARCOAT, 1 +#define AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE aiTextureType_CLEARCOAT, 2 + +// Transmission +// ------------ +// https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission +// Base percentage of light transmitted through the surface. 0.0 = Opaque, 1.0 = Fully transparent +#define AI_MATKEY_TRANSMISSION_FACTOR "$mat.transmission.factor", 0, 0 +// Texture defining percentage of light transmitted through the surface. +// Multiplied by AI_MATKEY_TRANSMISSION_FACTOR +#define AI_MATKEY_TRANSMISSION_TEXTURE aiTextureType_TRANSMISSION, 0 + // Emissive // -------- #define AI_MATKEY_USE_EMISSIVE_MAP "$mat.useEmissiveMap", 0, 0 diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index fd904e4fc..c67bcc3b8 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -60,20 +60,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0 //#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0 //#define AI_MATKEY_GLTF_UNLIT "$mat.gltf.unlit", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_SHEEN "$mat.gltf.materialSheen", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR "$mat.gltf.materialSheen.sheenColorFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1 -#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2 -#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT "$mat.gltf.materialClearcoat", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR "$mat.gltf.materialClearcoat.clearcoatFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR "$mat.gltf.materialClearcoat.clearcoatRoughnessFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE aiTextureType_UNKNOWN, 3 -#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 4 -#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE aiTextureType_NORMALS, 1 -#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION "$mat.gltf.materialTransmission", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR "$mat.gltf.materialTransmission.transmissionFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE aiTextureType_UNKNOWN, 5 +//#define AI_MATKEY_GLTF_MATERIAL_SHEEN "$mat.gltf.materialSheen", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR "$mat.gltf.materialSheen.sheenColorFactor", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1 +//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2 +//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT "$mat.gltf.materialClearcoat", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR "$mat.gltf.materialClearcoat.clearcoatFactor", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR "$mat.gltf.materialClearcoat.clearcoatRoughnessFactor", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE aiTextureType_UNKNOWN, 3 +//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 4 +//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE aiTextureType_NORMALS, 1 +//#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION "$mat.gltf.materialTransmission", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR "$mat.gltf.materialTransmission.transmissionFactor", 0, 0 +//#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE aiTextureType_UNKNOWN, 5 #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index e0ac10ad5..766372325 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -152,6 +152,20 @@ TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_pbrSpecularGlossiness) { } #ifndef ASSIMP_BUILD_NO_EXPORT + +TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossiness) { + Assimp::Importer importer; + Assimp::Exporter exporter; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", + aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + // Export + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb")); + + // And re-import + EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true)); +} + TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) { Assimp::Importer importer; Assimp::Exporter exporter; @@ -169,6 +183,7 @@ TEST_F(utglTF2ImportExport, importglTF2EmbeddedAndExportToOBJ) { EXPECT_NE(nullptr, scene); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured_out.obj")); } + #endif // ASSIMP_BUILD_NO_EXPORT TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePointsWithoutIndices) {