diff --git a/Engine/source/ts/assimp/assimpAppMaterial.cpp b/Engine/source/ts/assimp/assimpAppMaterial.cpp index 6fdc913e5..55ba12506 100644 --- a/Engine/source/ts/assimp/assimpAppMaterial.cpp +++ b/Engine/source/ts/assimp/assimpAppMaterial.cpp @@ -19,6 +19,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- +//#define TORQUE_PBR_MATERIALS #include "platform/platform.h" #include "ts/loader/appSequence.h" @@ -38,7 +39,7 @@ String AppMaterial::cleanString(const String& str) String cleanStr(str); // Replace invalid characters with underscores - const String badChars(" -,.+=*/"); + const String badChars(" -,.+=*/[]"); for (String::SizeType i = 0; i < badChars.length(); i++) cleanStr.replace(badChars[i], '_'); @@ -52,50 +53,27 @@ String AppMaterial::cleanString(const String& str) AssimpAppMaterial::AssimpAppMaterial(const char* matName) { name = matName; - diffuseColor = LinearColorF::ONE; - specularColor = LinearColorF::ONE; - specularPower = 0.8f; - doubleSided = false; // Set some defaults flags |= TSMaterialList::S_Wrap; flags |= TSMaterialList::T_Wrap; } -AssimpAppMaterial::AssimpAppMaterial(const struct aiMaterial* mtl) +AssimpAppMaterial::AssimpAppMaterial(aiMaterial* mtl) : + mAIMat(mtl) { aiString matName; mtl->Get(AI_MATKEY_NAME, matName); name = matName.C_Str(); - if ( name.isEmpty() ) - name = "defaultMaterial"; - Con::printf("[ASSIMP] Loaded Material: %s", matName.C_Str()); - - // Opacity - F32 opacity = 0.0f; - mtl->Get(AI_MATKEY_OPACITY, opacity); - - // Diffuse color - aiColor3D diff_color (0.f, 0.f, 0.f); - mtl->Get(AI_MATKEY_COLOR_DIFFUSE, diff_color); - diffuseColor = LinearColorF(diff_color.r, diff_color.g, diff_color.b, opacity); - - // Spec Color color - aiColor3D spec_color (0.f, 0.f, 0.f); - mtl->Get(AI_MATKEY_COLOR_DIFFUSE, spec_color ); - specularColor = LinearColorF(spec_color.r, spec_color.g, spec_color.b, 1.0f); - - // Specular Power - mtl->Get(AI_MATKEY_SHININESS_STRENGTH, specularPower); - - // Double-Sided - S32 dbl_sided = 0; - mtl->Get(AI_MATKEY_TWOSIDED, dbl_sided); - doubleSided = (dbl_sided != 0); - - // Set some defaults - flags |= TSMaterialList::S_Wrap; - flags |= TSMaterialList::T_Wrap; + if (name.isEmpty()) + { + name = cleanString(TSShapeLoader::getShapePath().getFileName());; + name += "_defMat"; + } + Con::printf("[ASSIMP] Loading Material: %s", name.c_str()); +#ifdef TORQUE_DEBUG + enumerateMaterialProperties(mtl); +#endif } Material* AssimpAppMaterial::createMaterial(const Torque::Path& path) const @@ -105,34 +83,264 @@ Material* AssimpAppMaterial::createMaterial(const Torque::Path& path) const String cleanFile = cleanString(TSShapeLoader::getShapePath().getFileName()); String cleanName = cleanString(getName()); - // Prefix the material name with the filename (if not done already by TSShapeConstructor prefix) - //if (!cleanName.startsWith(cleanFile)) - // cleanName = cleanFile + "_" + cleanName; - - // Determine the blend operation for this material - Material::BlendOp blendOp = (flags & TSMaterialList::Translucent) ? Material::LerpAlpha : Material::None; - if (flags & TSMaterialList::Additive) - blendOp = Material::Add; - else if (flags & TSMaterialList::Subtractive) - blendOp = Material::Sub; - // Create the Material definition const String oldScriptFile = Con::getVariable("$Con::File"); Con::setVariable("$Con::File", path.getFullPath()); // modify current script path so texture lookups are correct - Material *newMat = MATMGR->allocateAndRegister( cleanName, getName() ); + Material *newMat = MATMGR->allocateAndRegister(cleanName, getName()); Con::setVariable("$Con::File", oldScriptFile); // restore script path - newMat->mDiffuseMapFilename[0] = ""; - newMat->mNormalMapFilename[0] = ""; - newMat->mSpecularMapFilename[0] = ""; - - newMat->mDiffuse[0] = diffuseColor; - //newMat->mSpecular[0] = specularColor; - //newMat->mSpecularPower[0] = specularPower; - - newMat->mDoubleSided = doubleSided; - newMat->mTranslucent = (bool)(flags & TSMaterialList::Translucent); - newMat->mTranslucentBlendOp = blendOp; + initMaterial(path, newMat); return newMat; -} \ No newline at end of file +} + +void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) const +{ + String cleanFile = cleanString(TSShapeLoader::getShapePath().getFileName()); + String cleanName = cleanString(getName()); + + // Determine the blend mode and transparency for this material + Material::BlendOp blendOp = Material::None; + bool translucent = false; + float opacity = 1.0f; + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_OPACITY, opacity)) + { + if (opacity != 1.0f) + { + translucent = true; + int blendInt; + blendOp = Material::LerpAlpha; + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_BLEND_FUNC, blendInt)) + { + if (blendInt == aiBlendMode_Additive) + blendOp = Material::Add; + } + } + } + else + { // No opacity key, see if it's defined as a gltf property + aiString opacityMode; + if (AI_SUCCESS == mAIMat->Get("$mat.gltf.alphaMode", 0, 0, opacityMode)) + { + if (dStrcmp("MASK", opacityMode.C_Str()) == 0) + { + translucent = true; + blendOp = Material::LerpAlpha; + + float cutoff; + if (AI_SUCCESS == mAIMat->Get("$mat.gltf.alphaCutoff", 0, 0, cutoff)) + { + mat->mAlphaRef = (U32)(cutoff * 255); // alpha ref 0-255 + mat->mAlphaTest = true; + } + } + else if (dStrcmp("OPAQUE", opacityMode.C_Str()) != 0) + { + translucent = true; + blendOp = Material::LerpAlpha; + } + } + } + mat->mTranslucent = translucent; + mat->mTranslucentBlendOp = blendOp; + + // Assign color values. + LinearColorF diffuseColor(1.0f, 1.0f, 1.0f, 1.0f); + aiColor3D read_color(1.f, 1.f, 1.f); + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_COLOR_DIFFUSE, read_color)) + diffuseColor.set(read_color.r, read_color.g, read_color.b, opacity); + mat->mDiffuse[0] = diffuseColor; + + aiString texName; + String torquePath; + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), texName)) + { + torquePath = texName.C_Str(); + if (!torquePath.isEmpty()) + mat->mDiffuseMapFilename[0] = cleanTextureName(torquePath, cleanFile); + } + + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), texName)) + { + torquePath = texName.C_Str(); + if (!torquePath.isEmpty()) + mat->mNormalMapFilename[0] = cleanTextureName(torquePath, cleanFile); + } + +#ifdef TORQUE_PBR_MATERIALS + float floatVal; + if (AI_SUCCESS == mAIMat->Get("$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0, floatVal)) + { // The shape has pbr material definitions + String aoName, rmName; // occlusion and roughness/metalness maps + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0), texName)) + aoName = texName.C_Str(); + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_UNKNOWN, 0), texName)) + rmName = texName.C_Str(); + + //if (aoName.isNotEmpty() && (aoName == rmName)) + // mat->mOrmMapFilename[0] = cleanTextureName(aoName, cleanFile); // It's an ORM map + //else if (aoName.isNotEmpty() || rmName.isNotEmpty()) + if (aoName.isNotEmpty() || rmName.isNotEmpty()) + { // If we have either map, fill all three slots + if (rmName.isNotEmpty()) + { + mat->mRoughMapFilename[0] = cleanTextureName(rmName, cleanFile); // Roughness + mat->mSmoothnessChan[0] = 1.0f; + mat->mInvertSmoothness = (floatVal == 1.0f); + mat->mMetalMapFilename[0] = cleanTextureName(rmName, cleanFile); // Metallic + mat->mMetalChan[0] = 2.0f; + } + if (aoName.isNotEmpty()) + { + mat->mAOMapFilename[0] = cleanTextureName(aoName, cleanFile); // occlusion + mat->mAOChan[0] = 0.0f; + } + else + { + mat->mAOMapFilename[0] = cleanTextureName(rmName, cleanFile); // occlusion + mat->mAOChan[0] = 0.0f; + } + } + } +#else + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, 0), texName)) + { + torquePath = texName.C_Str(); + if (!torquePath.isEmpty()) + mat->mSpecularMapFilename[0] = cleanTextureName(torquePath, cleanFile); + } + + LinearColorF specularColor(1.0f, 1.0f, 1.0f, 1.0f); + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_COLOR_SPECULAR, read_color)) + specularColor.set(read_color.r, read_color.g, read_color.b, opacity); + mat->mSpecular[0] = specularColor; + + // Specular Power + F32 specularPower = 1.0f; + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_SHININESS_STRENGTH, specularPower)) + mat->mSpecularPower[0] = specularPower; + + // Specular + F32 specularStrength = 0.0f; + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_SHININESS, specularStrength)) + mat->mSpecularStrength[0] = specularStrength; +#endif + + // Double-Sided + bool doubleSided = false; + S32 dbl_sided = 0; + if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TWOSIDED, dbl_sided)) + doubleSided = (dbl_sided != 0); + mat->mDoubleSided = doubleSided; +} + +String AssimpAppMaterial::cleanTextureName(String& texName, String& shapeName) +{ + String cleanStr; + + if (texName[0] == '*') + { + cleanStr = shapeName; + cleanStr += "_cachedTex"; + cleanStr += texName.substr(1); + } + else + { + cleanStr = texName; + cleanStr.replace('\\', '/'); + } + + return cleanStr; +} + +#ifdef TORQUE_DEBUG +void AssimpAppMaterial::enumerateMaterialProperties(aiMaterial* mtl) +{ + for (U32 i = 0; i < mtl->mNumProperties; ++i) + { + aiMaterialProperty* matProp = mtl->mProperties[i]; + String outText; + if (matProp) + { + outText = String::ToString(" Key: %s, Index: %d, Semantic: ", matProp->mKey.C_Str(), matProp->mIndex); + switch (matProp->mSemantic) + { + case aiTextureType_NONE: + outText += "aiTextureType_NONE"; + break; + case aiTextureType_DIFFUSE: + outText += "aiTextureType_DIFFUSE"; + break; + case aiTextureType_SPECULAR: + outText += "aiTextureType_SPECULAR"; + break; + case aiTextureType_AMBIENT: + outText += "aiTextureType_AMBIENT"; + break; + case aiTextureType_EMISSIVE: + outText += "aiTextureType_EMISSIVE"; + break; + case aiTextureType_HEIGHT: + outText += "aiTextureType_HEIGHT"; + break; + case aiTextureType_NORMALS: + outText += "aiTextureType_NORMALS"; + break; + case aiTextureType_SHININESS: + outText += "aiTextureType_SHININESS"; + break; + case aiTextureType_OPACITY: + outText += "aiTextureType_OPACITY"; + break; + case aiTextureType_DISPLACEMENT: + outText += "aiTextureType_DISPLACEMENT"; + break; + case aiTextureType_LIGHTMAP: + outText += "aiTextureType_LIGHTMAP"; + break; + case aiTextureType_REFLECTION: + outText += "aiTextureType_REFLECTION"; + break; + default: + outText += "aiTextureType_UNKNOWN"; + break; + } + + aiString stringProp; + F32* floatProp; + double* doubleProp; + S32* intProp; + + switch (matProp->mType) + { + case aiPTI_Float: + floatProp = (F32*)matProp->mData; + for (U32 j = 0; j < matProp->mDataLength / sizeof(F32); ++j) + outText += String::ToString(", %0.4f", floatProp[j]); + break; + case aiPTI_Double: + doubleProp = (double*)matProp->mData; + for (U32 j = 0; j < matProp->mDataLength / sizeof(double); ++j) + outText += String::ToString(", %0.4lf", doubleProp[j]); + break; + case aiPTI_String: + aiGetMaterialString(mtl, matProp->mKey.C_Str(), matProp->mSemantic, matProp->mIndex, &stringProp); + outText += String::ToString(", %s", stringProp.C_Str()); + break; + case aiPTI_Integer: + intProp = (S32*)matProp->mData; + for (U32 j = 0; j < matProp->mDataLength / sizeof(S32); ++j) + outText += String::ToString(", %d", intProp[j]); + break; + case aiPTI_Buffer: + outText += ", aiPTI_Buffer format data"; + break; + default: + outText += ", Unknown data type"; + } + + Con::printf("%s", outText.c_str()); + } + } +} +#endif \ No newline at end of file diff --git a/Engine/source/ts/assimp/assimpAppMaterial.h b/Engine/source/ts/assimp/assimpAppMaterial.h index 4f24873a6..64aaedf28 100644 --- a/Engine/source/ts/assimp/assimpAppMaterial.h +++ b/Engine/source/ts/assimp/assimpAppMaterial.h @@ -26,6 +26,7 @@ #ifndef _APPMATERIAL_H_ #include "ts/loader/appMaterial.h" #endif +#include class Material; @@ -34,18 +35,22 @@ class AssimpAppMaterial : public AppMaterial typedef AppMaterial Parent; String name; - LinearColorF diffuseColor; - LinearColorF specularColor; - F32 specularPower; - bool doubleSided; + aiMaterial* mAIMat; + +#ifdef TORQUE_DEBUG + void enumerateMaterialProperties(aiMaterial* mtl); +#endif + static String cleanTextureName(String& texName, String& shapeName); + public: AssimpAppMaterial(const char* matName); - AssimpAppMaterial(const struct aiMaterial* mtl); + AssimpAppMaterial(aiMaterial* mtl); ~AssimpAppMaterial() { } String getName() const { return name; } Material* createMaterial(const Torque::Path& path) const; + void initMaterial(const Torque::Path& path, Material* mat) const; }; #endif // _ASSIMP_APPMATERIAL_H_