Files
2025-05-18 13:04:45 +08:00

1010 lines
29 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DatasmithMaxWriter.h"
#include "DatasmithMaxClassIDs.h"
#include "MaxMaterialsToUEPbr/DatasmithMaxMaterialsToUEPbr.h"
#include "DatasmithExportOptions.h"
#include "DatasmithSceneFactory.h"
#include "DatasmithMaxSceneHelper.h"
#include "DatasmithMaxLogger.h"
#include "Misc/Paths.h"
#include "Windows/AllowWindowsPlatformTypes.h"
MAX_INCLUDES_START
#include "bitmap.h"
#include "xref/iXrefMaterial.h"
MAX_INCLUDES_END
#include "Windows/HideWindowsPlatformTypes.h"
FString FDatasmithMaxMatWriter::TextureSuffix = TEXT("_Tex");
FString FDatasmithMaxMatWriter::TextureBakeFormat = TEXT(".tga");
bool FDatasmithMaxMatHelper::HasNonBakeableSubmap(Texmap* InTexmap)
{
if (InTexmap == NULL)
{
return false;
}
// Skip any view dependent TexMap
// Having a THIRDPARTYMULTITEXCLASS as an input for a color correction node crashes when calling RenderBitmap on the color correction texmap so skip it.
if (InTexmap->ClassID() == VRAYDIRTCLASS || InTexmap->ClassID() == CORONAAOCLASS || InTexmap->ClassID() == FALLOFFCLASS || InTexmap->ClassID() == THIRDPARTYMULTITEXCLASS)
{
return true;
}
if (InTexmap->ClassID() == RBITMAPCLASS)
{
StdUVGen* UV = ((BitmapTex*)InTexmap)->GetUVGen();
if (UV == NULL)
{
return true;
}
float U = UV->GetUScl(GetCOREInterface()->GetTime());
float V = UV->GetVScl(GetCOREInterface()->GetTime());
float IntegralPart;
if (U > 10.f || V > 10.f || FMath::IsNearlyEqual(FMath::Modf(U, &IntegralPart), 0.f) == false || FMath::IsNearlyEqual(FMath::Modf(V, &IntegralPart), 0.f) == false)
{
return true;
}
}
for (int SubMap = 0; SubMap < InTexmap->NumSubTexmaps(); SubMap++)
{
if (InTexmap->SubTexmapOn(SubMap) != 0 && HasNonBakeableSubmap(InTexmap->GetSubTexmap(SubMap)) == true)
{
return true;
}
}
return false;
}
EDSBitmapType FDatasmithMaxMatHelper::GetTextureClass(Texmap* InTexMap)
{
EDSBitmapType Type = EDSBitmapType::NotSupported;
if (InTexMap != nullptr)
{
MSTR ClassName;
InTexMap->GetClassName(ClassName);
if (InTexMap->ClassID() == RBITMAPCLASS)
{
Type = EDSBitmapType::RegularBitmap;
}
//Somehow, there are multiple autodesk map classes using the same ClassID, we only support Autodesk Bitmap.
else if (InTexMap->ClassID() == AUTODESKBITMAPCLASS && FCString::Stricmp(ClassName, TEXT("Autodesk Bitmap")) == 0)
{
Type = EDSBitmapType::AutodeskBitmap;
}
else if (InTexMap->ClassID() == THEABITMAPCLASS)
{
Type = EDSBitmapType::TheaBitmap;
}
else if (InTexMap->ClassID() == REGULARNORMALCLASS)
{
Type = EDSBitmapType::NormalMap;
}
else if (InTexMap->ClassID() == VRAYNORMALCLASS)
{
Type = EDSBitmapType::NormalMap;
}
else if (InTexMap->ClassID() == CORONANORMALCLASS)
{
Type = EDSBitmapType::NormalMap;
}
else if (InTexMap->ClassID() == COLORCORRECTCLASS)
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexMap) == false)
{
Type = EDSBitmapType::BakeableMap;
}
else
{
Type = EDSBitmapType::ColorCorrector;
}
}
else if (InTexMap->ClassID() == FALLOFFCLASS)
{
Type = EDSBitmapType::FallOff;
}
else if (InTexMap->ClassID() == MIXCLASS)
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexMap) == false)
{
Type = EDSBitmapType::BakeableMap;
}
else
{
Type = EDSBitmapType::Mix;
}
}
else if (InTexMap->ClassID() == NOISECLASS)
{
Type = EDSBitmapType::Noise;
}
else if (InTexMap->ClassID() == GRADIENTCLASS)
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexMap) == false)
{
Type = EDSBitmapType::BakeableMap;
}
else
{
Type = EDSBitmapType::Gradient;
}
}
else if (InTexMap->ClassID() == GRADIENTRAMPCLASS)
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexMap) == false)
{
Type = EDSBitmapType::BakeableMap;
}
}
else if (InTexMap->ClassID() == CHECKERCLASS)
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexMap) == false)
{
Type = EDSBitmapType::BakeableMap;
}
else
{
Type = EDSBitmapType::Checker;
}
}
else if (InTexMap->ClassID() == CELLULARCLASS)
{
Type = EDSBitmapType::Cellular;
}
else if (InTexMap->ClassID() == VRAYDIRTCLASS)
{
Type = EDSBitmapType::VRayDirt;
}
else if (InTexMap->ClassID() == COMPOSITETEXCLASS)
{
Type = EDSBitmapType::CompositeTex;
}
else if (InTexMap->ClassID() == CORONABITMAPCLASS)
{
Type = EDSBitmapType::CoronaBitmap;
}
else if (InTexMap->ClassID() == VRAYHDRICLASS)
{
Type = EDSBitmapType::VRayHRDI;
}
else if (InTexMap->ClassID() == CORONACOLORCLASS)
{
Type = EDSBitmapType::CoronaColor;
}
else if (InTexMap->ClassID() == CORONAMIXCLASS)
{
Type = EDSBitmapType::CoronaMix;
}
else if (InTexMap->ClassID() == CORONAMULTITEXCLASS)
{
Type = EDSBitmapType::CoronaMultiTex;
}
else if (InTexMap->ClassID() == CORONAAOCLASS)
{
Type = EDSBitmapType::CoronaAO;
}
else if (InTexMap->ClassID() == VRAYCOLORCLASS)
{
Type = EDSBitmapType::VRayColor;
}
else if (InTexMap->ClassID() == THIRDPARTYMULTITEXCLASS)
{
Type = EDSBitmapType::ThirdPartyMultiTex;
}
else if (InTexMap->ClassID() == CORONAPHYSICALSKYCLASS)
{
Type = EDSBitmapType::PhysicalSky;
}
else if (InTexMap->ClassID() == VRAYPHYSICALSKYCLASS)
{
Type = EDSBitmapType::PhysicalSky;
}
else if (InTexMap->ClassID() == MRPHYSICALSKYCLASS)
{
Type = EDSBitmapType::PhysicalSky;
}
else if (InTexMap->ClassID() == MRPHYSICALSKYBCLASS)
{
Type = EDSBitmapType::PhysicalSky;
}
else if (InTexMap->ClassID() == TILESMAPCLASS)
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexMap) == false)
{
Type = EDSBitmapType::BakeableMap;
}
}
}
return Type;
}
EDSMaterialType FDatasmithMaxMatHelper::GetMaterialClass(Mtl* Material)
{
EDSMaterialType Type = EDSMaterialType::NotSupported;
if (Material != nullptr)
{
if (Material->ClassID() == THEAMATOLDCLASS)
{
Type = EDSMaterialType::TheaMaterialDeprecated;
}
else if (Material->ClassID() == THEARANDOMCLASS)
{
Type = EDSMaterialType::TheaRandom;
}
else if (Material->ClassID() == THEAMATERIALCLASS)
{
Type = EDSMaterialType::TheaMaterial;
}
else if (Material->ClassID() == THEABASICCLASS)
{
Type = EDSMaterialType::TheaBasic;
}
else if (Material->ClassID() == THEAGLOSSYCLASS)
{
Type = EDSMaterialType::TheaGlossy;
}
else if (Material->ClassID() == THEASSSCLASS)
{
Type = EDSMaterialType::TheaSSS;
}
else if (Material->ClassID() == THEAFILMCLASS)
{
Type = EDSMaterialType::TheaFilm;
}
else if (Material->ClassID() == THEACOATINGCLASS)
{
Type = EDSMaterialType::TheaCoating;
}
else if (Material->ClassID() == MULTIMAT_CLASS_ID)
{
Type = EDSMaterialType::MultiMat;
}
else if (Material->ClassID() == STANDARDMATCLASS)
{
Type = EDSMaterialType::StandardMat;
}
else if (Material->ClassID() == SHELLCLASS)
{
Type = EDSMaterialType::ShellMat;
}
else if (Material->ClassID() == BLENDMATCLASS)
{
Type = EDSMaterialType::BlendMat;
}
else if (Material->ClassID() == XREFMATCLASS)
{
Type = EDSMaterialType::XRefMat;
}
else if (Material->ClassID() == ARCHDESIGNMATCLASS)
{
Type = EDSMaterialType::ArchDesignMat;
}
else if (Material->ClassID() == VRAYMATCLASS)
{
Type = EDSMaterialType::VRayMat;
}
else if (Material->ClassID() == VRAYBLENDMATCLASS)
{
Type = EDSMaterialType::VRayBlendMat;
}
else if (Material->ClassID() == VRAYLIGHTMATCLASS)
{
Type = EDSMaterialType::VRayLightMat;
}
else if (Material->ClassID() == VRAYFASTSSSCLASS)
{
Type = EDSMaterialType::VRayFastSSSMat;
}
else if (Material->ClassID() == CORONAMATCLASS)
{
Type = EDSMaterialType::CoronaMat;
}
else if (Material->ClassID() == CORONALAYERMATCLASS)
{
Type = EDSMaterialType::CoronaLayerMat;
}
else if (Material->ClassID() == CORONALIGHTMATCLASS)
{
Type = EDSMaterialType::CoronaLightMat;
}
else if (Material->ClassID() == PHYSICALMATCLASS)
{
Type = EDSMaterialType::PhysicalMat;
}
}
return Type;
}
Mtl* FDatasmithMaxMatHelper::GetRenderedXRefMaterial(Mtl* Material)
{
const TimeValue CurrentTime = GetCOREInterface()->GetTime();
const int NumParamBlocks = Material->NumParamBlocks();
bool bSourceMaterialOverridden = false;
Mtl* MaterialOverride = nullptr;
for (int j = 0; j < NumParamBlocks; j++)
{
IParamBlock2* ParamBlock2 = Material->GetParamBlockByID((short)j);
ParamBlockDesc2* ParamBlockDesc = ParamBlock2->GetDesc();
for (int i = 0; i < ParamBlockDesc->count; i++)
{
const ParamDef& ParamDefinition = ParamBlockDesc->paramdefs[i];
// Diffuse
if (FCString::Stricmp(ParamDefinition.int_name, TEXT("enableOverride")) == 0)
{
bSourceMaterialOverridden = ParamBlock2->GetInt(ParamDefinition.ID, CurrentTime) != 0;
}
else if (FCString::Stricmp(ParamDefinition.int_name, TEXT("overrideMaterial")) == 0)
{
MaterialOverride = ParamBlock2->GetMtl(ParamDefinition.ID, CurrentTime);
}
}
ParamBlock2->ReleaseDesc();
}
Mtl* RenderedMaterial = nullptr;
if (bSourceMaterialOverridden)
{
RenderedMaterial = MaterialOverride;
}
else
{
IXRefMaterial* XRefMaterial = static_cast<IXRefMaterial*>(Material);
RenderedMaterial = XRefMaterial->GetSourceMaterial(true);
}
return RenderedMaterial;
}
FLinearColor FDatasmithMaxMatHelper::MaxColorToFLinearColor(BMM_Color_fl Color, float Multiplier /*= 1.0f*/)
{
Color.r = FMath::Pow(Color.r, 1.0f / FDatasmithExportOptions::ColorGamma);
Color.g = FMath::Pow(Color.g, 1.0f / FDatasmithExportOptions::ColorGamma);
Color.b = FMath::Pow(Color.b, 1.0f / FDatasmithExportOptions::ColorGamma);
float Red = Color.r * Multiplier;
float Green = Color.g * Multiplier;
float Blue = Color.b * Multiplier;
return FLinearColor(Red, Green, Blue);
}
FLinearColor FDatasmithMaxMatHelper::MaxLinearColorToFLinearColor(BMM_Color_fl Color, float Multiplier /*= 1.0f*/)
{
return FLinearColor( Color.r, Color.g, Color.b );
}
float FDatasmithMaxMatHelper::GetBitmapGamma(BitmapTex* InBitmapTex)
{
if (InBitmapTex)
{
if (Bitmap* ActualBitmap = InBitmapTex->GetBitmap(GetCOREInterface()->GetTime()))
{
return ActualBitmap->Gamma();
}
}
return 2.2f;
}
float FDatasmithMaxMatHelper::GetBitmapGamma(BitmapInfo* InBitmap)
{
if (InBitmap)
{
return InBitmap->Gamma();
}
return 2.2f;
}
bool FDatasmithMaxMatHelper::IsSRGB(BitmapTex& InBitmapTex)
{
if (Bitmap* ActualBitmap = InBitmapTex.GetBitmap(GetCOREInterface()->GetTime()))
{
return IsSRGB(*ActualBitmap);
}
return true;
}
bool FDatasmithMaxMatHelper::IsSRGB(Bitmap& InBitmap)
{
if (InBitmap.IsHighDynamicRange() )
{
return false;
}
#ifdef MAX_RELEASE_R19
BitmapInfo BitmapInformation = InBitmap.GetBitmapInfo();
switch ( BitmapInformation.Type() )
{
// UE considers that all bit depth >= 16 are linear
case BMM_GRAY_16:
case BMM_FLOAT_RGBA_32:
case BMM_FLOAT_GRAY_32:
case BMM_REALPIX_32:
case BMM_TRUE_48:
case BMM_TRUE_64:
return false; // Linear
break;
default:
return true; // sRGB
break;
}
#endif // MAX_RELEASE_R19
return true;
}
bool FDatasmithMaxMatExport::UseFirstSubMapOnly(EDSMaterialType MaterialType, Mtl* Material)
{
switch (MaterialType)
{
case EDSMaterialType::TheaMaterial:
case EDSMaterialType::MultiMat:
case EDSMaterialType::StandardMat:
case EDSMaterialType::ArchDesignMat:
case EDSMaterialType::VRayMat:
case EDSMaterialType::VRayLightMat:
case EDSMaterialType::CoronaMat:
case EDSMaterialType::CoronaLightMat:
case EDSMaterialType::BlendMat:
case EDSMaterialType::XRefMat:
case EDSMaterialType::VRayBlendMat:
case EDSMaterialType::CoronaLayerMat:
return false;
default:
if (Material->NumSubMtls() < 1)
{
return false;
}
else
{
return true;
}
}
}
TSharedPtr< IDatasmithBaseMaterialElement > FDatasmithMaxMatExport::ExportUniqueMaterial(TSharedRef< IDatasmithScene > DatasmithScene, Mtl* Material, const TCHAR* AssetsPath)
{
if (!Material)
{
return {};
}
FString MaterialName(FDatasmithMaxMaterialsToUEPbrManager::GetDatasmithMaterialName(Material));
for (int i = 0; i < DatasmithScene->GetMaterialsCount(); i++)
{
if (FString(DatasmithScene->GetMaterial(i)->GetName()) == MaterialName)
{
return DatasmithScene->GetMaterial(i);
}
}
if ( FDatasmithMaxMaterialsToUEPbr* MaterialConverter = FDatasmithMaxMaterialsToUEPbrManager::GetMaterialConverter( Material ) )
{
TSharedPtr< IDatasmithBaseMaterialElement > UEPbrMaterial;
MaterialConverter->Convert( DatasmithScene, UEPbrMaterial, Material, AssetsPath );
FDatasmithMaxMaterialsToUEPbrManager::AddDatasmithMaterial(DatasmithScene, Material, UEPbrMaterial);
return UEPbrMaterial;
}
else
{
TSharedRef< IDatasmithMaterialElement > MaterialElement = FDatasmithSceneFactory::CreateMaterial( *MaterialName );
FDatasmithMaxMaterialsToUEPbrManager::AddDatasmithMaterial(DatasmithScene, Material, MaterialElement);
WriteXMLMaterial( DatasmithScene, MaterialElement, Material );
return MaterialElement;
}
}
void FDatasmithMaxMatExport::WriteXMLMaterial(TSharedRef< IDatasmithScene > DatasmithScene, TSharedPtr< IDatasmithMaterialElement > MaterialElement, Mtl* Material)
{
if (Material == nullptr)
{
return;
}
EDSMaterialType MaterialType = FDatasmithMaxMatHelper::GetMaterialClass(Material);
switch (FDatasmithMaxMatHelper::GetMaterialClass(Material))
{
case EDSMaterialType::StandardMat:
FDatasmithMaxMatWriter::ExportStandardMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::TheaMaterial:
FDatasmithMaxMatWriter::ExportTheaMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::VRayMat:
FDatasmithMaxMatWriter::ExportVRayMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::VRayLightMat:
FDatasmithMaxMatWriter::ExportVRayLightMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::ArchDesignMat:
FDatasmithMaxMatWriter::ExportArchDesignMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::CoronaMat:
FDatasmithMaxMatWriter::ExportCoronaMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::CoronaLightMat:
FDatasmithMaxMatWriter::ExportCoronaLightMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::BlendMat:
FDatasmithMaxMatWriter::ExportBlendMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::XRefMat:
FDatasmithMaxMatExport::WriteXMLMaterial(DatasmithScene, MaterialElement, FDatasmithMaxMatHelper::GetRenderedXRefMaterial(Material));
break;
case EDSMaterialType::VRayBlendMat:
FDatasmithMaxMatWriter::ExportVrayBlendMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::CoronaLayerMat:
FDatasmithMaxMatWriter::ExportCoronaBlendMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::PhysicalMat:
FDatasmithMaxMatWriter::ExportPhysicalMaterial(DatasmithScene, MaterialElement, Material);
break;
case EDSMaterialType::TheaRandom:
return; // already added!
break;
default:
if (UseFirstSubMapOnly(MaterialType, Material) == false)
{
DatasmithMaxLogger::Get().AddUnsupportedMat(Material);
}
else
{
DatasmithMaxLogger::Get().AddPartialSupportedMat(Material);
FDatasmithMaxMatExport::WriteXMLMaterial(DatasmithScene, MaterialElement, Material->GetSubMtl(0));
}
break;
}
}
FString FDatasmithMaxMatWriter::DumpTexture(TSharedRef< IDatasmithScene > DatasmithScene, TSharedPtr<IDatasmithCompositeTexture>& CompTex, Texmap* InTexmap, const TCHAR* Prefix, const TCHAR* ColorPrefix, bool bForceInvert, bool bIsGrayscale)
{
if (InTexmap == NULL)
{
return TEXT("");
}
// if it is not a regular one it should be nested.
if (CompTex->GetMode() != EDatasmithCompMode::Regular)
{
TSharedPtr<IDatasmithCompositeTexture> ChildCompTex = FDatasmithSceneFactory::CreateCompositeTexture();
FString Result = DumpTexture(DatasmithScene, ChildCompTex, InTexmap, Prefix,ColorPrefix, bForceInvert, bIsGrayscale);
CompTex->AddSurface(ChildCompTex);
return Result;
}
EDSBitmapType TextureClass = FDatasmithMaxMatHelper::GetTextureClass(InTexmap);
if (FString(Prefix) == DATASMITH_BUMPTEXNAME && TextureClass != EDSBitmapType::NormalMap)
{
DatasmithMaxLogger::Get().AddTextureError(TEXT("Bump maps are automatically converted to normal maps, as Unreal Engine does not handle bump maps directly."));
}
switch( TextureClass )
{
case EDSBitmapType::RegularBitmap:
{
return DumpBitmap(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::AutodeskBitmap:
{
return DumpAutodeskBitmap(CompTex, InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::TheaBitmap:
{
return DumpBitmapThea(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::CoronaBitmap:
{
return DumpBitmapCorona(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::VRayHRDI:
{
return DumpVrayHdri(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert);
}
case EDSBitmapType::ColorCorrector:
{
if(FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexmap) == false)
{
return DumpBakeable(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorCorrect(DatasmithScene, CompTex, InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
}
case EDSBitmapType::Gradient:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("color1"));
}
}
case EDSBitmapType::GradientRamp:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("color1"));
}
}
case EDSBitmapType::Checker:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("color1"));
}
}
case EDSBitmapType::Cellular:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("cellColor"));
}
}
case EDSBitmapType::FallOff:
{
return DumpFalloff(DatasmithScene, CompTex, InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::Mix:
{
return DumpMix(DatasmithScene, CompTex, InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::CompositeTex:
{
return DumpCompositetex(DatasmithScene, CompTex, InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::NormalMap:
{
return DumpNormalTexture(DatasmithScene, CompTex, InTexmap, Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::Noise:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("color1"));
}
}
case EDSBitmapType::VRayDirt:
{
DatasmithMaxLogger::Get().AddTextureError(TEXT("V-Ray dirt texture is not supported and only the unoccluded texture/color will be used"));
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("unoccluded_color"));
}
}
case EDSBitmapType::CoronaAO:
{
DatasmithMaxLogger::Get().AddGeneralError(TEXT("CoronaAO texture is not supported and only the unoccluded texture/color will be used"));
if (InTexmap->GetSubTexmap(1) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(1), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("colorUnoccluded"));
}
}
case EDSBitmapType::VRayColor:
{
return DumpVrayColor(CompTex, InTexmap, Prefix, bForceInvert);
}
case EDSBitmapType::CoronaColor:
{
return DumpCoronaColor(CompTex, InTexmap, Prefix, bForceInvert);
}
case EDSBitmapType::CoronaMix:
{
return DumpCoronaMix(DatasmithScene, CompTex, InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::CoronaMultiTex:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
return DumpCoronaMultitex(DatasmithScene, CompTex, InTexmap, Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
case EDSBitmapType::PhysicalSky:
{
DatasmithScene->SetUsePhysicalSky(true);
return TEXT("");
}
case EDSBitmapType::ThirdPartyMultiTex:
{
DatasmithMaxLogger::Get().AddPartialSupportedMap(InTexmap);
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("sub_color"));
}
}
case EDSBitmapType::BakeableMap:
{
if (FDatasmithMaxMatHelper::HasNonBakeableSubmap(InTexmap) == false)
{
return DumpBakeable(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert, bIsGrayscale);
}
}
default:
{
if (InTexmap->NumSubTexmaps() > 0)
{
DatasmithMaxLogger::Get().AddUnsupportedMap(InTexmap);
// just for try!
if (InTexmap->GetSubTexmap(0) != NULL)
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert, bIsGrayscale);
}
else
{
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("color1"));
}
}
else
{
DatasmithMaxLogger::Get().AddUnsupportedMap(InTexmap);
return DumpColorOfTexmap(CompTex, InTexmap, ColorPrefix, TEXT("color1"));
}
}
}
}
FString FDatasmithMaxMatWriter::DumpNormalTexture(TSharedRef< IDatasmithScene > DatasmithScene, TSharedPtr<IDatasmithCompositeTexture>& CompTex, Texmap* InTexmap, const TCHAR* Prefix, const TCHAR* ColorPrefix, bool bForceInvert, bool bIsGrayscale)
{
int NumParamBlocks = InTexmap->NumParamBlocks();
bool bInvertGreen = false;
for (int j = 0; j < NumParamBlocks; j++)
{
IParamBlock2* ParamBlock2 = InTexmap->GetParamBlockByID((short)j);
// The the descriptor to 'decode'
ParamBlockDesc2* ParamBlockDesc = ParamBlock2->GetDesc();
// Loop through all the defined parameters therein
for (int i = 0; i < ParamBlockDesc->count; i++)
{
const ParamDef& ParamDefinition = ParamBlockDesc->paramdefs[i];
if (FCString::Stricmp(ParamDefinition.int_name, TEXT("flip_green")) == 0 || FCString::Stricmp(ParamDefinition.int_name, TEXT("flipgreen")) == 0)
{
if (ParamBlock2->GetInt(ParamDefinition.ID, GetCOREInterface()->GetTime()) == 1)
{
bInvertGreen = true;
}
continue;
}
if (FCString::Stricmp(ParamDefinition.int_name, TEXT("complement_ddl")) == 0)
{
if (ParamBlock2->GetInt(ParamDefinition.ID, GetCOREInterface()->GetTime()) == 4)
{
bInvertGreen = false;
}
else
{
bInvertGreen = true;
}
continue;
}
}
}
EDSBitmapType TextureClass = FDatasmithMaxMatHelper::GetTextureClass(InTexmap);
if (TextureClass == EDSBitmapType::NormalMap)
{
if (FString(Prefix) != DATASMITH_BUMPTEXNAME)
{
FString DumpName = DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(0), Prefix, ColorPrefix, bForceInvert || bInvertGreen, bIsGrayscale);
TSharedPtr< IDatasmithTextureElement > TextureElement;
for (int TextureIndex = 0; TextureIndex < DatasmithScene->GetTexturesCount(); TextureIndex++)
{
if (DumpName == DatasmithScene->GetTexture(TextureIndex)->GetName())
{
TextureElement = DatasmithScene->GetTexture(TextureIndex);
}
}
if (TextureElement)
{
// Only process the TextureElement once (we assume that the "Other" TextureMode means that it hasn't been processed yet)
if ( TextureElement->GetTextureMode() == EDatasmithTextureMode::Other )
{
if ( bInvertGreen )
{
TextureElement->SetTextureMode( EDatasmithTextureMode::NormalGreenInv );
}
else
{
TextureElement->SetTextureMode( EDatasmithTextureMode::Normal );
}
float RgbCurve = TextureElement->GetRGBCurve();
// if RgbCurve <= 0 it has been set to default mode so we can forget about that
// this happens mostly when no advanced gamma correction is enabled in 3dsmax preferences
if (RgbCurve > 0.f)
{
if (FDatasmithMaxMatWriter::GetCoronaFixNormal(InTexmap) == true)
{
// corona has a checkbox to work in automatic mode
RgbCurve = -1.f;
}
else
{
// Bitmaps are by default using Gamma/2.2f RGB curve but the reference for normalmaps
// should be Gamma/1.0f
// if the user has set the proper value (1.0) the result will be 2.2/2.2 = 1.0
RgbCurve *= 2.2f;
}
TextureElement->SetRGBCurve(RgbCurve);
if (FMath::IsNearlyEqual(RgbCurve, 1.0f, 0.001f) == false && RgbCurve > 0.0f)
{
FString Error = FString("Potential wrong input gamma on normalmap: ") + FPaths::GetCleanFilename(TextureElement->GetFile());
DatasmithMaxLogger::Get().AddTextureError(*Error);
}
}
}
}
return DumpName;
}
else
{
return DumpTexture(DatasmithScene, CompTex, InTexmap->GetSubTexmap(1), TEXT(""), TEXT(""), bForceInvert, bIsGrayscale);
}
}
if (TextureClass == EDSBitmapType::TheaBitmap)
{
return DumpBitmapThea(CompTex, (BitmapTex*)InTexmap, Prefix, bForceInvert || bInvertGreen, bIsGrayscale);
}
return TEXT("");
}
void FDatasmithMaxMatWriter::DumpWeightedTexture(TSharedRef< IDatasmithScene > DatasmithScene, TSharedPtr<IDatasmithCompositeTexture>& CompTex, Texmap* InTexmap, BMM_Color_fl Color, float Weight, const TCHAR* Prefix, const TCHAR* ColorPrefix, bool bForceInvert, bool bIsGrayscale)
{
FString ActualPrefix = FString(Prefix) + FString(TEXT("comp"));
CompTex->SetMode(EDatasmithCompMode::Mix);
DumpTexture(DatasmithScene, CompTex, InTexmap, DATASMITH_TEXTURENAME, DATASMITH_COLORNAME, bForceInvert, bIsGrayscale);
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(Color));
CompTex->AddParamVal1(IDatasmithCompositeTexture::ParamVal(1.0f-(float)Weight, TEXT("Weight")));
}
void FDatasmithMaxMatWriter::DumpWeightedColor(TSharedPtr<IDatasmithCompositeTexture>& CompTex, BMM_Color_fl ColorA, BMM_Color_fl ColorB, float Weight, const TCHAR* Prefix)
{
if (Weight == 1)
{
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(ColorA));
return;
}
if (Weight == 0)
{
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(ColorB));
return;
}
FString ActualPrefix = FString(Prefix) + FString(TEXT("comp"));
CompTex->SetMode(EDatasmithCompMode::Mix);
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(ColorA));
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(ColorB));
CompTex->AddParamVal1(IDatasmithCompositeTexture::ParamVal(1.0f-(float)Weight, TEXT("Weight")));
}
FString FDatasmithMaxMatWriter::DumpColorOfTexmap(TSharedPtr<IDatasmithCompositeTexture>& CompTex, Texmap* InTexmap, const TCHAR* ColorPrefix, TCHAR* Property)
{
int NumParamBlocks = InTexmap->NumParamBlocks();
for (int j = 0; j < NumParamBlocks; j++)
{
IParamBlock2* ParamBlock2 = InTexmap->GetParamBlockByID((short)j);
if (ParamBlock2 == NULL)
{
return TEXT("");
}
// The the descriptor to 'decode'
ParamBlockDesc2* ParamBlockDesc = ParamBlock2->GetDesc();
if (ParamBlockDesc == NULL)
{
return TEXT("");
}
// Loop through all the defined parameters therein
for (int i = 0; i < ParamBlockDesc->count; i++)
{
const ParamDef& ParamDefinition = ParamBlockDesc->paramdefs[i];
if (FCString::Stricmp(ParamDefinition.int_name, Property) == 0)
{
BMM_Color_fl Color = (BMM_Color_fl)ParamBlock2->GetColor(ParamDefinition.ID, GetCOREInterface()->GetTime());
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(Color));
return TEXT("");
}
}
ParamBlock2->ReleaseDesc();
}
// not found using 'property', choose first color
for (int j = 0; j < NumParamBlocks; j++)
{
IParamBlock2* ParamBlock2 = InTexmap->GetParamBlockByID((short)j);
ParamBlockDesc2* ParamBlockDesc = ParamBlock2->GetDesc();
for (int i = 0; i < ParamBlockDesc->count; i++)
{
const ParamDef& ParamDefinition = ParamBlockDesc->paramdefs[i];
BMM_Color_fl Color = (BMM_Color_fl)ParamBlock2->GetColor(ParamDefinition.ID, GetCOREInterface()->GetTime());
if (Color.r != 0 || Color.g != 0 || Color.b != 0)
{
CompTex->AddSurface(FDatasmithMaxMatHelper::MaxColorToFLinearColor(Color));
return TEXT("");
}
}
ParamBlock2->ReleaseDesc();
}
return TEXT("");
}