|
@@ -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] = "";
|
|
|
+ initMaterial(path, newMat);
|
|
|
|
|
|
- newMat->mDiffuse[0] = diffuseColor;
|
|
|
- //newMat->mSpecular[0] = specularColor;
|
|
|
- //newMat->mSpecularPower[0] = specularPower;
|
|
|
+ return newMat;
|
|
|
+}
|
|
|
|
|
|
- newMat->mDoubleSided = doubleSided;
|
|
|
- newMat->mTranslucent = (bool)(flags & TSMaterialList::Translucent);
|
|
|
- newMat->mTranslucentBlendOp = blendOp;
|
|
|
+void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) const
|
|
|
+{
|
|
|
+ String cleanFile = cleanString(TSShapeLoader::getShapePath().getFileName());
|
|
|
+ String cleanName = cleanString(getName());
|
|
|
|
|
|
- return newMat;
|
|
|
-}
|
|
|
+ // 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
|