2021-11-07 23:43:01 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# ifdef NEW_DIRECTLINK_PLUGIN
# include "DatasmithMaxDirectLink.h"
# include "DatasmithMaxHelper.h"
# include "DatasmithMaxWriter.h"
# include "DatasmithMaxClassIDs.h"
2022-06-10 12:47:33 -04:00
# include "DatasmithMaxSceneExporter.h"
2022-03-24 10:41:30 -04:00
# include "MaxMaterialsToUEPbr/DatasmithMaxMaterialsToUEPbr.h"
2021-11-07 23:43:01 -05:00
# include "DatasmithSceneFactory.h"
# include "Logging/LogMacros.h"
# include "Windows/AllowWindowsPlatformTypes.h"
MAX_INCLUDES_START
# include "impexp.h"
# include "max.h"
MAX_INCLUDES_END
namespace DatasmithMaxDirectLink
{
2022-06-10 12:47:33 -04:00
void FMaterialsCollectionTracker : : AddActualMaterial ( FMaterialTracker & MaterialTracker , Mtl * Material )
{
// Record relationships between tracked material and actual materials used on geometry(e.g. submaterials of a tracked multisubobj material)
UsedMaterialToMaterialTracker . FindOrAdd ( Material ) . Add ( & MaterialTracker ) ;
MaterialTracker . AddActualMaterial ( Material ) ;
}
const TCHAR * FMaterialsCollectionTracker : : GetMaterialName ( Mtl * Material )
{
if ( FString * NamePtr = UsedMaterialToDatasmithMaterialName . Find ( Material ) )
{
return * * NamePtr ;
}
return * UsedMaterialToDatasmithMaterialName . Add ( Material ,
MaterialNameProvider . GenerateUniqueName ( FDatasmithUtils : : SanitizeObjectName ( Material - > GetName ( ) . data ( ) ) ) ) ;
}
void FMaterialsCollectionTracker : : AssignMeshMaterials ( const TSharedPtr < IDatasmithMeshElement > & MeshElement , Mtl * Material , const TSet < uint16 > & SupportedChannels )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) = = EDSMaterialType : : XRefMat )
{
AssignMeshMaterials ( MeshElement , FDatasmithMaxMatHelper : : GetRenderedXRefMaterial ( Material ) , SupportedChannels ) ;
return ;
}
if ( Material ! = nullptr )
{
TArray < uint16 > ChannelsSorted = SupportedChannels . Array ( ) ;
ChannelsSorted . Sort ( ) ;
for ( uint16 Channel : ChannelsSorted )
{
//Max's channel UI is not zero-based, so we register an incremented ChannelID for better visual consistency after importing in Unreal.
uint16 DisplayedChannelID = Channel + 1 ;
// Multi mat
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) = = EDSMaterialType : : MultiMat )
{
// Replicate the 3ds max behavior where material ids greater than the number of sub-materials wrap around and are mapped to the existing sub-materials
if ( Mtl * SubMaterial = Material - > GetSubMtl ( Channel % Material - > NumSubMtls ( ) ) )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( SubMaterial ) = = EDSMaterialType : : TheaRandom )
{
MeshElement - > SetMaterial ( * FDatasmithMaxSceneExporter : : GetRandomSubMaterial ( SubMaterial , MeshElement - > GetDimensions ( ) ) , DisplayedChannelID ) ;
}
else
{
MeshElement - > SetMaterial ( GetMaterialName ( SubMaterial ) , DisplayedChannelID ) ;
}
}
}
else if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) = = EDSMaterialType : : TheaRandom )
{
MeshElement - > SetMaterial ( * FDatasmithMaxSceneExporter : : GetRandomSubMaterial ( Material , MeshElement - > GetDimensions ( ) ) , DisplayedChannelID ) ;
}
// Single material
else
{
MeshElement - > SetMaterial ( GetMaterialName ( Material ) , DisplayedChannelID ) ;
}
}
}
}
void FMaterialsCollectionTracker : : AssignMeshActorMaterials ( const TSharedPtr < IDatasmithMeshActorElement > & MeshActor , Mtl * Material , TSet < uint16 > & SupportedChannels , const FVector3f & RandomSeed )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) = = EDSMaterialType : : XRefMat )
{
AssignMeshActorMaterials ( MeshActor , FDatasmithMaxMatHelper : : GetRenderedXRefMaterial ( Material ) , SupportedChannels , RandomSeed ) ;
return ;
}
if ( Material ! = nullptr )
{
if ( SupportedChannels . Num ( ) < = 1 )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) ! = EDSMaterialType : : MultiMat )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) ! = EDSMaterialType : : TheaRandom )
{
MeshActor - > AddMaterialOverride ( GetMaterialName ( Material ) , - 1 ) ;
}
else
{
MeshActor - > AddMaterialOverride ( * FDatasmithMaxSceneExporter : : GetRandomSubMaterial ( Material , RandomSeed ) , - 1 ) ;
}
}
else
{
int Mid = 0 ;
//Find the lowest supported material id.
SupportedChannels . Sort ( [ ] ( const uint16 & A , const uint16 & B ) { return ( A < B ) ; } ) ;
for ( const uint16 SupportedMid : SupportedChannels )
{
Mid = SupportedMid ;
}
// Replicate the 3ds max behavior where material ids greater than the number of sub-materials wrap around and are mapped to the existing sub-materials
if ( Mtl * SubMaterial = Material - > GetSubMtl ( Mid % Material - > NumSubMtls ( ) ) )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( SubMaterial ) ! = EDSMaterialType : : TheaRandom )
{
MeshActor - > AddMaterialOverride ( GetMaterialName ( SubMaterial ) , - 1 ) ;
}
else
{
MeshActor - > AddMaterialOverride ( * FDatasmithMaxSceneExporter : : GetRandomSubMaterial ( SubMaterial , RandomSeed ) , - 1 ) ;
}
}
}
}
else
{
int ActualSubObj = 1 ;
SupportedChannels . Sort ( [ ] ( const uint16 & A , const uint16 & B ) { return ( A < B ) ; } ) ;
for ( const uint16 Mid : SupportedChannels )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) ! = EDSMaterialType : : MultiMat )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) ! = EDSMaterialType : : TheaRandom )
{
MeshActor - > AddMaterialOverride ( GetMaterialName ( Material ) , ActualSubObj ) ;
}
else
{
MeshActor - > AddMaterialOverride ( * FDatasmithMaxSceneExporter : : GetRandomSubMaterial ( Material , RandomSeed ) , ActualSubObj ) ;
}
}
else
{
// Replicate the 3ds max behavior where material ids greater than the number of sub-materials wrap around and are mapped to the existing sub-materials
int32 MaterialIndex = Mid % Material - > NumSubMtls ( ) ;
Mtl * SubMaterial = Material - > GetSubMtl ( MaterialIndex ) ;
if ( SubMaterial ! = nullptr )
{
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( SubMaterial ) ! = EDSMaterialType : : TheaRandom )
{
//Material slots in Max are not zero-based, so we serialize our SlotID starting from 1 for better visual consistency.
MeshActor - > AddMaterialOverride ( GetMaterialName ( SubMaterial ) , Mid + 1 ) ;
}
else
{
MeshActor - > AddMaterialOverride ( * FDatasmithMaxSceneExporter : : GetRandomSubMaterial ( SubMaterial , RandomSeed ) , MaterialIndex + 1 ) ;
}
}
}
ActualSubObj + + ;
}
}
}
}
2021-11-07 23:43:01 -05:00
// Copied from
// FDatasmithMaxSceneParser::MaterialEnum
// FDatasmithMaxSceneParser::TexEnum
// Collects actual materials that are used by the top-level material(assigned to node)
class FMaterialEnum
{
public :
FMaterialsCollectionTracker & MaterialsCollectionTracker ;
FMaterialTracker & MaterialTracker ;
FMaterialEnum ( FMaterialsCollectionTracker & InMaterialsCollectionTracker , FMaterialTracker & InMaterialTracker ) : MaterialsCollectionTracker ( InMaterialsCollectionTracker ) , MaterialTracker ( InMaterialTracker ) { }
void MaterialEnum ( Mtl * Material , bool bAddMaterial )
{
if ( Material = = NULL )
{
return ;
}
if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) = = EDSMaterialType : : XRefMat )
{
MaterialEnum ( FDatasmithMaxMatHelper : : GetRenderedXRefMaterial ( Material ) , true ) ;
}
else if ( FDatasmithMaxMatHelper : : GetMaterialClass ( Material ) = = EDSMaterialType : : MultiMat )
{
for ( int i = 0 ; i < Material - > NumSubMtls ( ) ; i + + )
{
MaterialEnum ( Material - > GetSubMtl ( i ) , true ) ;
}
}
else
{
if ( bAddMaterial )
{
2022-06-10 12:47:33 -04:00
MaterialsCollectionTracker . AddActualMaterial ( MaterialTracker , Material ) ;
2021-11-07 23:43:01 -05:00
}
2022-06-10 12:47:33 -04:00
bool bAddRecursively = Material - > ClassID ( ) = = THEARANDOMCLASS | | Material - > ClassID ( ) = = VRAYBLENDMATCLASS | | Material - > ClassID ( ) = = CORONALAYERMATCLASS | | Material - > ClassID ( ) = = BLENDMATCLASS ;
2021-11-07 23:43:01 -05:00
for ( int i = 0 ; i < Material - > NumSubMtls ( ) ; i + + )
{
MaterialEnum ( Material - > GetSubMtl ( i ) , bAddRecursively ) ;
}
}
}
} ;
void FMaterialsCollectionTracker : : Reset ( )
{
MaterialTrackers . Reset ( ) ;
InvalidatedMaterialTrackers . Reset ( ) ;
EncounteredMaterials . Reset ( ) ;
EncounteredTextures . Reset ( ) ;
MaterialNames . Reset ( ) ;
UsedMaterialToMaterialTracker . Reset ( ) ;
UsedMaterialToDatasmithMaterial . Reset ( ) ;
2022-06-10 12:47:33 -04:00
UsedMaterialToDatasmithMaterialName . Reset ( ) ;
MaterialNameProvider . Clear ( ) ;
2022-03-24 10:41:30 -04:00
UsedTextureToMaterialTracker . Reset ( ) ;
UsedTextureToDatasmithElement . Reset ( ) ;
2021-11-07 23:43:01 -05:00
}
void FMaterialsCollectionTracker : : UpdateMaterial ( FMaterialTracker * MaterialTracker )
{
RemoveConvertedMaterial ( * MaterialTracker ) ;
FMaterialEnum ( * this , * MaterialTracker ) . MaterialEnum ( MaterialTracker - > Material , true ) ;
2022-06-10 12:47:33 -04:00
}
void FMaterialsCollectionTracker : : AddDatasmithMaterialForUsedMaterial ( TSharedRef < IDatasmithScene > DatasmithScene , Mtl * Material , TSharedPtr < IDatasmithBaseMaterialElement > DatasmithMaterial )
{
if ( DatasmithMaterial )
2021-11-07 23:43:01 -05:00
{
2022-06-10 12:47:33 -04:00
SCENE_UPDATE_STAT_INC ( UpdateMaterials , Converted ) ;
DatasmithScene - > AddMaterial ( DatasmithMaterial ) ;
UsedMaterialToDatasmithMaterial . Add ( Material , DatasmithMaterial ) ;
SceneTracker . RemapConvertedMaterialUVChannels ( Material , DatasmithMaterial ) ;
2021-11-07 23:43:01 -05:00
}
}
2022-03-24 10:41:30 -04:00
void FMaterialsCollectionTracker : : ConvertMaterial ( Mtl * Material , TSharedRef < IDatasmithScene > DatasmithScene , const TCHAR * AssetsPath , TSet < Texmap * > & TexmapsConverted )
{
2022-06-10 12:47:33 -04:00
if ( UsedMaterialToDatasmithMaterial . Contains ( Material ) )
2022-03-24 10:41:30 -04:00
{
2022-06-10 12:47:33 -04:00
// Material might have been already converted - if it's present in UsedMaterialToDatasmithMaterial this means that it(or multisubobj it's part of) wasn't changed
// e.g. this happens when another multisubobj material is added with existing (and already converted) material as submaterial
return ;
2022-03-24 10:41:30 -04:00
}
2022-06-10 12:47:33 -04:00
SCENE_UPDATE_STAT_INC ( UpdateMaterials , Total ) ;
2022-03-24 10:41:30 -04:00
2022-06-10 12:47:33 -04:00
TMap < Texmap * , TSet < TSharedPtr < IDatasmithTextureElement > > > TexmapsUsedByMaterial ;
FMaterialConversionContext MaterialConversionContext = { TexmapsUsedByMaterial , * this } ;
TGuardValue MaterialConversionContextGuard ( FDatasmithMaxMaterialsToUEPbrManager : : Context , & MaterialConversionContext ) ;
TSharedPtr < IDatasmithBaseMaterialElement > DatasmithMaterial ;
2022-03-24 10:41:30 -04:00
if ( FDatasmithMaxMaterialsToUEPbr * MaterialConverter = FDatasmithMaxMaterialsToUEPbrManager : : GetMaterialConverter ( Material ) )
{
MaterialConverter - > Convert ( DatasmithScene , DatasmithMaterial , Material , AssetsPath ) ;
2022-06-10 12:47:33 -04:00
AddDatasmithMaterialForUsedMaterial ( DatasmithScene , Material , DatasmithMaterial ) ;
2022-03-24 10:41:30 -04:00
}
// Tie texture used by an actual material to tracked material
2022-06-07 02:12:06 -04:00
for ( TPair < Texmap * , TSet < TSharedPtr < IDatasmithTextureElement > > > TexmapAndDatasmithElements : TexmapsUsedByMaterial )
2022-03-24 10:41:30 -04:00
{
2022-06-07 02:12:06 -04:00
Texmap * Tex = TexmapAndDatasmithElements . Key ;
2022-03-24 10:41:30 -04:00
for ( FMaterialTracker * MaterialTracker : UsedMaterialToMaterialTracker [ Material ] )
{
2022-06-07 02:12:06 -04:00
MaterialTracker - > AddActualTexture ( Tex ) ;
UsedTextureToMaterialTracker . FindOrAdd ( Tex ) . Add ( MaterialTracker ) ;
2022-03-24 10:41:30 -04:00
}
2022-06-07 02:12:06 -04:00
// Some material converters create texture elements during material conversion(like bakeable) - record created texture elements
UsedTextureToDatasmithElement . FindOrAdd ( Tex ) . Append ( TexmapAndDatasmithElements . Value ) ;
TexmapsConverted . Add ( Tex ) ;
}
2022-03-24 10:41:30 -04:00
}
2021-11-07 23:43:01 -05:00
void FMaterialsCollectionTracker : : ReleaseMaterial ( FMaterialTracker & MaterialTracker )
{
RemoveConvertedMaterial ( MaterialTracker ) ;
MaterialTrackers . Remove ( MaterialTracker . Material ) ;
2022-03-10 01:41:48 -05:00
InvalidatedMaterialTrackers . Remove ( & MaterialTracker ) ;
2021-11-07 23:43:01 -05:00
}
2022-03-24 10:41:30 -04:00
2021-11-07 23:43:01 -05:00
void FMaterialsCollectionTracker : : RemoveConvertedMaterial ( FMaterialTracker & MaterialTracker )
{
for ( Mtl * Material : MaterialTracker . GetActualMaterials ( ) )
{
TSet < FMaterialTracker * > & MaterialTrackersForMaterial = UsedMaterialToMaterialTracker [ Material ] ;
MaterialTrackersForMaterial . Remove ( & MaterialTracker ) ;
if ( ! MaterialTrackersForMaterial . Num ( ) )
{
UsedMaterialToMaterialTracker . Remove ( Material ) ;
2022-06-10 12:47:33 -04:00
if ( FString Name ; UsedMaterialToDatasmithMaterialName . RemoveAndCopyValue ( Material , Name ) )
{
MaterialNameProvider . RemoveExistingName ( Name ) ;
}
2021-11-07 23:43:01 -05:00
TSharedPtr < IDatasmithBaseMaterialElement > DatasmithMaterial ;
if ( UsedMaterialToDatasmithMaterial . RemoveAndCopyValue ( Material , DatasmithMaterial ) )
{
SceneTracker . RemoveMaterial ( DatasmithMaterial ) ;
}
}
}
2022-03-24 10:41:30 -04:00
for ( Texmap * Texture : MaterialTracker . GetActualTexmaps ( ) )
{
TSet < FMaterialTracker * > & MaterialTrackersForTexture = UsedTextureToMaterialTracker [ Texture ] ;
MaterialTrackersForTexture . Remove ( & MaterialTracker ) ;
if ( ! MaterialTrackersForTexture . Num ( ) ) // No tracked materials are using this texture anymore
{
UsedTextureToMaterialTracker . Remove ( Texture ) ;
for ( const TSharedPtr < IDatasmithTextureElement > & TextureElement : UsedTextureToDatasmithElement [ Texture ] )
{
SceneTracker . RemoveTexture ( TextureElement ) ;
}
UsedTextureToDatasmithElement . Remove ( Texture ) ;
}
}
2021-11-07 23:43:01 -05:00
MaterialTracker . ResetActualMaterialAndTextures ( ) ;
}
FMaterialTracker * FMaterialsCollectionTracker : : AddMaterial ( Mtl * Material )
{
if ( FMaterialTrackerHandle * HandlePtr = MaterialTrackers . Find ( Material ) )
{
return HandlePtr - > GetMaterialTracker ( ) ;
}
// Track material if not yet
FMaterialTrackerHandle & MaterialTrackerHandle = MaterialTrackers . Emplace ( Material , Material ) ;
InvalidatedMaterialTrackers . Add ( MaterialTrackerHandle . GetMaterialTracker ( ) ) ;
return MaterialTrackerHandle . GetMaterialTracker ( ) ;
}
void FMaterialsCollectionTracker : : InvalidateMaterial ( Mtl * Material )
{
if ( FMaterialTrackerHandle * MaterialTrackerHandle = MaterialTrackers . Find ( Material ) )
{
InvalidatedMaterialTrackers . Add ( MaterialTrackerHandle - > GetMaterialTracker ( ) ) ;
}
}
}
# include "Windows/HideWindowsPlatformTypes.h"
# endif // NEW_DIRECTLINK_PLUGIN