Material initialization.

Fixes material initialization for texture and transparency assignments.
Lists all available material properties to console in debug builds.
Adds TORQUE_PBR_MATERIALS define for testing with PBR branches.
This commit is contained in:
OTHGMars 2019-04-22 00:08:15 -04:00
parent c1726dc1d1
commit 8d6a98b0be
2 changed files with 277 additions and 64 deletions

View file

@ -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;
}
}
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

View file

@ -26,6 +26,7 @@
#ifndef _APPMATERIAL_H_
#include "ts/loader/appMaterial.h"
#endif
#include <assimp/scene.h>
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_