void UMaterialEditorInstanceConstant::RegenerateArrays() { VisibleExpressions.Empty(); ParameterGroups.Empty(); if(Parent) { // Only operate on base materials UMaterial* ParentMaterial = Parent->GetMaterial(); SourceInstance->UpdateParameterNames(); // Update any parameter names that may have changed. // Loop through all types of parameters for this material and add them to the parameter arrays. TArray<FName> ParameterNames; TArray<FGuid> Guids; ParentMaterial->GetAllVectorParameterNames(ParameterNames, Guids); // Vector Parameters. for(int32 ParameterIdx=0; ParameterIdx<ParameterNames.Num(); ParameterIdx++) { UDEditorVectorParameterValue & ParameterValue = *(NewObject<UDEditorVectorParameterValue>()); FName ParameterName = ParameterNames[ParameterIdx]; FLinearColor Value; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; ParameterValue.ExpressionId = Guids[ParameterIdx]; if(SourceInstance->GetVectorParameterValue(ParameterName, Value)) { ParameterValue.ParameterValue = Value; } // @todo: This is kind of slow, maybe store these in a map for lookup? // See if this keyname exists in the source instance. for(int32 VectorParameterIdx=0; VectorParameterIdx<SourceInstance->VectorParameterValues.Num(); VectorParameterIdx++) { FVectorParameterValue& SourceParam = SourceInstance->VectorParameterValues[VectorParameterIdx]; if(ParameterName==SourceParam.ParameterName) { ParameterValue.bOverride = true; ParameterValue.ParameterValue = SourceParam.ParameterValue; } } AssignParameterToGroup(ParentMaterial, Cast<UDEditorParameterValue>(&ParameterValue)); } // Scalar Parameters. ParentMaterial->GetAllScalarParameterNames(ParameterNames, Guids); for (int32 ParameterIdx=0; ParameterIdx<ParameterNames.Num(); ParameterIdx++) { UDEditorScalarParameterValue& ParameterValue = *(NewObject<UDEditorScalarParameterValue>()); FName ParameterName = ParameterNames[ParameterIdx]; float Value; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; ParameterValue.ExpressionId = Guids[ParameterIdx]; if (SourceInstance->GetScalarParameterValue(ParameterName, Value)) { ParentMaterial->GetScalarParameterSliderMinMax(ParameterName, ParameterValue.SliderMin, ParameterValue.SliderMax); ParameterValue.ParameterValue = Value; } // @todo: This is kind of slow, maybe store these in a map for lookup? // See if this keyname exists in the source instance. for(int32 ScalarParameterIdx=0; ScalarParameterIdx<SourceInstance->ScalarParameterValues.Num(); ScalarParameterIdx++) { FScalarParameterValue& SourceParam = SourceInstance->ScalarParameterValues[ScalarParameterIdx]; if(ParameterName==SourceParam.ParameterName) { ParameterValue.bOverride = true; ParameterValue.ParameterValue = SourceParam.ParameterValue; } } AssignParameterToGroup(ParentMaterial, Cast<UDEditorParameterValue>(&ParameterValue)); } // Texture Parameters. ParentMaterial->GetAllTextureParameterNames(ParameterNames, Guids); for(int32 ParameterIdx=0; ParameterIdx<ParameterNames.Num(); ParameterIdx++) { UDEditorTextureParameterValue& ParameterValue = *(NewObject<UDEditorTextureParameterValue>()); FName ParameterName = ParameterNames[ParameterIdx]; UTexture* Value; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; ParameterValue.ExpressionId = Guids[ParameterIdx]; if(SourceInstance->GetTextureParameterValue(ParameterName, Value)) { ParameterValue.ParameterValue = Value; } // @todo: This is kind of slow, maybe store these in a map for lookup? // See if this keyname exists in the source instance. for(int32 TextureParameterIdx=0; TextureParameterIdx<SourceInstance->TextureParameterValues.Num(); TextureParameterIdx++) { FTextureParameterValue& SourceParam = SourceInstance->TextureParameterValues[TextureParameterIdx]; if(ParameterName==SourceParam.ParameterName) { ParameterValue.bOverride = true; ParameterValue.ParameterValue = SourceParam.ParameterValue; } } AssignParameterToGroup(ParentMaterial, Cast<UDEditorParameterValue>(&ParameterValue)); } // Font Parameters. ParentMaterial->GetAllFontParameterNames(ParameterNames, Guids); for(int32 ParameterIdx=0; ParameterIdx<ParameterNames.Num(); ParameterIdx++) { UDEditorFontParameterValue& ParameterValue = *(NewObject<UDEditorFontParameterValue>()); FName ParameterName = ParameterNames[ParameterIdx]; UFont* FontValue; int32 FontPage; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; ParameterValue.ExpressionId = Guids[ParameterIdx]; if(SourceInstance->GetFontParameterValue(ParameterName, FontValue,FontPage)) { ParameterValue.ParameterValue.FontValue = FontValue; ParameterValue.ParameterValue.FontPage = FontPage; } // @todo: This is kind of slow, maybe store these in a map for lookup? // See if this keyname exists in the source instance. for(int32 FontParameterIdx=0; FontParameterIdx<SourceInstance->FontParameterValues.Num(); FontParameterIdx++) { FFontParameterValue& SourceParam = SourceInstance->FontParameterValues[FontParameterIdx]; if(ParameterName==SourceParam.ParameterName) { ParameterValue.bOverride = true; ParameterValue.ParameterValue.FontValue = SourceParam.FontValue; ParameterValue.ParameterValue.FontPage = SourceParam.FontPage; } } AssignParameterToGroup(ParentMaterial, Cast<UDEditorParameterValue>(&ParameterValue)); } // Get all static parameters from the source instance. This will handle inheriting parent values. FStaticParameterSet SourceStaticParameters; SourceInstance->GetStaticParameterValues(SourceStaticParameters); // Copy Static Switch Parameters for(int32 ParameterIdx=0; ParameterIdx<SourceStaticParameters.StaticSwitchParameters.Num(); ParameterIdx++) { FStaticSwitchParameter StaticSwitchParameterValue = FStaticSwitchParameter(SourceStaticParameters.StaticSwitchParameters[ParameterIdx]); UDEditorStaticSwitchParameterValue& ParameterValue = *(NewObject<UDEditorStaticSwitchParameterValue>()); ParameterValue.ParameterValue =StaticSwitchParameterValue.Value; ParameterValue.bOverride =StaticSwitchParameterValue.bOverride; ParameterValue.ParameterName =StaticSwitchParameterValue.ParameterName; ParameterValue.ExpressionId= StaticSwitchParameterValue.ExpressionGUID; AssignParameterToGroup(ParentMaterial, Cast<UDEditorParameterValue>(&ParameterValue)); } // Copy Static Component Mask Parameters for(int32 ParameterIdx=0; ParameterIdx<SourceStaticParameters.StaticComponentMaskParameters.Num(); ParameterIdx++) { FStaticComponentMaskParameter StaticComponentMaskParameterValue = FStaticComponentMaskParameter(SourceStaticParameters.StaticComponentMaskParameters[ParameterIdx]); UDEditorStaticComponentMaskParameterValue& ParameterValue = *(NewObject<UDEditorStaticComponentMaskParameterValue>()); ParameterValue.ParameterValue.R = StaticComponentMaskParameterValue.R; ParameterValue.ParameterValue.G = StaticComponentMaskParameterValue.G; ParameterValue.ParameterValue.B = StaticComponentMaskParameterValue.B; ParameterValue.ParameterValue.A = StaticComponentMaskParameterValue.A; ParameterValue.bOverride =StaticComponentMaskParameterValue.bOverride; ParameterValue.ParameterName =StaticComponentMaskParameterValue.ParameterName; ParameterValue.ExpressionId= StaticComponentMaskParameterValue.ExpressionGUID; AssignParameterToGroup(ParentMaterial, Cast<UDEditorParameterValue>(&ParameterValue)); } IMaterialEditorModule* MaterialEditorModule = &FModuleManager::LoadModuleChecked<IMaterialEditorModule>( "MaterialEditor" ); MaterialEditorModule->GetVisibleMaterialParameters(ParentMaterial, SourceInstance, VisibleExpressions); } // sort contents of groups for(int32 ParameterIdx=0; ParameterIdx<ParameterGroups.Num(); ParameterIdx++) { FEditorParameterGroup & ParamGroup = ParameterGroups[ParameterIdx]; struct FCompareUDEditorParameterValueByParameterName { FORCEINLINE bool operator()(const UDEditorParameterValue& A, const UDEditorParameterValue& B) const { FString AName = A.ParameterName.ToString().ToLower(); FString BName = B.ParameterName.ToString().ToLower(); return AName < BName; } }; ParamGroup.Parameters.Sort( FCompareUDEditorParameterValueByParameterName() ); } // sort groups itself pushing defaults to end struct FCompareFEditorParameterGroupByName { FORCEINLINE bool operator()(const FEditorParameterGroup& A, const FEditorParameterGroup& B) const { FString AName = A.GroupName.ToString().ToLower(); FString BName = B.GroupName.ToString().ToLower(); if (AName == TEXT("none")) { return false; } if (BName == TEXT("none")) { return false; } return AName < BName; } }; ParameterGroups.Sort( FCompareFEditorParameterGroupByName() ); TArray<struct FEditorParameterGroup> ParameterDefaultGroups; for(int32 ParameterIdx=0; ParameterIdx<ParameterGroups.Num(); ParameterIdx++) { FEditorParameterGroup & ParamGroup = ParameterGroups[ParameterIdx]; if (bUseOldStyleMICEditorGroups == false) { if (ParamGroup.GroupName == TEXT("None")) { ParameterDefaultGroups.Add(ParamGroup); ParameterGroups.RemoveAt(ParameterIdx); break; } } else { if (ParamGroup.GroupName == TEXT("Vector Parameter Values") || ParamGroup.GroupName == TEXT("Scalar Parameter Values") || ParamGroup.GroupName == TEXT("Texture Parameter Values") || ParamGroup.GroupName == TEXT("Static Switch Parameter Values") || ParamGroup.GroupName == TEXT("Static Component Mask Parameter Values") || ParamGroup.GroupName == TEXT("Font Parameter Values")) { ParameterDefaultGroups.Add(ParamGroup); ParameterGroups.RemoveAt(ParameterIdx); } } } if (ParameterDefaultGroups.Num() >0) { ParameterGroups.Append(ParameterDefaultGroups); } }
//! @brief Create an Unreal Material for the given graph-instance UMaterial* CreateMaterial(graph_inst_t* GraphInstance, const FString & MaterialName, UObject* Outer) { // create an unreal material asset UMaterialFactoryNew* MaterialFactory = NewObject<UMaterialFactoryNew>(); UMaterial* UnrealMaterial = (UMaterial*)MaterialFactory->FactoryCreateNew( UMaterial::StaticClass(), Substance::Helpers::CreateObjectPackage(Outer, MaterialName), *MaterialName, RF_Standalone|RF_Public, NULL, GWarn ); // textures and properties for (auto ItOut = GraphInstance->Outputs.itfront(); ItOut; ++ItOut) { output_inst_t* OutputInst = &(*ItOut); output_desc_t* OutputDesc = OutputInst->GetOutputDesc(); CreateMaterialExpression( OutputInst, UnrealMaterial); } // special case: emissive only materials TArray<FName> ParamNames; TArray<FGuid> ParamIds; UnrealMaterial->GetAllTextureParameterNames(ParamNames, ParamIds); if (ParamNames.Num() == 1) { if (ParamNames[0].ToString() == TEXT("emissive")) { UnrealMaterial->SetShadingModel(MSM_Unlit); } } // special case: no roughness but glossiness if (!UnrealMaterial->Roughness.IsConnected()) { for (auto ItOut = GraphInstance->Outputs.itfront(); ItOut; ++ItOut) { output_inst_t* OutputInst = &(*ItOut); output_desc_t* OutputDesc = OutputInst->GetOutputDesc(); UTexture* Texture = *OutputInst->Texture; if (OutputDesc->Channel == CHAN_Glossiness && Texture) { // and link it to the material UMaterialExpressionOneMinus* OneMinus = NewObject<UMaterialExpressionOneMinus>(UnrealMaterial); UMaterialExpressionTextureSampleParameter2D* UnrealTextureExpression = CreateSampler(UnrealMaterial, Texture, OutputDesc); UnrealTextureExpression->MaterialExpressionEditorX -= 200; OneMinus->MaterialExpressionEditorX = -200; OneMinus->MaterialExpressionEditorY = UnrealTextureExpression->MaterialExpressionEditorY; UnrealTextureExpression->ConnectExpression(OneMinus->GetInput(0), 0); UnrealMaterial->Roughness.Expression = OneMinus; UnrealMaterial->Expressions.Add(UnrealTextureExpression); UnrealMaterial->Expressions.Add(OneMinus); } } } // let the material update itself if necessary UnrealMaterial->PreEditChange(NULL); UnrealMaterial->PostEditChange(); return UnrealMaterial; }