Improve FBX material import.

Some properties were being incorrectly interpreted,
and by default it was relying on a legacy system.
pull/1704/head
Tommy 2018-01-11 17:30:17 +01:00
parent c5101b185d
commit fb4a67d4fe
2 changed files with 108 additions and 35 deletions

View File

@ -241,6 +241,10 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiColor3D GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName, aiColor3D GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName,
bool& result ); bool& result );
aiColor3D GetColorPropertyFactored( const PropertyTable& props, const std::string& colorName,
const std::string& factorName, bool& result, bool useTemplate=true );
aiColor3D GetColorProperty( const PropertyTable& props, const std::string& colorName,
bool& result, bool useTemplate=true );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props ); void SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props );
@ -1716,7 +1720,7 @@ unsigned int Converter::ConvertMaterial( const Material& material, const MeshGeo
aiString str; aiString str;
// stip Material:: prefix // strip Material:: prefix
std::string name = material.Name(); std::string name = material.Name();
if ( name.substr( 0, 10 ) == "Material::" ) { if ( name.substr( 0, 10 ) == "Material::" ) {
name = name.substr( 10 ); name = name.substr( 10 );
@ -2077,40 +2081,62 @@ void Converter::SetTextureProperties( aiMaterial* out_mat, const LayeredTextureM
TrySetTextureProperties( out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh ); TrySetTextureProperties( out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh );
} }
aiColor3D Converter::GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName, aiColor3D Converter::GetColorPropertyFactored( const PropertyTable& props, const std::string& colorName,
bool& result ) const std::string& factorName, bool& result, bool useTemplate )
{ {
result = true; result = true;
bool ok; bool ok;
const aiVector3D& Diffuse = PropertyGet<aiVector3D>( props, baseName, ok ); aiVector3D BaseColor = PropertyGet<aiVector3D>( props, colorName, ok, useTemplate );
if ( ok ) { if ( ! ok ) {
return aiColor3D( Diffuse.x, Diffuse.y, Diffuse.z );
}
else {
aiVector3D DiffuseColor = PropertyGet<aiVector3D>( props, baseName + "Color", ok );
if ( ok ) {
float DiffuseFactor = PropertyGet<float>( props, baseName + "Factor", ok );
if ( ok ) {
DiffuseColor *= DiffuseFactor;
}
return aiColor3D( DiffuseColor.x, DiffuseColor.y, DiffuseColor.z );
}
}
result = false; result = false;
return aiColor3D( 0.0f, 0.0f, 0.0f ); return aiColor3D( 0.0f, 0.0f, 0.0f );
}
// if no factor name, return the colour as is
if ( factorName.empty() ) {
return aiColor3D( BaseColor.x, BaseColor.y, BaseColor.z );
}
// otherwise it should be multiplied by the factor, if found.
float factor = PropertyGet<float>( props, factorName, ok, useTemplate );
if ( ok ) {
BaseColor *= factor;
}
return aiColor3D( BaseColor.x, BaseColor.y, BaseColor.z );
} }
aiColor3D Converter::GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName,
bool& result )
{
return GetColorPropertyFactored( props, baseName + "Color", baseName + "Factor", result, true );
}
aiColor3D Converter::GetColorProperty( const PropertyTable& props, const std::string& colorName,
bool& result, bool useTemplate )
{
result = true;
bool ok;
const aiVector3D& ColorVec = PropertyGet<aiVector3D>( props, colorName, ok, useTemplate );
if ( ! ok ) {
result = false;
return aiColor3D( 0.0f, 0.0f, 0.0f );
}
return aiColor3D( ColorVec.x, ColorVec.y, ColorVec.z );
}
void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props ) void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props )
{ {
// set shading properties. There are various, redundant ways in which FBX materials // Set shading properties.
// specify their shading settings (depending on shading models, prop // Modern FBX Files have two separate systems for defining these,
// template etc.). No idea which one is right in a particular context. // with only the more comprehensive one described in the property template.
// Just try to make sense of it - there's no spec to verify this against, // Likely the other values are a legacy system,
// so why should we. // which is still always exported by the official FBX SDK.
//
// Blender's FBX import and export mostly ignore this legacy system,
// and as we only support recent versions of FBX anyway, we can do the same.
bool ok; bool ok;
const aiColor3D& Diffuse = GetColorPropertyFromMaterial( props, "Diffuse", ok ); const aiColor3D& Diffuse = GetColorPropertyFromMaterial( props, "Diffuse", ok );
if ( ok ) { if ( ok ) {
out_mat->AddProperty( &Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); out_mat->AddProperty( &Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
@ -2126,29 +2152,64 @@ void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyT
out_mat->AddProperty( &Ambient, 1, AI_MATKEY_COLOR_AMBIENT ); out_mat->AddProperty( &Ambient, 1, AI_MATKEY_COLOR_AMBIENT );
} }
const aiColor3D& Specular = GetColorPropertyFromMaterial( props, "Specular", ok ); // we store specular factor as SHININESS_STRENGTH, so just get the color
const aiColor3D& Specular = GetColorProperty( props, "SpecularColor", ok, true );
if ( ok ) { if ( ok ) {
out_mat->AddProperty( &Specular, 1, AI_MATKEY_COLOR_SPECULAR ); out_mat->AddProperty( &Specular, 1, AI_MATKEY_COLOR_SPECULAR );
} }
// and also try to get SHININESS_STRENGTH
const float SpecularFactor = PropertyGet<float>( props, "SpecularFactor", ok, true );
if ( ok ) {
out_mat->AddProperty( &SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH );
}
// and the specular exponent
const float ShininessExponent = PropertyGet<float>( props, "ShininessExponent", ok );
if ( ok ) {
out_mat->AddProperty( &ShininessExponent, 1, AI_MATKEY_SHININESS );
}
// TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
float CalculatedOpacity = 1.0;
if ( ok ) {
out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
// as calculated by FBX SDK 2017:
CalculatedOpacity = 1.0 - ((Transparent.r + Transparent.g + Transparent.b) / 3.0);
}
// use of TransparencyFactor is inconsistent.
// Maya always stores it as 1.0,
// so we can't use it to set AI_MATKEY_OPACITY.
// Blender is more sensible and stores it as the alpha value.
// However both the FBX SDK and Blender always write an additional
// legacy "Opacity" field, so we can try to use that.
//
// If we can't find it,
// we can fall back to the value which the FBX SDK calculates
// from transparency colour (RGB) and factor (F) as
// 1.0 - F*((R+G+B)/3).
//
// There's no consistent way to interpret this opacity value,
// so it's up to clients to do the correct thing.
const float Opacity = PropertyGet<float>( props, "Opacity", ok ); const float Opacity = PropertyGet<float>( props, "Opacity", ok );
if ( ok ) { if ( ok ) {
out_mat->AddProperty( &Opacity, 1, AI_MATKEY_OPACITY ); out_mat->AddProperty( &Opacity, 1, AI_MATKEY_OPACITY );
} }
else if ( CalculatedOpacity != 1.0 ) {
const float Reflectivity = PropertyGet<float>( props, "Reflectivity", ok ); out_mat->AddProperty( &CalculatedOpacity, 1, AI_MATKEY_OPACITY );
if ( ok ) {
out_mat->AddProperty( &Reflectivity, 1, AI_MATKEY_REFLECTIVITY );
} }
const float Shininess = PropertyGet<float>( props, "Shininess", ok ); // reflection color and factor are stored separately
const aiColor3D& Reflection = GetColorProperty( props, "ReflectionColor", ok, true );
if ( ok ) { if ( ok ) {
out_mat->AddProperty( &Shininess, 1, AI_MATKEY_SHININESS_STRENGTH ); out_mat->AddProperty( &Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE );
} }
const float ShininessExponent = PropertyGet<float>( props, "ShininessExponent", ok ); float ReflectionFactor = PropertyGet<float>( props, "ReflectionFactor", ok, true );
if ( ok ) { if ( ok ) {
out_mat->AddProperty( &ShininessExponent, 1, AI_MATKEY_SHININESS ); out_mat->AddProperty( &ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY );
} }
const float BumpFactor = PropertyGet<float>(props, "BumpFactor", ok); const float BumpFactor = PropertyGet<float>(props, "BumpFactor", ok);

View File

@ -148,12 +148,24 @@ T PropertyGet(const PropertyTable& in, const std::string& name, const T& default
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
inline inline
T PropertyGet(const PropertyTable& in, const std::string& name, bool& result) { T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
const Property* const prop = in.Get(name); const Property* prop = in.Get(name);
if( nullptr == prop) { if( nullptr == prop) {
if ( ! useTemplate ) {
result = false; result = false;
return T(); return T();
} }
const PropertyTable* templ = in.TemplateProps();
if ( nullptr == templ ) {
result = false;
return T();
}
prop = templ->Get(name);
if ( nullptr == prop ) {
result = false;
return T();
}
}
// strong typing, no need to be lenient // strong typing, no need to be lenient
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >(); const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();