// Copyright Epic Games, Inc. All Rights Reserved. #include "WireInterfaceImpl.h" #include "Modules/ModuleManager.h" #ifdef USE_OPENMODEL #include "CADOptions.h" #include "Containers/List.h" #include "DatasmithImportOptions.h" #include "DatasmithPayload.h" #include "DatasmithSceneFactory.h" #include "DatasmithUtils.h" #include "GenericPlatform/GenericPlatformTLS.h" #include "HAL/ConsoleManager.h" #include "IDatasmithSceneElements.h" #include "Misc/FileHelper.h" #include "Misc/Paths.h" #include "Modules/ModuleInterface.h" #include "Modules/ModuleManager.h" #include "Utility/DatasmithMeshHelper.h" #include "StaticMeshDescription.h" #include "StaticMeshOperations.h" #include "AliasModelToCADKernelConverter.h" #include "AliasModelToTechSoftConverter.h" // requires Techsoft as public dependency #include "CADInterfacesModule.h" #if PLATFORM_WINDOWS #include "Windows/AllowWindowsPlatformTypes.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if PLATFORM_WINDOWS #include "Windows/HideWindowsPlatformTypes.h" #endif #define LOCTEXT_NAMESPACE "WireInterface" #define WRONG_VERSION_TEXT "Unsupported version of Alias detected. Please upgrade to Alias 2021.3 (or later version)." #define TRACK_MESHELEMENT 0 #define MAKE_VISIBLE 0 #if MAKE_VISIBLE #include "CompGeom/FitOrientedBox3.h" #endif namespace UE_DATASMITHWIRETRANSLATOR_NAMESPACE { #if TRACK_MESHELEMENT //static const FString ToTrack(TEXT("shell_30181")); //static const FString ToTrack(TEXT("Blend_srf_1395")); //static const FString ToTrack(TEXT("M0047942")); //static const FString ToTrack(TEXT("C5_31495_surf")); // G6 static const FString ToTrack(TEXT("Object__TRANSFORM_copy_2_surf")); // refrigerator void MakeMeshVisible(FMeshDescription& MeshDescription); #endif #if WIRE_MEMORY_CHECK int32 AllocatedObjects = 0; int32 MaxAllocatedObjects = 0; TSet DagNodeSet; TSet ObjectSet; #endif static const FColor DefaultColor = FColor(200, 200, 200); const uint64 LibAliasNext_Version = 0xffffffffffffffffull; const uint64 LibAlias2025_0_0_Version = 8725724278030572; const uint64 LibAlias2024_1_0_Version = 8444253596292024; const uint64 LibAlias2023_1_0_Version = 8162778619576619; const uint64 LibAlias2023_0_0_Version = 8162774324609149; const uint64 LibAlias2022_2_0_Version = 7881307937833405; const uint64 LibAlias2022_1_0_Version = 7881303642865885; const uint64 LibAlias2022_0_1_Version = 7881299347964005; const uint64 LibAlias2021_3_2_Version = 7599833027117059; const uint64 LibAlias2021_3_1_Version = 7599824433840131; const uint64 LibAlias2021_3_0_Version = 7599824424206339; const uint64 LibAlias2021_Version = 7599824377020416; const uint64 LibAlias2020_Version = 7318349414924288; const uint64 LibAlias2019_Version = 5000000000000000; #if defined(OPEN_MODEL_2020) const uint64 LibAliasVersionMin = LibAlias2019_Version; const uint64 LibAliasVersionMax = LibAlias2021_3_0_Version; const FString AliasSdkVersion = TEXT("2020"); #elif defined(OPEN_MODEL_2021_3) const uint64 LibAliasVersionMin = LibAlias2021_3_0_Version; const uint64 LibAliasVersionMax = LibAlias2022_0_1_Version; const FString AliasSdkVersion = TEXT("2021.3"); #elif defined(OPEN_MODEL_2022) const uint64 LibAliasVersionMin = LibAlias2022_0_1_Version; const uint64 LibAliasVersionMax = LibAlias2022_1_0_Version; const FString AliasSdkVersion = TEXT("2022"); #elif defined(OPEN_MODEL_2022_1) const uint64 LibAliasVersionMin = LibAlias2022_1_0_Version; const uint64 LibAliasVersionMax = LibAlias2022_2_0_Version; const FString AliasSdkVersion = TEXT("2022.1"); #elif defined(OPEN_MODEL_2022_2) const uint64 LibAliasVersionMin = LibAlias2022_2_0_Version; const uint64 LibAliasVersionMax = LibAlias2023_0_0_Version; const FString AliasSdkVersion = TEXT("2022.2"); #elif defined(OPEN_MODEL_2023_0) const uint64 LibAliasVersionMin = LibAlias2023_0_0_Version; const uint64 LibAliasVersionMax = LibAlias2023_1_0_Version; const FString AliasSdkVersion = TEXT("2023.0"); #elif defined(OPEN_MODEL_2023_1) const uint64 LibAliasVersionMin = LibAlias2023_1_0_Version; const uint64 LibAliasVersionMax = LibAlias2024_1_0_Version; const FString AliasSdkVersion = TEXT("2023.1"); #elif defined(OPEN_MODEL_2024_1) const uint64 LibAliasVersionMin = LibAlias2024_1_0_Version; const uint64 LibAliasVersionMax = LibAlias2025_0_0_Version; const FString AliasSdkVersion = TEXT("2024.1"); #elif defined(OPEN_MODEL_2025_0) const uint64 LibAliasVersionMin = LibAlias2025_0_0_Version; const uint64 LibAliasVersionMax = LibAliasNext_Version; const FString AliasSdkVersion = TEXT("2025.0"); #endif // Alias material management (to allow sew of BReps of different materials): // To be compatible with "Retessellate" function, Alias material management as to be the same than CAD (TechSoft) import. // As a reminder: the name and slot of UE Material from CAD is based on CAD material/color data i.e. RGBA Color components => "UE Material slot" (int32) and "UE Material name" (FString = FString::FromInt("UE Material slot")) // UE Material Label is free. // // During Retessellate step, Color/Material of each CAD Faces are known, so "UE Material slot" can be deduced. // // For Alias import: // Alias BRep is exported in CAD modeler (CADKernel, TechSoft, ...) // Material is build in UE, // From an Alias Material, a unique Color is generated. // This Color is associated to the BRep Shell/face in the CAD modeler // The name and slot of the associated UE Material is defined from this color // So at the retessellate step, nothing changes from the CAD Retessellate process // // The unique Color of an Alias Material is defined as follows: // TypeHash(Alias Material Name) => uint24 == 3 uint8 => RGB components of the color FColor CreateShaderColorFromShaderName(const FString& ShaderName) { const uint32 ShaderHash = FCrc::Strihash_DEPRECATED(*ShaderName); const uint32 Red = (ShaderHash & 0xff000000) >> 24; const uint32 Green = (ShaderHash & 0x00ff0000) >> 16; const uint32 Blue = (ShaderHash & 0x0000ff00) >> 8; return FColor(Red, Green, Blue); } int32 CreateShaderId(const FColor& ShaderColor) { return FMath::Abs((int32)GetTypeHash(ShaderColor)); } uint32 GetSceneFileHash(const FString& FullPath, const FString& FileName) { FFileStatData FileStatData = IFileManager::Get().GetStatData(*FullPath); int64 FileSize = FileStatData.FileSize; FDateTime ModificationTime = FileStatData.ModificationTime; uint32 FileHash = GetTypeHash(FileName); FileHash = HashCombine(FileHash, GetTypeHash(FileSize)); FileHash = HashCombine(FileHash, GetTypeHash(ModificationTime)); return FileHash; } bool GetConsoleBoolValue(const TCHAR* CVarName, bool bDefault) { const IConsoleVariable* ConsoleVariable = IConsoleManager::Get().FindConsoleVariable(CVarName); return ConsoleVariable ? ConsoleVariable->GetBool() : bDefault; } bool FWireTranslatorImpl::Initialize(const TCHAR* InSceneFullName) { if (InSceneFullName) { statusCode Status = AlUniverse::initialize(); if (Status != sSuccess && Status != sAlreadyCreated) { UE_LOG(LogWireInterface, Error, TEXT("Cannot initialize OpenModel SDK. Import is aborted.")); return false; } const TStringConversion Result = StringCast(InSceneFullName); char OpenModelVersion[10]; if (bool(AlUniverse::isWireFile(Result.Get(), OpenModelVersion))) { SceneFullPath = InSceneFullName; SceneVersion = StringCast(OpenModelVersion).Get(); } else { UE_LOG(LogWireInterface, Error, TEXT("Cannot load %s with the selected OpenModel SDK."), InSceneFullName); return false; } } return true; } FWireTranslatorImpl::~FWireTranslatorImpl() { if (bSceneLoaded) { FLayerContainer::Reset(); MeshElementToParametricNode.Reset(); MeshElementToMeshNode.Reset(); MeshElementToBodyNode.Reset(); MeshElementToPatchMesh.Reset(); EncounteredNodes.Reset(); #if WIRE_MEMORY_CHECK if (!ensure(AllocatedObjects == 0)) { for (AlObject* Object : ObjectSet) { if (AlIsValid(Object)) { AlObjectType Type = Object->type(); printf(">>> %d\n", Type); } else { ensure(false); } } } #endif } bSceneLoaded = false; } void FWireTranslatorImpl::SetImportSettings(const FWireSettings& Settings) { WireSettings = Settings; WireSettings.bUseCADKernel = !CADLibrary::FImportParameters::bGDisableCADKernelTessellation; if (CADModelConverter) { CADModelConverter->SetImportParameters(Settings.ChordTolerance, Settings.MaxEdgeLength, Settings.NormalTolerance, (CADLibrary::EStitchingTechnique)Settings.StitchingTechnique); } } // Wire file parsing bool FWireTranslatorImpl::Load(TSharedPtr InScene) { UE_LOG(LogWireInterface, Display, TEXT("CAD translation [%s]."), *SceneFullPath); UE_LOG(LogWireInterface, Display, TEXT(" - File version: Alias %s"), *SceneVersion); UE_LOG(LogWireInterface, Display, TEXT(" - Parsing Library: Alias %s"), *AliasSdkVersion); UE_LOG(LogWireInterface, Display, TEXT(" - Tessellation Library: %s"), WireSettings.bUseCADKernel ? TEXT("CADKernel") : TEXT("TechSoft")); UE_LOG(LogWireInterface, Display, TEXT(" - Translation parameters:")); UE_LOG(LogWireInterface, Display, TEXT(" - Merge By Group: %s"), WireSettings.bMergeGeometryByGroup ? TEXT("True") : TEXT("False")); UE_LOG(LogWireInterface, Display, TEXT(" - Layer As actor: %s"), WireSettings.bUseLayerAsActor ? TEXT("True") : TEXT("False")); UE_LOG(LogWireInterface, Display, TEXT(" - Tessellation parameters:")); UE_LOG(LogWireInterface, Display, TEXT(" - ChordTolerance: %lf"), WireSettings.ChordTolerance); UE_LOG(LogWireInterface, Display, TEXT(" - MaxEdgeLength: %lf"), WireSettings.MaxEdgeLength); UE_LOG(LogWireInterface, Display, TEXT(" - MaxNormalAngle: %lf"), WireSettings.NormalTolerance); FString StitchingTechnique; switch (WireSettings.StitchingTechnique) { case EDatasmithCADStitchingTechnique::StitchingHeal: StitchingTechnique = TEXT("Heal"); break; case EDatasmithCADStitchingTechnique::StitchingSew: StitchingTechnique = TEXT("Sew"); break; default: StitchingTechnique = TEXT("None"); break; } UE_LOG(LogWireInterface, Display, TEXT(" - StitchingTechnique: %s"), *StitchingTechnique); UE_LOG(LogWireInterface, Display, TEXT(" - GeometricTolerance: %lf"), WireSettings.GetGeometricTolerance()); UE_LOG(LogWireInterface, Display, TEXT(" - Stitching Tolerance: %lf"), WireSettings.GetStitchingTolerance()); // #wire_import: TODO - Revisit stitching extension when using CADKernel //if (WireSettings.bUseCADKernel) //{ // UE_LOG(LogWireInterface, Display, TEXT(" - Stitching Options:")); // UE_LOG(LogWireInterface, Display, TEXT(" - ForceSew: %s"), CADLibrary::FImportParameters::bGStitchingForceSew ? TEXT("True") : TEXT("False")); // UE_LOG(LogWireInterface, Display, TEXT(" - RemoveThinFaces: %s"), CADLibrary::FImportParameters::bGStitchingRemoveThinFaces ? TEXT("True") : TEXT("False")); // UE_LOG(LogWireInterface, Display, TEXT(" - RemoveDuplicatedFaces: %s"), CADLibrary::FImportParameters::bGStitchingRemoveDuplicatedFaces ? TEXT("True") : TEXT("False")); // UE_LOG(LogWireInterface, Display, TEXT(" - ForceFactor: %f"), CADLibrary::FImportParameters::GStitchingForceFactor); //} DatasmithScene = InScene; const FString AliasProductVersion = FString::Printf(TEXT("Alias %s"), *AliasSdkVersion); DatasmithScene->SetHost(TEXT("Alias")); DatasmithScene->SetVendor(TEXT("Autodesk")); DatasmithScene->SetProductName(TEXT("Alias Tools")); DatasmithScene->SetExporterSDKVersion(*AliasSdkVersion); DatasmithScene->SetProductVersion(*AliasProductVersion); WireSettings.bAliasUseNative = GetConsoleBoolValue(TEXT("ds.Wiretranslator.UseNative"), false); if (!WireSettings.bAliasUseNative) { CADLibrary::FImportParameters ImportParameters; if (CADLibrary::FImportParameters::bGDisableCADKernelTessellation) { CADModelConverter = MakeShared(ImportParameters); } else { CADModelConverter = MakeShared(WireSettings, ImportParameters); } } else { // Merge by group when using Alias' tessellator WireSettings.bMergeGeometryByGroup = false; } // Initialize Alias. statusCode Status = AlUniverse::initialize(); if (Status != sSuccess && Status != sAlreadyCreated) { UE_LOG(LogWireInterface, Error, TEXT("Cannot initialize OpenModel SDK. Import is aborted.")); return false; } if (AlUniverse::retrieve(TCHAR_TO_UTF8(*SceneFullPath)) != sSuccess) { return false; } AlRetrieveOptions options; AlUniverse::retrieveOptions(options); bSceneLoaded = true; return TraverseModel(); } bool FWireTranslatorImpl::TraverseModel() { #if WIRE_MEMORY_CHECK AllocatedObjects = 0; MaxAllocatedObjects = 0; ObjectSet.Reset(); DagNodeSet.Reset(); #endif FAlDagNodePtr DagNode = FindOrAddDagNode(AlUniverse::firstDagNode()); while (DagNode) { TSharedPtr ActorElement = TraverseDag(DagNode); if (ActorElement) { DatasmithScene->AddActor(ActorElement); } DagNode = FindOrAddDagNode(DagNode->nextNode()); } TAlObjectPtr Set(AlUniverse::firstSet()); statusCode Status = Set ? sSuccess : sFailure; while (Status == sSuccess) { // #wire_import: Add an actor to represent the set. TAlObjectPtr SetMember(Set->firstMember()); statusCode MemberStatus = SetMember ? sSuccess : sFailure; while (MemberStatus == sSuccess) { FAlDagNodePtr DagNodeInSet(SetMember->object() ? SetMember->object()->asDagNodePtr() : nullptr); if (DagNodeInSet) { TSharedPtr ActorElement = TraverseDag(DagNodeInSet); if (ActorElement) { DatasmithScene->AddActor(ActorElement); } } MemberStatus = SetMember->nextSetMemberD(); } Status = Set->nextSetD(); } return true; } TSharedPtr FWireTranslatorImpl::TraverseDag(const FAlDagNodePtr& RootNode) { if (RootNode.IsAGroup()) { return WireSettings.bMergeGeometryByGroup ? ProcessGroupNode(RootNode) : TraverseGroupNode(RootNode); } else if (RootNode.HasGeometry()) { return ProcessGeometryNode(RootNode); } return TSharedPtr(); } TSharedPtr FWireTranslatorImpl::TraverseGroupNode(const FAlDagNodePtr& GroupNode, const TAlObjectPtr& ParentLayer) { if (!GroupNode.IsAGroup()) { return TSharedPtr(); } TArray Children; FAlDagNodePtr ChildNode = FindOrAddDagNode(GroupNode->asGroupNodePtr()->childNode()); while (ChildNode) { Children.Add(ChildNode); ChildNode = FindOrAddDagNode(ChildNode->nextNode()); } const int32 ChildrenCount = Children.Num(); if (ChildrenCount == 0) { return TSharedPtr(); } TArray> ChildActors; ChildActors.Reserve(ChildrenCount); TAlObjectPtr GroupLayer = FLayerContainer::FindOrAdd(GroupNode->layer()); for (FAlDagNodePtr& Child : Children) { if (TSharedPtr ActorElement = TraverseGroupNode(Child, GroupLayer)) { ChildActors.Emplace(MoveTemp(ActorElement)); } else if (Child.IsAMesh() || Child.IsASurface()) { if (TSharedPtr ChildActorElement = ProcessGeometryNode(Child, ParentLayer)) { ChildActors.Emplace(MoveTemp(ChildActorElement)); } } } if (ChildActors.Num() == 0) { return TSharedPtr(); } TSharedPtr ActorElement = FDatasmithSceneFactory::CreateActor(*GroupNode.GetUniqueID(GROUPNODE_TYPE)); if (!ActorElement.IsValid()) { return ActorElement; } FString Label = GroupNode.GetName(); ActorElement->SetLabel(Label.Len() > 0 ? *Label : TEXT("UnnamedGroup")); FString CsvLayerString; if (OpenModelUtils::GetCsvLayerString(GroupLayer, CsvLayerString)) { ActorElement->SetLayer(*CsvLayerString); } GroupNode.SetActorTransform(*ActorElement); for (TSharedPtr& ChildActor : ChildActors) { if (OpenModelUtils::ActorHasContent(ChildActor)) { ActorElement->AddChild(ChildActor); } } if (WireSettings.bUseLayerAsActor && GroupLayer != ParentLayer) { if (OpenModelUtils::ActorHasContent(ActorElement)) { if (TSharedPtr LayerActor = FindOrAddLayerActor(GroupLayer)) { LayerActor->AddChild(ActorElement); } } return TSharedPtr(); } return ActorElement; } TSharedPtr FWireTranslatorImpl::ProcessGroupNode(const FAlDagNodePtr& GroupNode, const TAlObjectPtr& ParentLayer) { if (!GroupNode.IsAGroup()) { return TSharedPtr(); } TArray Children; FAlDagNodePtr ChildNode = FindOrAddDagNode(GroupNode->asGroupNodePtr()->childNode()); while (ChildNode) { Children.Add(ChildNode); AlDagNode* NextNode = ChildNode->nextNode(); #if WIRE_MEMORY_CHECK ensure(NextNode != ChildNode.Get()); #endif ChildNode = FindOrAddDagNode(NextNode); } const int32 ChildrenCount = Children.Num(); if (ChildrenCount == 0) { return TSharedPtr(); } TArray> ChildActors; ChildActors.Reserve(ChildrenCount); TAlObjectPtr GroupLayer = FLayerContainer::FindOrAdd(GroupNode->layer()); TSharedPtr BodyNode = MakeShared(GroupNode.GetName() + TEXT("_surf"), GroupLayer, ChildrenCount); TSharedPtr PatchMesh = MakeShared(GroupNode.GetName() + TEXT("_mesh"), GroupLayer, ChildrenCount); for(FAlDagNodePtr& Child : Children) { if (TSharedPtr ActorElement = ProcessGroupNode(Child, GroupLayer)) { ChildActors.Emplace(MoveTemp(ActorElement)); } else if (Child.IsAMesh()) { PatchMesh->AddMeshNode(Child); } else if (Child.IsASurface() || Child.IsAShell()) { BodyNode->AddNode(Child); } } if (ChildActors.IsEmpty() && !BodyNode->Initialize() && !PatchMesh->Initialize()) { return TSharedPtr(); } if (TSharedPtr ActorElement = ProcessBodyNode(BodyNode, GroupNode, GroupLayer)) { if (OpenModelUtils::ActorHasContent(ActorElement)) { ChildActors.Emplace(MoveTemp(ActorElement)); } } if (TSharedPtr ActorElement = ProcessPatchMesh(PatchMesh, GroupNode, GroupLayer)) { if (OpenModelUtils::ActorHasContent(ActorElement)) { ChildActors.Emplace(MoveTemp(ActorElement)); } } if (ChildActors.Num() == 0) { return TSharedPtr(); } TSharedPtr ActorElement; if (WireSettings.bMergeGeometryByGroup && ChildActors.Num() == 1) { ActorElement = ChildActors[0]; } else { ActorElement = FDatasmithSceneFactory::CreateActor(*GroupNode.GetUniqueID(GROUPNODE_TYPE)); } if (!ActorElement.IsValid()) { return ActorElement; } FString Label = GroupNode.GetName(); ActorElement->SetLabel(Label.Len() > 0 ? *Label : TEXT("UnnamedGroup")); FString CsvLayerString; if (OpenModelUtils::GetCsvLayerString(GroupLayer, CsvLayerString)) { ActorElement->SetLayer(*CsvLayerString); } if (WireSettings.bMergeGeometryByGroup && ChildActors.Num() > 1) { GroupNode.SetActorTransform(*ActorElement); for (TSharedPtr& ChildActor : ChildActors) { if (OpenModelUtils::ActorHasContent(ChildActor)) { ActorElement->AddChild(ChildActor); } } } if (WireSettings.bUseLayerAsActor && GroupLayer != ParentLayer) { if (OpenModelUtils::ActorHasContent(ActorElement)) { if (TSharedPtr LayerActor = FindOrAddLayerActor(GroupLayer)) { LayerActor->AddChild(ActorElement); } } return TSharedPtr(); } return ActorElement; } TSharedPtr FWireTranslatorImpl::ProcessGeometryNode(const FAlDagNodePtr& GeomNode, const TAlObjectPtr& ParentLayer) { const TAlObjectPtr& Layer = GeomNode.GetLayer(); if (Layer && Layer->invisible()) { return TSharedPtr(); } TSharedPtr MeshElement = FindOrAddMeshElement(GeomNode); if (!MeshElement.IsValid()) { return TSharedPtr(); } TSharedPtr ActorElement = FDatasmithSceneFactory::CreateMeshActor(*GeomNode.GetUniqueID(MESHNODE_TYPE)); if (!ActorElement.IsValid()) { return TSharedPtr(); } FString Label = GeomNode.GetName(); ActorElement->SetLabel(Label.Len() > 0 ? *Label : TEXT("NoName")); ActorElement->SetStaticMeshPathName(MeshElement->GetName()); FString CsvLayerString; if (OpenModelUtils::GetCsvLayerString(Layer, CsvLayerString)) { ActorElement->SetLayer(*CsvLayerString); } GeomNode.SetActorTransform(*ActorElement); if (WireSettings.bUseLayerAsActor && Layer != ParentLayer) { if (TSharedPtr LayerActor = FindOrAddLayerActor(Layer)) { LayerActor->AddChild(ActorElement); return TSharedPtr(); } ensureWire(false); } return ActorElement; } TSharedPtr FWireTranslatorImpl::ProcessBodyNode(TSharedPtr& BodyNode, const FAlDagNodePtr& GroupNode, const TAlObjectPtr& ParentLayer) { if (!BodyNode->HasContent()) { return TSharedPtr(); } FAlDagNodePtr Singleton; if (BodyNode->GetSingleContent(Singleton)) { return ProcessGeometryNode(Singleton, ParentLayer); } TSharedPtr MeshElement = FindOrAddMeshElement(BodyNode); if (!MeshElement.IsValid()) { return TSharedPtr(); } TSharedPtr ActorElement = FDatasmithSceneFactory::CreateMeshActor(*BodyNode->GetUniqueID()); if (!ActorElement.IsValid()) { return TSharedPtr(); } FString Label = BodyNode->GetName(); ActorElement->SetLabel(Label.Len() > 0 ? *Label : TEXT("NoName")); ActorElement->SetStaticMeshPathName(MeshElement->GetName()); FString CsvLayerString; if (OpenModelUtils::GetCsvLayerString(BodyNode->GetLayer(), CsvLayerString)) { ActorElement->SetLayer(*CsvLayerString); } if (BodyNode->GetLayer() && !BodyNode->GetLayer()->isSymmetric()) { GroupNode.SetActorTransform(*ActorElement); } if (WireSettings.bUseLayerAsActor && BodyNode->GetLayer() != ParentLayer) { if (TSharedPtr LayerActor = FindOrAddLayerActor(BodyNode->GetLayer())) { LayerActor->AddChild(ActorElement); return TSharedPtr(); } ensureWire(false); } return ActorElement; } TSharedPtr FWireTranslatorImpl::ProcessPatchMesh(TSharedPtr& PatchMesh, const FAlDagNodePtr& GroupNode, const TAlObjectPtr& ParentLayer) { if (!PatchMesh->HasContent()) { return TSharedPtr(); } if (!GroupNode.IsVisible()) { return TSharedPtr(); } FAlDagNodePtr Singleton; if (PatchMesh->GetSingleContent(Singleton)) { return ProcessGeometryNode(Singleton, ParentLayer); } TSharedPtr MeshElement = FindOrAddMeshElement(PatchMesh); if (!MeshElement.IsValid()) { return TSharedPtr(); } TSharedPtr ActorElement = FDatasmithSceneFactory::CreateMeshActor(*PatchMesh->GetUniqueID()); if (!ActorElement.IsValid()) { return TSharedPtr(); } FString Label = PatchMesh->GetName(); ActorElement->SetLabel(Label.Len() > 0 ? *Label : TEXT("NoName")); ActorElement->SetStaticMeshPathName(MeshElement->GetName()); FString CsvLayerString; if (OpenModelUtils::GetCsvLayerString(PatchMesh->GetLayer(), CsvLayerString)) { ActorElement->SetLayer(*CsvLayerString); } GroupNode.SetActorTransform(*ActorElement); if (WireSettings.bUseLayerAsActor && PatchMesh->GetLayer() != ParentLayer) { if (TSharedPtr LayerActor = FindOrAddLayerActor(PatchMesh->GetLayer())) { LayerActor->AddChild(ActorElement); return TSharedPtr(); } ensureWire(false); } return ActorElement; } TSharedPtr FWireTranslatorImpl::FindOrAddMeshElement(const FAlDagNodePtr& GeomNode) { // Look if geometry has not been already processed, return it if found if (TSharedPtr* MeshElementPtr = GeomNodeToMeshElement.Find(GeomNode.GetHash())) { return *MeshElementPtr; } if (!GeomNode.HasGeometry()) { // #wire_import: Log an error return TSharedPtr(); } TSharedPtr MeshElement = FDatasmithSceneFactory::CreateMesh(*GeomNode.GetUniqueID(MESH_TYPE)); MeshElement->SetLabel(*GeomNode.GetName()); MeshElement->SetLightmapSourceUV(-1); #if TRACK_MESHELEMENT { if (!ToTrack.Equals(MeshElement->GetLabel())) { return TSharedPtr(); } } #endif auto ApplyMaterial = [this, &MeshElement](const TAlObjectPtr& Shader, int32 SlotIndex) { if (TSharedPtr MaterialElement = this->FindOrAddMaterial(Shader)) { MeshElement->SetMaterial(MaterialElement->GetName(), SlotIndex); } }; TAlObjectPtr Shell; if (GeomNode.GetShell(Shell)) { TAlObjectPtr Shader(Shell->firstShader()); int32 SlotIndex = 0; while (Shader) { ApplyMaterial(Shader, SlotIndex++); Shader = Shell->nextShader(Shader.Get()); } // #wire_import: Check There are as many shaders as trim regions MeshElementToParametricNode.Add(MeshElement, GeomNode); } else { TAlObjectPtr Surface; if (GeomNode.GetSurface(Surface)) { // #wire_import: Check for trim regions ApplyMaterial(Surface->firstShader(), 0); MeshElementToParametricNode.Add(MeshElement, GeomNode); } else { TAlObjectPtr Mesh; if (GeomNode.GetMesh(Mesh)) { ApplyMaterial(Mesh->firstShader(), 0); MeshElementToMeshNode.Add(MeshElement, GeomNode); } else { // #wire_import: Log an error return TSharedPtr(); } } } DatasmithScene->AddMesh(MeshElement); GeomNodeToMeshElement.Add(GeomNode.GetHash(), MeshElement); return MeshElement; } TSharedPtr FWireTranslatorImpl::FindOrAddMeshElement(TSharedPtr& BodyNode) { // Look if geometry has not been already processed, return it if found if (TSharedPtr* MeshElementPtr = BodyNodeToMeshElement.Find(BodyNode->GetHash())) { return *MeshElementPtr; } if (!BodyNode->HasContent()) { // #wire_import: Log an error return TSharedPtr(); } TSharedPtr MeshElement = FDatasmithSceneFactory::CreateMesh(*BodyNode->GetUniqueID()); MeshElement->SetLabel(*BodyNode->GetName()); MeshElement->SetLightmapSourceUV(-1); #if TRACK_MESHELEMENT { if (!ToTrack.Equals(MeshElement->GetLabel())) { return TSharedPtr(); } } #endif auto ApplyMaterial = [this, &MeshElement](int32 SlotIndex, const TAlObjectPtr& Shader) { if (TSharedPtr MaterialElement = this->FindOrAddMaterial(Shader)) { MeshElement->SetMaterial(MaterialElement->GetName(), SlotIndex); } }; BodyNode->IterateOnSlotIndices(ApplyMaterial); DatasmithScene->AddMesh(MeshElement); BodyNodeToMeshElement.Add(BodyNode->GetHash(), MeshElement); MeshElementToBodyNode.Add(MeshElement, BodyNode); return MeshElement; } TSharedPtr FWireTranslatorImpl::FindOrAddMeshElement(TSharedPtr& PatchMesh) { // Look if geometry has not been already processed, return it if found if (TSharedPtr* MeshElementPtr = PatchMeshToMeshElement.Find(PatchMesh->GetHash())) { return *MeshElementPtr; } if (!PatchMesh->HasContent()) { // #wire_import: Log an error return TSharedPtr(); } TSharedPtr MeshElement = FDatasmithSceneFactory::CreateMesh(*PatchMesh->GetUniqueID()); MeshElement->SetLabel(*PatchMesh->GetName()); MeshElement->SetLightmapSourceUV(-1); #if TRACK_MESHELEMENT { if (!ToTrack.Equals(MeshElement->GetLabel())) { return TSharedPtr(); } } #endif auto ApplyMaterial = [this, &MeshElement](const TAlObjectPtr& Shader, int32 SlotIndex) { if (TSharedPtr MaterialElement = this->FindOrAddMaterial(Shader)) { MeshElement->SetMaterial(MaterialElement->GetName(), SlotIndex); } }; int32 SlotIndex = 0; PatchMesh->IterateOnMeshNodes([&ApplyMaterial, &SlotIndex](const FAlDagNodePtr& MeshNode) { TAlObjectPtr Mesh; if (MeshNode.GetMesh(Mesh)) { ApplyMaterial(Mesh->firstShader(), SlotIndex++); } }); DatasmithScene->AddMesh(MeshElement); BodyNodeToMeshElement.Add(PatchMesh->GetHash(), MeshElement); MeshElementToPatchMesh.Add(MeshElement, PatchMesh); return MeshElement; } TSharedPtr FWireTranslatorImpl::FindOrAddLayerActor(const TAlObjectPtr& Layer) { if (!WireSettings.bUseLayerAsActor || !Layer || Layer.GetName().IsEmpty()) { return TSharedPtr(); } TSharedPtr* LayerActorPtr = LayerToActor.Find(Layer.GetHash()); if (LayerActorPtr) { return *LayerActorPtr; } TSharedPtr ParentLayerActor; TAlObjectPtr ParentLayer = FLayerContainer::FindOrAdd(Layer->parentLayer()); if (ParentLayer) { ParentLayerActor = FindOrAddLayerActor(ParentLayer); } TSharedPtr LayerActor = FDatasmithSceneFactory::CreateActor(*Layer.GetUniqueID(LAYER_TYPE)); FString LayerName = Layer.GetName(); LayerActor->SetLabel(*LayerName); FString CsvLayerString; if (OpenModelUtils::GetCsvLayerString(Layer, CsvLayerString)) { LayerActor->SetLayer(*CsvLayerString); } if (ParentLayerActor) { ParentLayerActor->AddChild(LayerActor); } else { DatasmithScene->AddActor(LayerActor); } LayerToActor.Add(Layer.GetHash(), LayerActor); return LayerActor; } // Geometry retrieval bool FWireTranslatorImpl::LoadStaticMesh(const TSharedPtr MeshElement, FDatasmithMeshElementPayload& OutMeshPayload, const FDatasmithTessellationOptions& InTessellationOptions) { CADLibrary::FMeshParameters MeshParameters; #if WIRE_MEMORY_CHECK int32 PrevAllocatedObjects = AllocatedObjects; #endif if (TOptional Mesh = GetMeshDescription(MeshElement, MeshParameters)) { #if TRACK_MESHELEMENT FMeshDescription& MeshDescription = OutMeshPayload.LodMeshes.Add_GetRef(MoveTemp(Mesh.GetValue())); MakeMeshVisible(MeshDescription); #else OutMeshPayload.LodMeshes.Add(MoveTemp(Mesh.GetValue())); #endif const TCHAR* MeshFilename = MeshElement->GetFile(); if (!WireSettings.bAliasUseNative && FPaths::FileExists(MeshFilename)) { CADModelConverter->AddSurfaceDataForMesh(MeshFilename, MeshParameters, InTessellationOptions, OutMeshPayload); // Remove the file because it is temporary since caching is disabled. if (!CADLibrary::FImportParameters::bGEnableCADCache) { IFileManager::Get().Delete(MeshFilename); } } #if WIRE_MEMORY_CHECK ensure(PrevAllocatedObjects == AllocatedObjects); #endif return true; } return false; } TOptional FWireTranslatorImpl::GetMeshDescription(TSharedPtr MeshElement, CADLibrary::FMeshParameters& OutMeshParameters) { if (WireSettings.bAliasUseNative) { if (FAlDagNodePtr* GeomNodePtr = MeshElementToParametricNode.Find(MeshElement)) { FAlDagNodePtr& GeomNode = *GeomNodePtr; // #wire_import: Check whether parametric geometry with symmetry keeps the symmetry // #wire_import: the best way, should be to don't have to apply inverse global transform to the generated mesh FAlDagNodePtr MeshNode = OpenModelUtils::TesselateDagLeaf(*GeomNode, ETesselatorType::Fast, WireSettings.ChordTolerance); TAlObjectPtr Mesh; if (MeshNode.GetMesh(Mesh)) { AlMatrix4x4 AlMatrix; GeomNode->inverseGlobalTransformationMatrix(AlMatrix); Mesh->transform(AlMatrix); // Get the meshes from the dag nodes. Note that removing the mesh's DAG. // will also removes the meshes, so we have to do it later. return GetMeshDescriptionFromMeshNode(MeshNode, MeshElement, OutMeshParameters); } } if (FAlDagNodePtr* MeshNodePtr = MeshElementToMeshNode.Find(MeshElement)) { FAlDagNodePtr MeshNode = *MeshNodePtr; if (MeshNode) { return GetMeshDescriptionFromMeshNode(MeshNode, MeshElement, OutMeshParameters); } } return TOptional(); } if (TSharedPtr* BodyNodePtr = MeshElementToBodyNode.Find(MeshElement)) { return GetMeshDescriptionFromBodyNode(*BodyNodePtr, MeshElement, OutMeshParameters); } if (FAlDagNodePtr* GeomNodePtr = MeshElementToParametricNode.Find(MeshElement)) { return GetMeshDescriptionFromParametricNode(*GeomNodePtr, MeshElement, OutMeshParameters); } if (TSharedPtr* PatchMeshPtr = MeshElementToPatchMesh.Find(MeshElement)) { return GetMeshDescriptionFromPatchMesh(*PatchMeshPtr, MeshElement, OutMeshParameters); } if (FAlDagNodePtr* MeshNodePtr = MeshElementToMeshNode.Find(MeshElement)) { return GetMeshDescriptionFromMeshNode(*MeshNodePtr, MeshElement, OutMeshParameters); } return TOptional(); } TOptional FWireTranslatorImpl::GetMeshDescriptionFromBodyNode(TSharedPtr& BodyNode, TSharedPtr MeshElement, CADLibrary::FMeshParameters& OutMeshParameters) { OutMeshParameters = OpenModelUtils::GetMeshParameters(BodyNode->GetLayer()); TSharedPtr ModelConverter = GetModelConverter(); ModelConverter->InitializeProcess(); EAliasObjectReference ObjectReference = EAliasObjectReference::LocalReference; if (OutMeshParameters.bIsSymmetric) { // All actors of a Alias symmetric layer are defined in the world Reference i.e. they have identity transform. So Mesh actor has to be defined in the world reference. ObjectReference = EAliasObjectReference::WorldReference; } else if (WireSettings.bMergeGeometryByGroup) { // In the case of StitchingSew, AlDagNode children of a GroupNode are merged together. To be merged, they have to be defined in the reference of parent GroupNode. ObjectReference = EAliasObjectReference::ParentReference; } const FBodyNodeGeometry BodyNodeGeometry( (int32)ECADModelGeometryType::BodyNode, ObjectReference, BodyNode); ModelConverter->AddGeometry(BodyNodeGeometry); ModelConverter->RepairTopology(); ModelConverter->SaveModel(*OutputPath, MeshElement); FMeshDescription MeshDescription; DatasmithMeshHelper::PrepareAttributeForStaticMesh(MeshDescription); if (ModelConverter->Tessellate(OutMeshParameters, MeshDescription)) { return TOptional(MoveTemp(MeshDescription)); } const TCHAR* StaticMeshLabel = MeshElement->GetLabel(); const TCHAR* StaticMeshName = MeshElement->GetName(); UE_LOG(LogWireInterface, Warning, TEXT("Failed to generate the mesh of \"%s\" (%s) StaticMesh."), StaticMeshLabel, StaticMeshName); return TOptional(); } TOptional FWireTranslatorImpl::GetMeshDescriptionFromPatchMesh(TSharedPtr& PatchMesh, TSharedPtr MeshElement, CADLibrary::FMeshParameters& OutMeshParameters) { OutMeshParameters = OpenModelUtils::GetMeshParameters(PatchMesh->GetLayer()); FMeshDescription MeshDescription; DatasmithMeshHelper::PrepareAttributeForStaticMesh(MeshDescription); MeshDescription.Empty(); constexpr bool bMerge = true; int32 SlotIndex = 0; PatchMesh->IterateOnMeshNodes([&](const FAlDagNodePtr& MeshNode) { TAlObjectPtr Mesh; if (MeshNode.GetMesh(Mesh)) { AlMatrix4x4 AlMatrix; if (OutMeshParameters.bIsSymmetric) { MeshNode->globalTransformationMatrix(AlMatrix); } else { MeshNode->localTransformationMatrix(AlMatrix); } Mesh->transform(AlMatrix); const FString SlotMaterialName = DatasmithMeshHelper::DefaultSlotName(SlotIndex++).ToString(); OpenModelUtils::TransferAlMeshToMeshDescription(*Mesh, *SlotMaterialName, MeshDescription, OutMeshParameters, bMerge); } }); // Build edge meta data FStaticMeshOperations::DetermineEdgeHardnessesFromVertexInstanceNormals(MeshDescription); return MoveTemp(MeshDescription); } // #wire_import: AlSurfaceNode can have trim regions. This should be handle at this stage TOptional FWireTranslatorImpl::GetMeshDescriptionFromParametricNode(const FAlDagNodePtr& DagNode, TSharedPtr MeshElement, CADLibrary::FMeshParameters& OutMeshParameters) { OutMeshParameters = OpenModelUtils::GetMeshParameters(DagNode.GetLayer()); TSharedPtr ModelConverter = GetModelConverter(); ModelConverter->InitializeProcess(); EAliasObjectReference ObjectReference = EAliasObjectReference::LocalReference; // All geometry are processed in world space if layers are converted to actors // All actors of a Alias symmetric layer are defined in the world Reference // i.e. they have identity transform. So Mesh actor has to be defined in the world reference. if (OutMeshParameters.bIsSymmetric) { ObjectReference = EAliasObjectReference::WorldReference; } ensureWire(MeshElement->GetMaterialSlotCount() == 1); const FDagNodeGeometry DagNodeGeometry( (int32)ECADModelGeometryType::DagNode, ObjectReference, DagNode ); if (!ModelConverter->AddGeometry(DagNodeGeometry)) { return TOptional(); } ModelConverter->RepairTopology(); ModelConverter->SaveModel(*OutputPath, MeshElement); FMeshDescription MeshDescription; DatasmithMeshHelper::PrepareAttributeForStaticMesh(MeshDescription); OutMeshParameters = DagNode.GetMeshParameters(); if (ModelConverter->Tessellate(OutMeshParameters, MeshDescription)) { return TOptional(MoveTemp(MeshDescription)); } const TCHAR* StaticMeshLabel = MeshElement->GetLabel(); const TCHAR* StaticMeshName = MeshElement->GetName(); UE_LOG(LogWireInterface, Warning, TEXT("Failed to generate the mesh of \"%s\" (%s) StaticMesh."), StaticMeshLabel, StaticMeshName); return TOptional(); } TOptional FWireTranslatorImpl::GetMeshDescriptionFromMeshNode(const FAlDagNodePtr& MeshNode, TSharedPtr MeshElement, CADLibrary::FMeshParameters& OutMeshParameters) { if (!MeshNode) { return TOptional(); } TAlObjectPtr Mesh; if (!MeshNode.GetMesh(Mesh)) { return TOptional(); } OutMeshParameters = MeshNode.GetMeshParameters(); if (OutMeshParameters.bIsSymmetric) { AlMatrix4x4 AlGlobalMatrix; MeshNode->globalTransformationMatrix(AlGlobalMatrix); Mesh->transform(AlGlobalMatrix); } FMeshDescription MeshDescription; DatasmithMeshHelper::PrepareAttributeForStaticMesh(MeshDescription); const bool bMerge = false; OpenModelUtils::TransferAlMeshToMeshDescription(*Mesh, TEXT("0"), MeshDescription, OutMeshParameters, bMerge); // Build edge meta data FStaticMeshOperations::DetermineEdgeHardnessesFromVertexInstanceNormals(MeshDescription); return MoveTemp(MeshDescription); } TSharedPtr FWireTranslatorImpl::GetModelConverter() const { TSharedPtr ModelConverter; CADLibrary::FImportParameters ImportParameters; if (CADLibrary::FImportParameters::bGDisableCADKernelTessellation) { ModelConverter = MakeShared(ImportParameters); } else { ModelConverter = MakeShared(WireSettings, ImportParameters); } if (ModelConverter) { ModelConverter->SetImportParameters(WireSettings.ChordTolerance, WireSettings.MaxEdgeLength, WireSettings.NormalTolerance, (CADLibrary::EStitchingTechnique)WireSettings.StitchingTechnique); } return ModelConverter; } // Material creation TSharedPtr FWireTranslatorImpl::FindOrAddMaterial(const TAlObjectPtr& Shader) { const FString ShaderName = Shader.GetName(); if (TSharedPtr* MaterialElementPtr = ShaderNameToMaterial.Find(ShaderName)) { return *MaterialElementPtr; } const FString ShaderModelName = Shader->shadingModel(); TSharedPtr MaterialElement = FDatasmithSceneFactory::CreateUEPbrMaterial(*Shader.GetUniqueID(SHADER_TYPE)); MaterialElement->SetLabel(*ShaderName); if (ShaderModelName.Equals(TEXT("BLINN"))) { AddAlBlinnParameters(Shader, MaterialElement); } else if (ShaderModelName.Equals(TEXT("LAMBERT"))) { AddAlLambertParameters(Shader, MaterialElement); } else if (ShaderModelName.Equals(TEXT("LIGHTSOURCE"))) { AddAlLightSourceParameters(Shader, MaterialElement); } else if (ShaderModelName.Equals(TEXT("PHONG"))) { AddAlPhongParameters(Shader, MaterialElement); } DatasmithScene->AddMaterial(MaterialElement); ShaderNameToMaterial.Add(*ShaderName, MaterialElement); return MaterialElement; } bool FWireTranslatorImpl::GetCommonParameters(int32 Field, double Value, FColor& Color, FColor& TransparencyColor, FColor& IncandescenceColor, double GlowIntensity) { switch (AlShadingFields(Field)) { case AlShadingFields::kFLD_SHADING_COMMON_COLOR_R: Color.R = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_COLOR_G: Color.G = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_COLOR_B: Color.B = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_INCANDESCENCE_R: IncandescenceColor.R = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_INCANDESCENCE_G: IncandescenceColor.G = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_INCANDESCENCE_B: IncandescenceColor.B = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_TRANSPARENCY_R: TransparencyColor.R = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_TRANSPARENCY_G: TransparencyColor.G = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_TRANSPARENCY_B: TransparencyColor.B = (uint8)Value; return true; case AlShadingFields::kFLD_SHADING_COMMON_GLOW_INTENSITY: GlowIntensity = Value; return true; default: return false; } } void FWireTranslatorImpl::AddAlBlinnParameters(const TAlObjectPtr& Shader, TSharedPtr MaterialElement) { // Default values for a Blinn material FColor Color(145, 148, 153); FColor TransparencyColor(0, 0, 0); FColor IncandescenceColor(0, 0, 0); FColor SpecularColor(38, 38, 38); double Diffuse = 1.0; double GlowIntensity = 0.0; double Gloss = 0.8; double Eccentricity = 0.35; double Specularity = 1.0; double Reflectivity = 0.5; double SpecularRolloff = 0.5; AlList* List = Shader->fields(); for (AlShadingFieldItem* Item = static_cast(List->first()); Item; Item = Item->nextField()) { double Value = 0.0f; statusCode ErrorCode = Shader->parameter(Item->field(), Value); if (ErrorCode != 0) { continue; } if (GetCommonParameters(Item->field(), Value, Color, TransparencyColor, IncandescenceColor, GlowIntensity)) { continue; } switch (Item->field()) { case AlShadingFields::kFLD_SHADING_BLINN_DIFFUSE: Diffuse = Value; break; case AlShadingFields::kFLD_SHADING_BLINN_GLOSS_: Gloss = Value; break; case AlShadingFields::kFLD_SHADING_BLINN_SPECULAR_R: SpecularColor.R = (uint8)(255.f * Value); break; case AlShadingFields::kFLD_SHADING_BLINN_SPECULAR_G: SpecularColor.G = (uint8)(255.f * Value);; break; case AlShadingFields::kFLD_SHADING_BLINN_SPECULAR_B: SpecularColor.B = (uint8)(255.f * Value);; break; case AlShadingFields::kFLD_SHADING_BLINN_SPECULARITY_: Specularity = Value; break; case AlShadingFields::kFLD_SHADING_BLINN_SPECULAR_ROLLOFF: SpecularRolloff = Value; break; case AlShadingFields::kFLD_SHADING_BLINN_ECCENTRICITY: Eccentricity = Value; break; case AlShadingFields::kFLD_SHADING_BLINN_REFLECTIVITY: Reflectivity = Value; break; } } bool bIsTransparent = IsTransparent(TransparencyColor); // Construct parameter expressions IDatasmithMaterialExpressionScalar* DiffuseExpression = MaterialElement->AddMaterialExpression(); DiffuseExpression->GetScalar() = Diffuse; DiffuseExpression->SetName(TEXT("Diffuse")); IDatasmithMaterialExpressionScalar* GlossExpression = MaterialElement->AddMaterialExpression(); GlossExpression->GetScalar() = Gloss; GlossExpression->SetName(TEXT("Gloss")); IDatasmithMaterialExpressionColor* SpecularColorExpression = MaterialElement->AddMaterialExpression(); SpecularColorExpression->SetName(TEXT("SpecularColor")); SpecularColorExpression->GetColor() = FLinearColor::FromSRGBColor(SpecularColor); IDatasmithMaterialExpressionScalar* SpecularityExpression = MaterialElement->AddMaterialExpression(); SpecularityExpression->GetScalar() = Specularity * 0.3; SpecularityExpression->SetName(TEXT("Specularity")); IDatasmithMaterialExpressionScalar* SpecularRolloffExpression = MaterialElement->AddMaterialExpression(); SpecularRolloffExpression->GetScalar() = SpecularRolloff; SpecularRolloffExpression->SetName(TEXT("SpecularRolloff")); IDatasmithMaterialExpressionScalar* EccentricityExpression = MaterialElement->AddMaterialExpression(); EccentricityExpression->GetScalar() = Eccentricity; EccentricityExpression->SetName(TEXT("Eccentricity")); IDatasmithMaterialExpressionScalar* ReflectivityExpression = MaterialElement->AddMaterialExpression(); ReflectivityExpression->GetScalar() = Reflectivity; ReflectivityExpression->SetName(TEXT("Reflectivity")); IDatasmithMaterialExpressionColor* ColorExpression = MaterialElement->AddMaterialExpression(); ColorExpression->SetName(TEXT("Color")); ColorExpression->GetColor() = FLinearColor::FromSRGBColor(Color); IDatasmithMaterialExpressionColor* IncandescenceColorExpression = MaterialElement->AddMaterialExpression(); IncandescenceColorExpression->SetName(TEXT("IncandescenceColor")); IncandescenceColorExpression->GetColor() = FLinearColor::FromSRGBColor(IncandescenceColor); IDatasmithMaterialExpressionColor* TransparencyColorExpression = MaterialElement->AddMaterialExpression(); TransparencyColorExpression->SetName(TEXT("TransparencyColor")); TransparencyColorExpression->GetColor() = FLinearColor::FromSRGBColor(TransparencyColor); IDatasmithMaterialExpressionScalar* GlowIntensityExpression = MaterialElement->AddMaterialExpression(); GlowIntensityExpression->GetScalar() = GlowIntensity; GlowIntensityExpression->SetName(TEXT("GlowIntensity")); // Create aux expressions IDatasmithMaterialExpressionGeneric* ColorSpecLerp = MaterialElement->AddMaterialExpression(); ColorSpecLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionScalar* ColorSpecLerpValue = MaterialElement->AddMaterialExpression(); ColorSpecLerpValue->GetScalar() = 0.96f; IDatasmithMaterialExpressionGeneric* ColorMetallicLerp = MaterialElement->AddMaterialExpression(); ColorMetallicLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionGeneric* DiffuseLerp = MaterialElement->AddMaterialExpression(); DiffuseLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionScalar* DiffuseLerpA = MaterialElement->AddMaterialExpression(); DiffuseLerpA->GetScalar() = 0.04f; IDatasmithMaterialExpressionScalar* DiffuseLerpB = MaterialElement->AddMaterialExpression(); DiffuseLerpB->GetScalar() = 1.0f; IDatasmithMaterialExpressionGeneric* BaseColorMultiply = MaterialElement->AddMaterialExpression(); BaseColorMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* BaseColorAdd = MaterialElement->AddMaterialExpression(); BaseColorAdd->SetExpressionName(TEXT("Add")); IDatasmithMaterialExpressionGeneric* BaseColorTransparencyMultiply = MaterialElement->AddMaterialExpression(); BaseColorTransparencyMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceMultiply = MaterialElement->AddMaterialExpression(); IncandescenceMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceScaleMultiply = MaterialElement->AddMaterialExpression(); IncandescenceScaleMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionScalar* IncandescenceScale = MaterialElement->AddMaterialExpression(); IncandescenceScale->GetScalar() = 100.0f; IDatasmithMaterialExpressionGeneric* EccentricityMultiply = MaterialElement->AddMaterialExpression(); EccentricityMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* EccentricityOneMinus = MaterialElement->AddMaterialExpression(); EccentricityOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionGeneric* RoughnessOneMinus = MaterialElement->AddMaterialExpression(); RoughnessOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionScalar* FresnelExponent = MaterialElement->AddMaterialExpression(); FresnelExponent->GetScalar() = 4.0f; IDatasmithMaterialExpressionFunctionCall* FresnelFunc = MaterialElement->AddMaterialExpression(); FresnelFunc->SetFunctionPathName(TEXT("/Engine/Functions/Engine_MaterialFunctions02/Fresnel_Function.Fresnel_Function")); IDatasmithMaterialExpressionGeneric* FresnelLerp = MaterialElement->AddMaterialExpression(); FresnelLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionScalar* FresnelLerpA = MaterialElement->AddMaterialExpression(); FresnelLerpA->GetScalar() = 1.0f; IDatasmithMaterialExpressionScalar* SpecularPowerExp = MaterialElement->AddMaterialExpression(); SpecularPowerExp->GetScalar() = 0.5f; IDatasmithMaterialExpressionGeneric* Power = MaterialElement->AddMaterialExpression(); Power->SetExpressionName(TEXT("Power")); IDatasmithMaterialExpressionGeneric* FresnelMultiply = MaterialElement->AddMaterialExpression(); FresnelMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* TransparencyOneMinus = MaterialElement->AddMaterialExpression(); TransparencyOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionFunctionCall* BreakFloat3 = nullptr; IDatasmithMaterialExpressionGeneric* AddRG = nullptr; IDatasmithMaterialExpressionGeneric* AddRGB = nullptr; IDatasmithMaterialExpressionGeneric* Divide = nullptr; IDatasmithMaterialExpressionScalar* DivideConstant = nullptr; if (bIsTransparent) { BreakFloat3 = MaterialElement->AddMaterialExpression(); BreakFloat3->SetFunctionPathName(TEXT("/Engine/Functions/Engine_MaterialFunctions02/Utility/BreakFloat3Components.BreakFloat3Components")); AddRG = MaterialElement->AddMaterialExpression(); AddRG->SetExpressionName(TEXT("Add")); AddRGB = MaterialElement->AddMaterialExpression(); AddRGB->SetExpressionName(TEXT("Add")); Divide = MaterialElement->AddMaterialExpression(); Divide->SetExpressionName(TEXT("Divide")); DivideConstant = MaterialElement->AddMaterialExpression(); DivideConstant->GetScalar() = 3.0f; } // Connect expressions SpecularColorExpression->ConnectExpression(*ColorSpecLerp->GetInput(0)); ColorExpression->ConnectExpression(*ColorSpecLerp->GetInput(1)); ColorSpecLerpValue->ConnectExpression(*ColorSpecLerp->GetInput(2)); ColorExpression->ConnectExpression(*ColorMetallicLerp->GetInput(0)); ColorSpecLerp->ConnectExpression(*ColorMetallicLerp->GetInput(1)); GlossExpression->ConnectExpression(*ColorMetallicLerp->GetInput(2)); DiffuseLerpA->ConnectExpression(*DiffuseLerp->GetInput(0)); DiffuseLerpB->ConnectExpression(*DiffuseLerp->GetInput(1)); DiffuseExpression->ConnectExpression(*DiffuseLerp->GetInput(2)); ColorMetallicLerp->ConnectExpression(*BaseColorMultiply->GetInput(0)); DiffuseLerp->ConnectExpression(*BaseColorMultiply->GetInput(1)); BaseColorMultiply->ConnectExpression(*BaseColorAdd->GetInput(0)); IncandescenceColorExpression->ConnectExpression(*BaseColorAdd->GetInput(1)); BaseColorAdd->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(0)); TransparencyOneMinus->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(1)); GlowIntensityExpression->ConnectExpression(*IncandescenceScaleMultiply->GetInput(0)); IncandescenceScale->ConnectExpression(*IncandescenceScaleMultiply->GetInput(1)); BaseColorTransparencyMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(0)); IncandescenceScaleMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(1)); EccentricityExpression->ConnectExpression(*EccentricityOneMinus->GetInput(0)); EccentricityOneMinus->ConnectExpression(*EccentricityMultiply->GetInput(0)); SpecularityExpression->ConnectExpression(*EccentricityMultiply->GetInput(1)); EccentricityMultiply->ConnectExpression(*RoughnessOneMinus->GetInput(0)); FresnelExponent->ConnectExpression(*FresnelFunc->GetInput(3)); SpecularRolloffExpression->ConnectExpression(*Power->GetInput(0)); SpecularPowerExp->ConnectExpression(*Power->GetInput(1)); FresnelLerpA->ConnectExpression(*FresnelLerp->GetInput(0)); FresnelFunc->ConnectExpression(*FresnelLerp->GetInput(1)); Power->ConnectExpression(*FresnelLerp->GetInput(2)); FresnelLerp->ConnectExpression(*FresnelMultiply->GetInput(0)); ReflectivityExpression->ConnectExpression(*FresnelMultiply->GetInput(1)); TransparencyColorExpression->ConnectExpression(*TransparencyOneMinus->GetInput(0)); if (bIsTransparent) { TransparencyOneMinus->ConnectExpression(*BreakFloat3->GetInput(0)); BreakFloat3->ConnectExpression(*AddRG->GetInput(0), 0); BreakFloat3->ConnectExpression(*AddRG->GetInput(1), 1); AddRG->ConnectExpression(*AddRGB->GetInput(0)); BreakFloat3->ConnectExpression(*AddRGB->GetInput(1), 2); AddRGB->ConnectExpression(*Divide->GetInput(0)); DivideConstant->ConnectExpression(*Divide->GetInput(1)); } // Connect material outputs MaterialElement->GetBaseColor().SetExpression(BaseColorTransparencyMultiply); MaterialElement->GetMetallic().SetExpression(GlossExpression); MaterialElement->GetSpecular().SetExpression(FresnelMultiply); MaterialElement->GetRoughness().SetExpression(RoughnessOneMinus); MaterialElement->GetEmissiveColor().SetExpression(IncandescenceMultiply); if (bIsTransparent) { MaterialElement->GetOpacity().SetExpression(Divide); MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasBlinnTransparent")); } else { MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasBlinn")); } } void FWireTranslatorImpl::AddAlLambertParameters(const TAlObjectPtr& Shader, TSharedPtr MaterialElement) { // Default values for a Lambert material FColor Color(145, 148, 153); FColor TransparencyColor(0, 0, 0); FColor IncandescenceColor(0, 0, 0); double Diffuse = 1.0; double GlowIntensity = 0.0; AlList* List = Shader->fields(); for (AlShadingFieldItem* Item = static_cast(List->first()); Item; Item = Item->nextField()) { double Value = 0.0f; statusCode ErrorCode = Shader->parameter(Item->field(), Value); if (ErrorCode != 0) { continue; } if (GetCommonParameters(Item->field(), Value, Color, TransparencyColor, IncandescenceColor, GlowIntensity)) { continue; } switch (Item->field()) { case AlShadingFields::kFLD_SHADING_LAMBERT_DIFFUSE: Diffuse = Value; break; } } bool bIsTransparent = IsTransparent(TransparencyColor); // Construct parameter expressions IDatasmithMaterialExpressionScalar* DiffuseExpression = MaterialElement->AddMaterialExpression(); DiffuseExpression->GetScalar() = Diffuse; DiffuseExpression->SetName(TEXT("Diffuse")); IDatasmithMaterialExpressionColor* ColorExpression = MaterialElement->AddMaterialExpression(); ColorExpression->SetName(TEXT("Color")); ColorExpression->GetColor() = FLinearColor::FromSRGBColor(Color); IDatasmithMaterialExpressionColor* IncandescenceColorExpression = MaterialElement->AddMaterialExpression(); IncandescenceColorExpression->SetName(TEXT("IncandescenceColor")); IncandescenceColorExpression->GetColor() = FLinearColor::FromSRGBColor(IncandescenceColor); IDatasmithMaterialExpressionColor* TransparencyColorExpression = MaterialElement->AddMaterialExpression(); TransparencyColorExpression->SetName(TEXT("TransparencyColor")); TransparencyColorExpression->GetColor() = FLinearColor::FromSRGBColor(TransparencyColor); IDatasmithMaterialExpressionScalar* GlowIntensityExpression = MaterialElement->AddMaterialExpression(); GlowIntensityExpression->GetScalar() = GlowIntensity; GlowIntensityExpression->SetName(TEXT("GlowIntensity")); // Create aux expressions IDatasmithMaterialExpressionGeneric* DiffuseLerp = MaterialElement->AddMaterialExpression(); DiffuseLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionScalar* DiffuseLerpA = MaterialElement->AddMaterialExpression(); DiffuseLerpA->GetScalar() = 0.04f; IDatasmithMaterialExpressionScalar* DiffuseLerpB = MaterialElement->AddMaterialExpression(); DiffuseLerpB->GetScalar() = 1.0f; IDatasmithMaterialExpressionGeneric* BaseColorMultiply = MaterialElement->AddMaterialExpression(); BaseColorMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* BaseColorAdd = MaterialElement->AddMaterialExpression(); BaseColorAdd->SetExpressionName(TEXT("Add")); IDatasmithMaterialExpressionGeneric* BaseColorTransparencyMultiply = MaterialElement->AddMaterialExpression(); BaseColorTransparencyMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceMultiply = MaterialElement->AddMaterialExpression(); IncandescenceMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceScaleMultiply = MaterialElement->AddMaterialExpression(); IncandescenceScaleMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionScalar* IncandescenceScale = MaterialElement->AddMaterialExpression(); IncandescenceScale->GetScalar() = 100.0f; IDatasmithMaterialExpressionGeneric* TransparencyOneMinus = MaterialElement->AddMaterialExpression(); TransparencyOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionFunctionCall* BreakFloat3 = nullptr; IDatasmithMaterialExpressionGeneric* AddRG = nullptr; IDatasmithMaterialExpressionGeneric* AddRGB = nullptr; IDatasmithMaterialExpressionGeneric* Divide = nullptr; IDatasmithMaterialExpressionScalar* DivideConstant = nullptr; if (bIsTransparent) { BreakFloat3 = MaterialElement->AddMaterialExpression(); BreakFloat3->SetFunctionPathName(TEXT("/Engine/Functions/Engine_MaterialFunctions02/Utility/BreakFloat3Components.BreakFloat3Components")); AddRG = MaterialElement->AddMaterialExpression(); AddRG->SetExpressionName(TEXT("Add")); AddRGB = MaterialElement->AddMaterialExpression(); AddRGB->SetExpressionName(TEXT("Add")); Divide = MaterialElement->AddMaterialExpression(); Divide->SetExpressionName(TEXT("Divide")); DivideConstant = MaterialElement->AddMaterialExpression(); DivideConstant->GetScalar() = 3.0f; } // Connect expressions DiffuseLerpA->ConnectExpression(*DiffuseLerp->GetInput(0)); DiffuseLerpB->ConnectExpression(*DiffuseLerp->GetInput(1)); DiffuseExpression->ConnectExpression(*DiffuseLerp->GetInput(2)); ColorExpression->ConnectExpression(*BaseColorMultiply->GetInput(0)); DiffuseLerp->ConnectExpression(*BaseColorMultiply->GetInput(1)); BaseColorMultiply->ConnectExpression(*BaseColorAdd->GetInput(0)); IncandescenceColorExpression->ConnectExpression(*BaseColorAdd->GetInput(1)); BaseColorAdd->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(0)); TransparencyOneMinus->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(1)); GlowIntensityExpression->ConnectExpression(*IncandescenceScaleMultiply->GetInput(0)); IncandescenceScale->ConnectExpression(*IncandescenceScaleMultiply->GetInput(1)); BaseColorTransparencyMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(0)); IncandescenceScaleMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(1)); TransparencyColorExpression->ConnectExpression(*TransparencyOneMinus->GetInput(0)); if (bIsTransparent) { TransparencyOneMinus->ConnectExpression(*BreakFloat3->GetInput(0)); BreakFloat3->ConnectExpression(*AddRG->GetInput(0), 0); BreakFloat3->ConnectExpression(*AddRG->GetInput(1), 1); AddRG->ConnectExpression(*AddRGB->GetInput(0)); BreakFloat3->ConnectExpression(*AddRGB->GetInput(1), 2); AddRGB->ConnectExpression(*Divide->GetInput(0)); DivideConstant->ConnectExpression(*Divide->GetInput(1)); } // Connect material outputs MaterialElement->GetBaseColor().SetExpression(BaseColorTransparencyMultiply); MaterialElement->GetEmissiveColor().SetExpression(IncandescenceMultiply); if (bIsTransparent) { MaterialElement->GetOpacity().SetExpression(Divide); MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasLambertTransparent")); } else { MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasLambert")); } } void FWireTranslatorImpl::AddAlLightSourceParameters(const TAlObjectPtr& Shader, TSharedPtr MaterialElement) { // Default values for a LightSource material FColor Color(145, 148, 153); FColor TransparencyColor(0, 0, 0); FColor IncandescenceColor(0, 0, 0); double GlowIntensity = 0.0; AlList* List = Shader->fields(); for (AlShadingFieldItem* Item = static_cast(List->first()); Item; Item = Item->nextField()) { double Value = 0.0f; statusCode ErrorCode = Shader->parameter(Item->field(), Value); if (ErrorCode != 0) { continue; } GetCommonParameters(Item->field(), Value, Color, TransparencyColor, IncandescenceColor, GlowIntensity); } bool bIsTransparent = IsTransparent(TransparencyColor); // Construct parameter expressions IDatasmithMaterialExpressionColor* ColorExpression = MaterialElement->AddMaterialExpression(); ColorExpression->SetName(TEXT("Color")); ColorExpression->GetColor() = FLinearColor::FromSRGBColor(Color); IDatasmithMaterialExpressionColor* IncandescenceColorExpression = MaterialElement->AddMaterialExpression(); IncandescenceColorExpression->SetName(TEXT("IncandescenceColor")); IncandescenceColorExpression->GetColor() = FLinearColor::FromSRGBColor(IncandescenceColor); IDatasmithMaterialExpressionColor* TransparencyColorExpression = MaterialElement->AddMaterialExpression(); TransparencyColorExpression->SetName(TEXT("TransparencyColor")); TransparencyColorExpression->GetColor() = FLinearColor::FromSRGBColor(TransparencyColor); IDatasmithMaterialExpressionScalar* GlowIntensityExpression = MaterialElement->AddMaterialExpression(); GlowIntensityExpression->GetScalar() = GlowIntensity; GlowIntensityExpression->SetName(TEXT("GlowIntensity")); // Create aux expressions IDatasmithMaterialExpressionGeneric* BaseColorAdd = MaterialElement->AddMaterialExpression(); BaseColorAdd->SetExpressionName(TEXT("Add")); IDatasmithMaterialExpressionGeneric* BaseColorTransparencyMultiply = MaterialElement->AddMaterialExpression(); BaseColorTransparencyMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceMultiply = MaterialElement->AddMaterialExpression(); IncandescenceMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceScaleMultiply = MaterialElement->AddMaterialExpression(); IncandescenceScaleMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionScalar* IncandescenceScale = MaterialElement->AddMaterialExpression(); IncandescenceScale->GetScalar() = 100.0f; IDatasmithMaterialExpressionGeneric* TransparencyOneMinus = MaterialElement->AddMaterialExpression(); TransparencyOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionFunctionCall* BreakFloat3 = nullptr; IDatasmithMaterialExpressionGeneric* AddRG = nullptr; IDatasmithMaterialExpressionGeneric* AddRGB = nullptr; IDatasmithMaterialExpressionGeneric* Divide = nullptr; IDatasmithMaterialExpressionScalar* DivideConstant = nullptr; if (bIsTransparent) { BreakFloat3 = MaterialElement->AddMaterialExpression(); BreakFloat3->SetFunctionPathName(TEXT("/Engine/Functions/Engine_MaterialFunctions02/Utility/BreakFloat3Components.BreakFloat3Components")); AddRG = MaterialElement->AddMaterialExpression(); AddRG->SetExpressionName(TEXT("Add")); AddRGB = MaterialElement->AddMaterialExpression(); AddRGB->SetExpressionName(TEXT("Add")); Divide = MaterialElement->AddMaterialExpression(); Divide->SetExpressionName(TEXT("Divide")); DivideConstant = MaterialElement->AddMaterialExpression(); DivideConstant->GetScalar() = 3.0f; } // Connect expressions ColorExpression->ConnectExpression(*BaseColorAdd->GetInput(0)); IncandescenceColorExpression->ConnectExpression(*BaseColorAdd->GetInput(1)); BaseColorAdd->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(0)); TransparencyOneMinus->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(1)); GlowIntensityExpression->ConnectExpression(*IncandescenceScaleMultiply->GetInput(0)); IncandescenceScale->ConnectExpression(*IncandescenceScaleMultiply->GetInput(1)); BaseColorTransparencyMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(0)); IncandescenceScaleMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(1)); TransparencyColorExpression->ConnectExpression(*TransparencyOneMinus->GetInput(0)); if (bIsTransparent) { TransparencyOneMinus->ConnectExpression(*BreakFloat3->GetInput(0)); BreakFloat3->ConnectExpression(*AddRG->GetInput(0), 0); BreakFloat3->ConnectExpression(*AddRG->GetInput(1), 1); AddRG->ConnectExpression(*AddRGB->GetInput(0)); BreakFloat3->ConnectExpression(*AddRGB->GetInput(1), 2); AddRGB->ConnectExpression(*Divide->GetInput(0)); DivideConstant->ConnectExpression(*Divide->GetInput(1)); } // Connect material outputs MaterialElement->GetBaseColor().SetExpression(BaseColorTransparencyMultiply); MaterialElement->GetEmissiveColor().SetExpression(IncandescenceMultiply); if (bIsTransparent) { MaterialElement->GetOpacity().SetExpression(Divide); MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasLightSourceTransparent")); } else { MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasLightSource")); } } void FWireTranslatorImpl::AddAlPhongParameters(const TAlObjectPtr& Shader, TSharedPtr MaterialElement) { // Default values for a Phong material FColor Color(145, 148, 153); FColor TransparencyColor(0, 0, 0); FColor IncandescenceColor(0, 0, 0); FColor SpecularColor(38, 38, 38); double Diffuse = 1.0; double GlowIntensity = 0.0; double Gloss = 0.8; double Shinyness = 20.0; double Specularity = 1.0; double Reflectivity = 0.5; AlList* List = Shader->fields(); for (AlShadingFieldItem* Item = static_cast(List->first()); Item; Item = Item->nextField()) { double Value = 0.0f; statusCode ErrorCode = Shader->parameter(Item->field(), Value); if (ErrorCode != 0) { continue; } if (GetCommonParameters(Item->field(), Value, Color, TransparencyColor, IncandescenceColor, GlowIntensity)) { continue; } switch (Item->field()) { case AlShadingFields::kFLD_SHADING_PHONG_DIFFUSE: Diffuse = Value; break; case AlShadingFields::kFLD_SHADING_PHONG_GLOSS_: Gloss = Value; break; case AlShadingFields::kFLD_SHADING_PHONG_SPECULAR_R: SpecularColor.R = (uint8)(255.f * Value);; break; case AlShadingFields::kFLD_SHADING_PHONG_SPECULAR_G: SpecularColor.G = (uint8)(255.f * Value);; break; case AlShadingFields::kFLD_SHADING_PHONG_SPECULAR_B: SpecularColor.B = (uint8)(255.f * Value);; break; case AlShadingFields::kFLD_SHADING_PHONG_SPECULARITY_: Specularity = Value; break; case AlShadingFields::kFLD_SHADING_PHONG_SHINYNESS: Shinyness = Value; break; case AlShadingFields::kFLD_SHADING_PHONG_REFLECTIVITY: Reflectivity = Value; break; } } bool bIsTransparent = IsTransparent(TransparencyColor); // Construct parameter expressions IDatasmithMaterialExpressionScalar* DiffuseExpression = MaterialElement->AddMaterialExpression(); DiffuseExpression->GetScalar() = Diffuse; DiffuseExpression->SetName(TEXT("Diffuse")); IDatasmithMaterialExpressionScalar* GlossExpression = MaterialElement->AddMaterialExpression(); GlossExpression->GetScalar() = Gloss; GlossExpression->SetName(TEXT("Gloss")); IDatasmithMaterialExpressionColor* SpecularColorExpression = MaterialElement->AddMaterialExpression(); SpecularColorExpression->SetName(TEXT("SpecularColor")); SpecularColorExpression->GetColor() = FLinearColor::FromSRGBColor(SpecularColor); IDatasmithMaterialExpressionScalar* SpecularityExpression = MaterialElement->AddMaterialExpression(); SpecularityExpression->GetScalar() = Specularity * 0.3; SpecularityExpression->SetName(TEXT("Specularity")); IDatasmithMaterialExpressionScalar* ShinynessExpression = MaterialElement->AddMaterialExpression(); ShinynessExpression->GetScalar() = Shinyness; ShinynessExpression->SetName(TEXT("Shinyness")); IDatasmithMaterialExpressionScalar* ReflectivityExpression = MaterialElement->AddMaterialExpression(); ReflectivityExpression->GetScalar() = Reflectivity; ReflectivityExpression->SetName(TEXT("Reflectivity")); IDatasmithMaterialExpressionColor* ColorExpression = MaterialElement->AddMaterialExpression(); ColorExpression->SetName(TEXT("Color")); ColorExpression->GetColor() = FLinearColor::FromSRGBColor(Color); IDatasmithMaterialExpressionColor* IncandescenceColorExpression = MaterialElement->AddMaterialExpression(); IncandescenceColorExpression->SetName(TEXT("IncandescenceColor")); IncandescenceColorExpression->GetColor() = FLinearColor::FromSRGBColor(IncandescenceColor); IDatasmithMaterialExpressionColor* TransparencyColorExpression = MaterialElement->AddMaterialExpression(); TransparencyColorExpression->SetName(TEXT("TransparencyColor")); TransparencyColorExpression->GetColor() = FLinearColor::FromSRGBColor(TransparencyColor); IDatasmithMaterialExpressionScalar* GlowIntensityExpression = MaterialElement->AddMaterialExpression(); GlowIntensityExpression->GetScalar() = GlowIntensity; GlowIntensityExpression->SetName(TEXT("GlowIntensity")); // Create aux expressions IDatasmithMaterialExpressionGeneric* ColorSpecLerp = MaterialElement->AddMaterialExpression(); ColorSpecLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionScalar* ColorSpecLerpValue = MaterialElement->AddMaterialExpression(); ColorSpecLerpValue->GetScalar() = 0.96f; IDatasmithMaterialExpressionGeneric* ColorMetallicLerp = MaterialElement->AddMaterialExpression(); ColorMetallicLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionGeneric* DiffuseLerp = MaterialElement->AddMaterialExpression(); DiffuseLerp->SetExpressionName(TEXT("LinearInterpolate")); IDatasmithMaterialExpressionScalar* DiffuseLerpA = MaterialElement->AddMaterialExpression(); DiffuseLerpA->GetScalar() = 0.04f; IDatasmithMaterialExpressionScalar* DiffuseLerpB = MaterialElement->AddMaterialExpression(); DiffuseLerpB->GetScalar() = 1.0f; IDatasmithMaterialExpressionGeneric* BaseColorMultiply = MaterialElement->AddMaterialExpression(); BaseColorMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* BaseColorAdd = MaterialElement->AddMaterialExpression(); BaseColorAdd->SetExpressionName(TEXT("Add")); IDatasmithMaterialExpressionGeneric* BaseColorTransparencyMultiply = MaterialElement->AddMaterialExpression(); BaseColorTransparencyMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceMultiply = MaterialElement->AddMaterialExpression(); IncandescenceMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* IncandescenceScaleMultiply = MaterialElement->AddMaterialExpression(); IncandescenceScaleMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionScalar* IncandescenceScale = MaterialElement->AddMaterialExpression(); IncandescenceScale->GetScalar() = 100.0f; IDatasmithMaterialExpressionGeneric* ShinynessSubtract = MaterialElement->AddMaterialExpression(); ShinynessSubtract->SetExpressionName(TEXT("Subtract")); IDatasmithMaterialExpressionScalar* ShinynessSubtract2 = MaterialElement->AddMaterialExpression(); ShinynessSubtract2->GetScalar() = 2.0f; IDatasmithMaterialExpressionGeneric* ShinynessDivide = MaterialElement->AddMaterialExpression(); ShinynessDivide->SetExpressionName(TEXT("Divide")); IDatasmithMaterialExpressionScalar* ShinynessDivide98 = MaterialElement->AddMaterialExpression(); ShinynessDivide98->GetScalar() = 98.0f; IDatasmithMaterialExpressionGeneric* SpecularityMultiply = MaterialElement->AddMaterialExpression(); SpecularityMultiply->SetExpressionName(TEXT("Multiply")); IDatasmithMaterialExpressionGeneric* RoughnessOneMinus = MaterialElement->AddMaterialExpression(); RoughnessOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionGeneric* TransparencyOneMinus = MaterialElement->AddMaterialExpression(); TransparencyOneMinus->SetExpressionName(TEXT("OneMinus")); IDatasmithMaterialExpressionFunctionCall* BreakFloat3 = nullptr; IDatasmithMaterialExpressionGeneric* AddRG = nullptr; IDatasmithMaterialExpressionGeneric* AddRGB = nullptr; IDatasmithMaterialExpressionGeneric* Divide = nullptr; IDatasmithMaterialExpressionScalar* DivideConstant = nullptr; if (bIsTransparent) { BreakFloat3 = MaterialElement->AddMaterialExpression(); BreakFloat3->SetFunctionPathName(TEXT("/Engine/Functions/Engine_MaterialFunctions02/Utility/BreakFloat3Components.BreakFloat3Components")); AddRG = MaterialElement->AddMaterialExpression(); AddRG->SetExpressionName(TEXT("Add")); AddRGB = MaterialElement->AddMaterialExpression(); AddRGB->SetExpressionName(TEXT("Add")); Divide = MaterialElement->AddMaterialExpression(); Divide->SetExpressionName(TEXT("Divide")); DivideConstant = MaterialElement->AddMaterialExpression(); DivideConstant->GetScalar() = 3.0f; } // Connect expressions SpecularColorExpression->ConnectExpression(*ColorSpecLerp->GetInput(0)); ColorExpression->ConnectExpression(*ColorSpecLerp->GetInput(1)); ColorSpecLerpValue->ConnectExpression(*ColorSpecLerp->GetInput(2)); ColorExpression->ConnectExpression(*ColorMetallicLerp->GetInput(0)); ColorSpecLerp->ConnectExpression(*ColorMetallicLerp->GetInput(1)); GlossExpression->ConnectExpression(*ColorMetallicLerp->GetInput(2)); DiffuseLerpA->ConnectExpression(*DiffuseLerp->GetInput(0)); DiffuseLerpB->ConnectExpression(*DiffuseLerp->GetInput(1)); DiffuseExpression->ConnectExpression(*DiffuseLerp->GetInput(2)); ColorMetallicLerp->ConnectExpression(*BaseColorMultiply->GetInput(0)); DiffuseLerp->ConnectExpression(*BaseColorMultiply->GetInput(1)); BaseColorMultiply->ConnectExpression(*BaseColorAdd->GetInput(0)); IncandescenceColorExpression->ConnectExpression(*BaseColorAdd->GetInput(1)); BaseColorAdd->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(0)); TransparencyOneMinus->ConnectExpression(*BaseColorTransparencyMultiply->GetInput(1)); GlowIntensityExpression->ConnectExpression(*IncandescenceScaleMultiply->GetInput(0)); IncandescenceScale->ConnectExpression(*IncandescenceScaleMultiply->GetInput(1)); BaseColorTransparencyMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(0)); IncandescenceScaleMultiply->ConnectExpression(*IncandescenceMultiply->GetInput(1)); ShinynessExpression->ConnectExpression(*ShinynessSubtract->GetInput(0)); ShinynessSubtract2->ConnectExpression(*ShinynessSubtract->GetInput(1)); ShinynessSubtract->ConnectExpression(*ShinynessDivide->GetInput(0)); ShinynessDivide98->ConnectExpression(*ShinynessDivide->GetInput(1)); ShinynessDivide->ConnectExpression(*SpecularityMultiply->GetInput(0)); SpecularityExpression->ConnectExpression(*SpecularityMultiply->GetInput(1)); SpecularityMultiply->ConnectExpression(*RoughnessOneMinus->GetInput(0)); TransparencyColorExpression->ConnectExpression(*TransparencyOneMinus->GetInput(0)); if (bIsTransparent) { TransparencyOneMinus->ConnectExpression(*BreakFloat3->GetInput(0)); BreakFloat3->ConnectExpression(*AddRG->GetInput(0), 0); BreakFloat3->ConnectExpression(*AddRG->GetInput(1), 1); AddRG->ConnectExpression(*AddRGB->GetInput(0)); BreakFloat3->ConnectExpression(*AddRGB->GetInput(1), 2); AddRGB->ConnectExpression(*Divide->GetInput(0)); DivideConstant->ConnectExpression(*Divide->GetInput(1)); } // Connect material outputs MaterialElement->GetBaseColor().SetExpression(BaseColorTransparencyMultiply); MaterialElement->GetMetallic().SetExpression(GlossExpression); MaterialElement->GetSpecular().SetExpression(ReflectivityExpression); MaterialElement->GetRoughness().SetExpression(RoughnessOneMinus); MaterialElement->GetEmissiveColor().SetExpression(IncandescenceMultiply); if (bIsTransparent) { MaterialElement->GetOpacity().SetExpression(Divide); MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasPhongTransparent")); } else { MaterialElement->SetParentLabel(TEXT("M_DatasmithAliasPhong")); } } class FWireInterfaceModule : public IModuleInterface { public: virtual void StartupModule() override { uint64 AliasVersion = IWireInterface::GetRequiredAliasVersion(); #ifdef OPEN_MODEL_2020 // Check installed version of Alias Tools because binaries before 2021.3 are not compatible with Alias 2022 if (LibAlias2020_Version < AliasVersion && AliasVersion < LibAlias2021_Version) { static const bool bIsDisplay = []() -> bool { UE_LOG(LogWireInterface, Warning, TEXT(WRONG_VERSION_TEXT)); return true; }(); return; } #endif if (LibAliasVersionMin <= AliasVersion && AliasVersion < LibAliasVersionMax) { auto MakeInterfaceFunc = []() -> TSharedPtr { return MakeShared(); }; IWireInterface::RegisterInterface(UE_OPENMODEL_MAJOR_VERSION, UE_OPENMODEL_MAJOR_VERSION, MoveTemp(MakeInterfaceFunc)); } } virtual void ShutdownModule() override { #if WIRE_MEMORY_CHECK // #wire_import: Need to investigate why this is crashing when enabled. if (bool(AlUniverse::isInitialized())) { AlUniverse::deleteAll(); } #endif } }; #if TRACK_MESHELEMENT #pragma optimize("", off) void MakeMeshVisible(FMeshDescription& MeshDescription) { #if MAKE_VISIBLE using namespace UE::Geometry; TVertexAttributesRef VertexPositions = MeshDescription.GetVertexPositions(); TArrayView Positions = VertexPositions.GetRawArray(); TOrientedBox3 OBox = FitOrientedBox3Points(Positions); FVertexArray& Vertices = MeshDescription.Vertices(); const TMatrix3 Matrix = OBox.Frame.Rotation.ToRotationMatrix(); constexpr float MinSize = 1.f; constexpr float MaxSize = 20.f; const float ScaleX = OBox.Extents.X < MinSize ? 20.f / OBox.Extents.X : OBox.Extents.X > MaxSize ? MaxSize / OBox.Extents.X : 10.f; const float ScaleY = OBox.Extents.Y < MinSize ? 20.f / OBox.Extents.Y : OBox.Extents.Y > MaxSize ? MaxSize / OBox.Extents.Y : 10.f; const float ScaleZ = OBox.Extents.Z < MinSize ? 20.f / OBox.Extents.Z : OBox.Extents.Z > MaxSize ? MaxSize / OBox.Extents.Z : 10.f; UE_LOG(LogWireInterface, Warning, TEXT("Scaling factor: %.3f %.3f %.3f"), ScaleX, ScaleY, ScaleZ); const FVector3f AxisX = OBox.AxisX(); const FVector3f AxisY = OBox.AxisY(); const FVector3f AxisZ = OBox.AxisZ(); for (const FVertexID& VertexID : MeshDescription.Vertices().GetElementIDs()) { FVector3f P = VertexPositions[VertexID] - OBox.Frame.Origin; VertexPositions[VertexID] = ((P | AxisX) * ScaleX) * AxisX + ((P | AxisY) * ScaleY) * AxisY + ((P | AxisZ) * ScaleZ) * AxisZ; } #endif } #endif } // namespace #undef LOCTEXT_NAMESPACE // "DatasmithWireTranslator" #else // USE_OPENMODEL namespace UE_DATASMITHWIRETRANSLATOR_NAMESPACE { class FWireInterfaceModule : public IModuleInterface { public: virtual void StartupModule() override { } virtual void ShutdownModule() override { } }; } #endif // need this macro wrapper to expand the UE_DATASMITHWIRETRANSLATOR_MODULE_NAME macro and not create symbols with "UE_DATASMITHWIRETRANSLATOR_MODULE_NAME" in the token #define IMPLEMENT_MODULE_WRAPPER(ModuleName) IMPLEMENT_MODULE(UE_DATASMITHWIRETRANSLATOR_NAMESPACE::FWireInterfaceModule, ModuleName); IMPLEMENT_MODULE_WRAPPER(UE_DATASMITHWIRETRANSLATOR_MODULE_NAME)