/**
 * Extract the material names from the Apex Render Mesh contained within an Apex Destructible Asset.
 * @param ImportData - SkeletalMesh import data into which we are extracting information
 * @param ApexDestructibleAsset - the Apex Destructible Asset
 */
static void ImportMaterialsForSkelMesh(FSkeletalMeshImportData &ImportData, const NxDestructibleAsset& ApexDestructibleAsset)
{
	physx::PxU32 SubmeshCount = 0;

	// Get the submesh count from the Destructible Asset's Render Mesh
	const physx::NxRenderMeshAsset* ApexRenderMesh = ApexDestructibleAsset.getRenderMeshAsset();
	if (ApexRenderMesh != NULL)
	{
		SubmeshCount = ApexRenderMesh->getSubmeshCount();
	}

	if( SubmeshCount == 0 )
	{
		// No material info, create a default material slot
		++SubmeshCount;
		UE_LOG(LogApexDestructibleAssetImport, Warning,TEXT("No material associated with skeletal mesh - using default"));
	}
	else
	{
		UE_LOG(LogApexDestructibleAssetImport, Warning,TEXT("Using default materials for material slot"));
	}

	// Create material slots
	UMaterial* DefaultMaterial = UMaterial::GetDefaultMaterial(MD_Surface);
	if (DefaultMaterial)
	{
		for (uint32 MatIndex = 0; MatIndex < SubmeshCount; MatIndex++)
		{
			ImportData.Materials.Add( VMaterial() );

			ImportData.Materials.Last().Material = DefaultMaterial;
			ImportData.Materials.Last().MaterialImportName = DefaultMaterial->GetName();
		}
	}
}
FLinearColor UMaterialGraphNode::GetNodeTitleColor() const
{
	UMaterial* Material = CastChecked<UMaterialGraph>(GetGraph())->Material;

	// Generate title color
	FColor TitleColor = MaterialExpression->BorderColor;
	TitleColor.A = 255;

	if (bIsErrorExpression)
	{
		// Outline expressions that caused errors in red
		TitleColor = FColor( 255, 0, 0 );
	}
	else if (bIsCurrentSearchResult)
	{
		TitleColor = FColor( 64, 64, 255 );
	}
	else if (bIsPreviewExpression)
	{
		// If we are currently previewing a node, its border should be the preview color.
		TitleColor = FColor( 70, 100, 200 );
	}
	else if (UMaterial::IsParameter(MaterialExpression))
	{
		if (Material->HasDuplicateParameters(MaterialExpression))
		{
			TitleColor = FColor( 0, 255, 255 );
		}
		else
		{
			TitleColor = FColor( 0, 128, 128 );
		}
	}
	else if (UMaterial::IsDynamicParameter(MaterialExpression))
	{
		if (Material->HasDuplicateDynamicParameters(MaterialExpression))
		{
			TitleColor = FColor( 0, 255, 255 );
		}
		else
		{
			TitleColor = FColor( 0, 128, 128 );
		}
	}

	return FLinearColor(TitleColor);
}
Пример #3
0
void FMaterialTrackEditor::AddVectorParameter( FGuid ObjectBinding, UMovieSceneMaterialTrack* MaterialTrack, FName ParameterName )
{
	UMovieSceneSequence* MovieSceneSequence = GetMovieSceneSequence();
	float KeyTime = GetTimeForKey( MovieSceneSequence );

	UMaterial* Material = GetMaterialForTrack( ObjectBinding, MaterialTrack );
	if ( Material != nullptr )
	{
		const FScopedTransaction Transaction( LOCTEXT( "AddVectorParameter", "Add vector parameter" ) );
		FLinearColor ParameterValue;
		Material->GetVectorParameterValue( ParameterName, ParameterValue );
		MaterialTrack->Modify();
		for ( UMovieSceneSection* Section : MaterialTrack->GetAllSections() )
		{
			Section->Modify();
		}
		MaterialTrack->AddVectorParameterKey( ParameterName, KeyTime, ParameterValue );
	}
	NotifyMovieSceneDataChanged();
}
Пример #4
0
TSharedRef<SWidget> FMaterialTrackEditor::OnGetAddParameterMenuContent( FGuid ObjectBinding, UMovieSceneMaterialTrack* MaterialTrack )
{
	FMenuBuilder AddParameterMenuBuilder( true, nullptr );

	UMaterial* Material = GetMaterialForTrack( ObjectBinding, MaterialTrack );
	if ( Material != nullptr )
	{
		TArray<FParameterNameAndAction> ParameterNamesAndActions;

		// Collect scalar parameters.
		TArray<FName> ScalarParameterNames;
		TArray<FGuid> ScalarParmeterGuids;
		Material->GetAllScalarParameterNames( ScalarParameterNames, ScalarParmeterGuids );
		for ( const FName& ScalarParameterName : ScalarParameterNames )
		{
			FUIAction AddParameterMenuAction( FExecuteAction::CreateSP( this, &FMaterialTrackEditor::AddScalarParameter, ObjectBinding, MaterialTrack, ScalarParameterName ) );
			FParameterNameAndAction NameAndAction( ScalarParameterName, AddParameterMenuAction );
			ParameterNamesAndActions.Add(NameAndAction);
		}

		// Collect vector parameters.
		TArray<FName> VectorParameterNames;
		TArray<FGuid> VectorParmeterGuids;
		Material->GetAllVectorParameterNames( VectorParameterNames, VectorParmeterGuids );
		for ( const FName& VectorParameterName : VectorParameterNames )
		{
			FUIAction AddParameterMenuAction( FExecuteAction::CreateSP( this, &FMaterialTrackEditor::AddVectorParameter, ObjectBinding, MaterialTrack, VectorParameterName ) );
			FParameterNameAndAction NameAndAction( VectorParameterName, AddParameterMenuAction );
			ParameterNamesAndActions.Add( NameAndAction );
		}

		// Sort and generate menu.
		ParameterNamesAndActions.Sort();
		for ( FParameterNameAndAction NameAndAction : ParameterNamesAndActions )
		{
			AddParameterMenuBuilder.AddMenuEntry( FText::FromName( NameAndAction.ParameterName ), FText(), FSlateIcon(), NameAndAction.Action );
		}
	}

	return AddParameterMenuBuilder.MakeWidget();
}
void FBufferVisualizationData::Initialize()
{
	if (!bIsInitialized)
	{
		if (AllowDebugViewmodes())
		{
			check(MaterialMap.Num() == 0);

			FConfigSection* MaterialSection = GConfig->GetSectionPrivate( TEXT("Engine.BufferVisualizationMaterials"), false, true, GEngineIni );

			if (MaterialSection != NULL)
			{
				for (FConfigSection::TIterator It(*MaterialSection); It; ++It)
				{
					FString MaterialName;
					if( FParse::Value( *It.Value().GetValue(), TEXT("Material="), MaterialName, true ) )
					{
						UMaterial* Material = LoadObject<UMaterial>(NULL, *MaterialName);
			
						if (Material)
						{
							Material->AddToRoot();
							Record& Rec = MaterialMap.Add(It.Key(), Record());
							Rec.Name = It.Key().GetPlainNameString();
							Rec.Material = Material;
							FText DisplayName;
							FParse::Value( *It.Value().GetValue(), TEXT("Name="), DisplayName, TEXT("Engine.BufferVisualizationMaterials") );
							Rec.DisplayName = DisplayName;
						}
					}
				}
			}

			ConfigureConsoleCommand();
		}

		bIsInitialized = true;
	}
}
void UnFbx::FFbxImporter::CreateUnrealMaterial(FbxSurfaceMaterial* FbxMaterial, TArray<UMaterialInterface*>& OutMaterials, TArray<FString>& UVSets)
{
	FString MaterialFullName = ANSI_TO_TCHAR(MakeName(FbxMaterial->GetName()));

	// check for a 'skinXX' suffix in the material name
	int32 MaterialNameLen = FCString::Strlen(*MaterialFullName) + 1;
	char* MaterialNameANSI = new char[MaterialNameLen];
	FCStringAnsi::Strcpy(MaterialNameANSI, MaterialNameLen, TCHAR_TO_ANSI(*MaterialFullName));
	if (FCStringAnsi::Strlen(MaterialNameANSI) > 6)
	{
		const char* SkinXX = MaterialNameANSI + FCStringAnsi::Strlen(MaterialNameANSI) - 6;
		if (FCharAnsi::ToUpper(*SkinXX) == 'S' && FCharAnsi::ToUpper(*(SkinXX+1)) == 'K' && 
			FCharAnsi::ToUpper(*(SkinXX+2)) == 'I' && FCharAnsi::ToUpper(*(SkinXX+3)) == 'N')
		{
			if (FCharAnsi::IsDigit(*(SkinXX+4)) && FCharAnsi::IsDigit(*(SkinXX+5)))
			{
				// remove the 'skinXX' suffix from the material name
				MaterialFullName = MaterialFullName.Left(MaterialNameLen - 7);
			}
		}
	}

	MaterialFullName = ObjectTools::SanitizeObjectName(MaterialFullName);

	// Make sure we have a parent
	if ( !ensure(Parent) )
	{
		return;
	}
	
	// set where to place the materials
	FString NewPackageName = FPackageName::GetLongPackagePath(Parent->GetOutermost()->GetName()) + TEXT("/") + MaterialFullName;
	NewPackageName = PackageTools::SanitizePackageName(NewPackageName);
	UPackage* Package = CreatePackage(NULL, *NewPackageName);
	
	UMaterialInterface* UnrealMaterialInterface = FindObject<UMaterialInterface>(Package,*MaterialFullName);
	// does not override existing materials
	if (UnrealMaterialInterface != NULL)
	{
		OutMaterials.Add(UnrealMaterialInterface);
		return;
	}
	
	// create an unreal material asset
	UMaterialFactoryNew* MaterialFactory = new UMaterialFactoryNew(FPostConstructInitializeProperties());
	
	UMaterial* UnrealMaterial = (UMaterial*)MaterialFactory->FactoryCreateNew(
		UMaterial::StaticClass(), Package, *MaterialFullName, RF_Standalone|RF_Public, NULL, GWarn );
	// TODO :  need this ? UnrealMaterial->bUsedWithStaticLighting = true;

	if ( UnrealMaterial != NULL )
	{
		// Notify the asset registry
		FAssetRegistryModule::AssetCreated(UnrealMaterial);

		// Set the dirty flag so this package will get saved later
		Package->SetDirtyFlag(true);
	}

	// textures and properties
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sDiffuse, UnrealMaterial->DiffuseColor, false, UVSets);
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sEmissive, UnrealMaterial->EmissiveColor, false, UVSets);
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sSpecular, UnrealMaterial->SpecularColor, false, UVSets);
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sSpecularFactor, UnrealMaterial->SpecularColor, false, UVSets); // SpecularFactor modulates the SpecularColor value if there's one
	//CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sShininess, UnrealMaterial->SpecularPower, false, UVSets);
	if (!CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sNormalMap, UnrealMaterial->Normal, true, UVSets))
	{
		CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sBump, UnrealMaterial->Normal, true, UVSets); // no bump in unreal, use as normal map
	}
	//CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, KFbxSurfaceMaterial::sTransparentColor, UnrealMaterial->Opacity, false, UVSets);
	//CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, KFbxSurfaceMaterial::sTransparencyFactor, UnrealMaterial->OpacityMask, false, UVSets);
	FixupMaterial( *FbxMaterial, UnrealMaterial); // add random diffuse if none exists

	// compile shaders for PC (from UPrecompileShadersCommandlet::ProcessMaterial
	// and FMaterialEditor::UpdateOriginalMaterial)

	// make sure that any static meshes, etc using this material will stop using the FMaterialResource of the original 
	// material, and will use the new FMaterialResource created when we make a new UMaterial in place
	FGlobalComponentReregisterContext RecreateComponents;
	
	// let the material update itself if necessary
	UnrealMaterial->PreEditChange(NULL);
		UnrealMaterial->PostEditChange();
	
	OutMaterials.Add(UnrealMaterial);
}
Пример #7
0
// ***************************************************************************
void			CDriverUser::deleteMaterial(UMaterial &umat)
{
	delete umat.getObjectPtr();
	umat.detach();
}
FLinearColor UMaterialGraphNode::GetNodeTitleColor() const
{
	UMaterial* Material = CastChecked<UMaterialGraph>(GetGraph())->Material;

	if (bIsPreviewExpression)
	{
		// If we are currently previewing a node, its border should be the preview color.
		return FColor( 70, 100, 200 );
	}

	const UGraphEditorSettings* Settings = GetDefault<UGraphEditorSettings>();

	if (UsesBoolColour(MaterialExpression))
	{
		return Settings->BooleanPinTypeColor;
	}
	else if (UsesFloatColour(MaterialExpression))
	{
		return Settings->FloatPinTypeColor;
	}
	else if (UsesVectorColour(MaterialExpression))
	{
		return Settings->VectorPinTypeColor;
	}
	else if (UsesObjectColour(MaterialExpression))
	{
		return Settings->ObjectPinTypeColor;
	}
	else if (UsesEventColour(MaterialExpression))
	{
		return Settings->EventNodeTitleColor;
	}
	else if (MaterialExpression->IsA(UMaterialExpressionMaterialFunctionCall::StaticClass()))
	{
		// Previously FColor(0, 116, 255);
		return Settings->FunctionCallNodeTitleColor;
	}
	else if (MaterialExpression->IsA(UMaterialExpressionFunctionOutput::StaticClass()))
	{
		// Previously FColor(255, 155, 0);
		return Settings->ResultNodeTitleColor;
	}
	else if (MaterialExpression->IsA(UMaterialExpressionCustomOutput::StaticClass()))
	{
		// Previously FColor(255, 155, 0);
		return Settings->ResultNodeTitleColor;
	}
	else if (UMaterial::IsParameter(MaterialExpression))
	{
		if (Material->HasDuplicateParameters(MaterialExpression))
		{
			return FColor( 0, 255, 255 );
		}
		else
		{
			return FColor( 0, 128, 128 );
		}
	}
	else if (UMaterial::IsDynamicParameter(MaterialExpression))
	{
		if (Material->HasDuplicateDynamicParameters(MaterialExpression))
		{
			return FColor( 0, 255, 255 );
		}
		else
		{
			return FColor( 0, 128, 128 );
		}
	}

	// Assume that most material expressions act like pure functions and don't affect anything else
	return Settings->PureFunctionCallNodeTitleColor;
}
void UMaterialParameterCollection::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	// If the array counts have changed, an element has been added or removed, and we need to update the uniform buffer layout,
	// Which also requires recompiling any referencing materials
	if (ScalarParameters.Num() != PreviousScalarParameters.Num()
		|| VectorParameters.Num() != PreviousVectorParameters.Num())
	{
		// Limit the count of parameters to fit within uniform buffer limits
		const uint32 MaxScalarParameters = 1024;

		if (ScalarParameters.Num() > MaxScalarParameters)
		{
			ScalarParameters.RemoveAt(MaxScalarParameters, ScalarParameters.Num() - MaxScalarParameters);
		}

		const uint32 MaxVectorParameters = 1024;

		if (VectorParameters.Num() > MaxVectorParameters)
		{
			VectorParameters.RemoveAt(MaxVectorParameters, VectorParameters.Num() - MaxVectorParameters);
		}

		// Generate a new Id so that unloaded materials that reference this collection will update correctly on load
		StateId = FGuid::NewGuid();

		// Update the uniform buffer layout
		CreateBufferStruct();

		// Recreate each instance of this collection
		for (TObjectIterator<UWorld> It; It; ++It)
		{
			UWorld* CurrentWorld = *It;
			CurrentWorld->AddParameterCollectionInstance(this, false);
		}

		// Build set of changed parameter names
		TSet<FName> ParameterNames;
		for (const FCollectionVectorParameter& Param : PreviousVectorParameters)
		{
			ParameterNames.Add(Param.ParameterName);
		}

		for (const FCollectionScalarParameter& Param : PreviousScalarParameters)
		{
			ParameterNames.Add(Param.ParameterName);
		}

		for (const FCollectionVectorParameter& Param : VectorParameters)
		{
			ParameterNames.Remove(Param.ParameterName);
		}

		for (const FCollectionScalarParameter& Param : ScalarParameters)
		{
			ParameterNames.Remove(Param.ParameterName);
		}

		// Create a material update context so we can safely update materials using this parameter collection.
		{
			FMaterialUpdateContext UpdateContext;

			// Go through all materials in memory and recompile them if they use this material parameter collection
			for (TObjectIterator<UMaterial> It; It; ++It)
			{
				UMaterial* CurrentMaterial = *It;

				bool bRecompile = false;

				// Preview materials often use expressions for rendering that are not in their Expressions array, 
				// And therefore their MaterialParameterCollectionInfos are not up to date.
				if (CurrentMaterial->bIsPreviewMaterial)
				{
					bRecompile = true;
				}
				else
				{
					for (int32 FunctionIndex = 0; FunctionIndex < CurrentMaterial->MaterialParameterCollectionInfos.Num() && !bRecompile; FunctionIndex++)
					{
						if (CurrentMaterial->MaterialParameterCollectionInfos[FunctionIndex].ParameterCollection == this)
						{
							TArray<UMaterialExpressionCollectionParameter*> CollectionParameters;
							CurrentMaterial->GetAllExpressionsInMaterialAndFunctionsOfType(CollectionParameters);
							for (UMaterialExpressionCollectionParameter* CollectionParameter : CollectionParameters)
							{
								if (ParameterNames.Contains(CollectionParameter->ParameterName))
								{
									bRecompile = true;
									break;
								}
							}
						}
					}
				}

				if (bRecompile)
				{
					UpdateContext.AddMaterial(CurrentMaterial);

					// Propagate the change to this material
					CurrentMaterial->PreEditChange(NULL);
					CurrentMaterial->PostEditChange();
					CurrentMaterial->MarkPackageDirty();
				}
			}
		}
	}

	// Update each world's scene with the new instance, and update each instance's uniform buffer to reflect the changes made by the user
	for (TObjectIterator<UWorld> It; It; ++It)
	{
		UWorld* CurrentWorld = *It;
		CurrentWorld->UpdateParameterCollectionInstances(true);
	}

	PreviousScalarParameters.Empty();
	PreviousVectorParameters.Empty();

	Super::PostEditChangeProperty(PropertyChangedEvent);
}
Пример #10
0
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);
	}

}
Пример #11
0
void FGridWidget::DrawNewGrid(const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
	bool bUseTextureSolution = CVarEditorNewLevelGrid.GetValueOnGameThread() > 1;
	UMaterial* GridMaterial = bUseTextureSolution ? LevelGridMaterial2 : LevelGridMaterial;
	UMaterialInstanceDynamic* MaterialInst = bUseTextureSolution ? LevelGridMaterialInst2 : LevelGridMaterialInst;

	if (GridMaterial->IsCompilingOrHadCompileError(View->GetFeatureLevel()))
	{
		// The material would appear to be black (because we don't use a MaterialDomain but a UsageFlag - we should change that).
		// Here we rather want to hide it.
		return;
	}

	if(!MaterialInst)
	{
		return;
	}

	bool bMSAA = IsEditorCompositingMSAAEnabled(View->GetFeatureLevel());
	bool bIsPerspective = ( View->ViewMatrices.ProjMatrix.M[3][3] < 1.0f );

	// in unreal units
	float SnapGridSize = GEditor->GetGridSize();

	// not used yet
	const bool bSnapEnabled = GetDefault<ULevelEditorViewportSettings>()->GridEnabled;

	float SnapAlphaMultiplier = 1.0f;

	// to get a light grid in a black level but use a high opacity value to be able to see it in a bright level
	static float Darken = 0.11f;

	static FName GridColorName("GridColor");
	static FName SnapColorName("SnapColor");
	static FName ExponentName("Exponent");
	static FName AlphaBiasName("AlphaBias");
	
	if(bIsPerspective)
	{
		MaterialInst->SetVectorParameterValue(GridColorName, FLinearColor(0.6f * Darken, 0.6f * Darken, 0.6f * Darken, CVarEditor3DGridFade.GetValueOnGameThread()));
		MaterialInst->SetVectorParameterValue(SnapColorName, FLinearColor(0.5f, 0.0f, 0.0f, SnapAlphaMultiplier * CVarEditor3DSnapFade.GetValueOnGameThread()));
	}
	else
	{
		MaterialInst->SetVectorParameterValue(GridColorName, FLinearColor(0.6f * Darken, 0.6f * Darken, 0.6f * Darken, CVarEditor2DGridFade.GetValueOnGameThread()));
		MaterialInst->SetVectorParameterValue(SnapColorName, FLinearColor(0.5f, 0.0f, 0.0f, SnapAlphaMultiplier * CVarEditor2DSnapFade.GetValueOnGameThread()));
	}

	// true:1m, false:1dm ios smallest grid size
	bool bLarger1mGrid = true;

	const int Exponent = 10;

	// 2 is the default so we need to set it
	MaterialInst->SetScalarParameterValue(ExponentName, (float)Exponent);

	// without MSAA we need the grid to be more see through so lines behind it can be recognized
	MaterialInst->SetScalarParameterValue(AlphaBiasName, bMSAA ? 0.0f : 0.05f);

	// grid for size
	float GridSplit = 0.5f;
	// red dots to visualize the snap
	float SnapSplit = 0.075f;

	float WorldToUVScale = 0.001f;

	if(bLarger1mGrid)
	{
		WorldToUVScale *= 0.1f;
		GridSplit *= 0.1f;
	}

	// in 2D all grid lines are same size in world space (they are at different scale so we need to adjust here)
	FLinearColor GridSplitTriple(GridSplit * 0.01f, GridSplit * 0.1f, GridSplit);

	if(bIsPerspective)
	{
		// largest grid lines
		GridSplitTriple.R *= 8.0f;
		// medium grid lines
		GridSplitTriple.G *= 3.0f;
		// fine grid lines
		GridSplitTriple.B *= 1.0f;
	}

	if(!bIsPerspective)
	{
		// screenspace size looks better in 2d

		float ScaleX = View->ViewMatrices.ProjMatrix.M[0][0] * View->ViewRect.Width();
		float ScaleY = View->ViewMatrices.ProjMatrix.M[1][1] * View->ViewRect.Height();

		float Scale = FMath::Min(ScaleX, ScaleY);

		float GridScale = CVarEditor2DSnapScale.GetValueOnGameThread();
		float GridMin = CVarEditor2DSnapMin.GetValueOnGameThread();

		// we need to account for a larger grids setting
		SnapSplit = 1.25f * FMath::Min(GridScale / SnapGridSize / Scale, GridMin);

		// hack test
		GridSplitTriple.R = 0.25f * FMath::Min(GridScale / 100 / Scale * 0.01f, GridMin);
		GridSplitTriple.G = 0.25f * FMath::Min(GridScale / 100 / Scale * 0.1f, GridMin);
		GridSplitTriple.B = 0.25f * FMath::Min(GridScale / 100 / Scale, GridMin);
	}

	float SnapTile = (1.0f / WorldToUVScale) / FMath::Max(1.0f, SnapGridSize);

	MaterialInst->SetVectorParameterValue("GridSplit", GridSplitTriple);
	MaterialInst->SetScalarParameterValue("SnapSplit", SnapSplit);
	MaterialInst->SetScalarParameterValue("SnapTile", SnapTile);

	FMatrix ObjectToWorld = FMatrix::Identity;

	FVector CameraPos = View->ViewMatrices.ViewOrigin;

	FVector2D UVCameraPos = FVector2D(CameraPos.X, CameraPos.Y);

	ObjectToWorld.SetOrigin(FVector(CameraPos.X, CameraPos.Y, 0));

	FLinearColor AxisColors[3];
	GetAxisColors(AxisColors, true);

	FLinearColor UAxisColor = AxisColors[1];
	FLinearColor VAxisColor = AxisColors[0];

	if(!bIsPerspective)
	{
		float FarZ = 100000.0f;

		if(View->ViewMatrices.ViewMatrix.M[1][1] == -1.f )		// Top
		{
			ObjectToWorld.SetOrigin(FVector(CameraPos.X, CameraPos.Y, -FarZ));
		}
		if(View->ViewMatrices.ViewMatrix.M[1][2] == -1.f )		// Front
		{
			UVCameraPos = FVector2D(CameraPos.Z, CameraPos.X);
			ObjectToWorld.SetAxis(0, FVector(0,0,1));
			ObjectToWorld.SetAxis(1, FVector(1,0,0));
			ObjectToWorld.SetAxis(2, FVector(0,1,0));
			ObjectToWorld.SetOrigin(FVector(CameraPos.X, -FarZ, CameraPos.Z));
			UAxisColor = AxisColors[0];
			VAxisColor = AxisColors[2];
		}
		else if(View->ViewMatrices.ViewMatrix.M[1][0] == 1.f )		// Side
		{
			UVCameraPos = FVector2D(CameraPos.Y, CameraPos.Z);
			ObjectToWorld.SetAxis(0, FVector(0,1,0));
			ObjectToWorld.SetAxis(1, FVector(0,0,1));
			ObjectToWorld.SetAxis(2, FVector(1,0,0));
			ObjectToWorld.SetOrigin(FVector(FarZ, CameraPos.Y, CameraPos.Z));
			UAxisColor = AxisColors[2];
			VAxisColor = AxisColors[1];
		}
	}
	
	MaterialInst->SetVectorParameterValue("UAxisColor", UAxisColor);
	MaterialInst->SetVectorParameterValue("VAxisColor", VAxisColor);

	// We don't want to affect the mouse interaction.
	PDI->SetHitProxy(0);

	// good enough to avoid the AMD artifacts, horizon still appears to be a line
	float Radii = 100000;

	if(bIsPerspective)
	{
		// the higher we get the larger we make the geometry to give the illusion of an infinite grid while maintains the precision nearby
		Radii *= FMath::Max( 1.0f, FMath::Abs(CameraPos.Z) / 1000.0f );
	}
	else
	{
		float ScaleX = View->ViewMatrices.ProjMatrix.M[0][0];
		float ScaleY = View->ViewMatrices.ProjMatrix.M[1][1];

		float Scale = FMath::Min(ScaleX, ScaleY);

		Scale *= View->ViewRect.Width();

		// We render a larger grid if we are zoomed out more (good precision at any scale)
		Radii *= 1.0f / Scale;
	}

	FVector2D UVMid = UVCameraPos * WorldToUVScale;
	float UVRadi = Radii * WorldToUVScale;

	FVector2D UVMin = UVMid + FVector2D(-UVRadi, -UVRadi);
	FVector2D UVMax = UVMid + FVector2D(UVRadi, UVRadi);

	// vertex pos is in -1..1 range
	DrawPlane10x10(PDI, ObjectToWorld, Radii, UVMin, UVMax, MaterialInst->GetRenderProxy(false), SDPG_World );
}
void FMaterialThumbnailScene::SetMaterialInterface(UMaterialInterface* InMaterial)
{
    check(PreviewActor);
    check(PreviewActor->GetStaticMeshComponent());

    bIsUIMaterial = false;
    if ( InMaterial )
    {
        // Transform the preview mesh as necessary
        FTransform Transform = FTransform::Identity;

        const USceneThumbnailInfoWithPrimitive* ThumbnailInfo = Cast<USceneThumbnailInfoWithPrimitive>(InMaterial->ThumbnailInfo);
        if ( !ThumbnailInfo )
        {
            ThumbnailInfo = USceneThumbnailInfoWithPrimitive::StaticClass()->GetDefaultObject<USceneThumbnailInfoWithPrimitive>();
        }

        UMaterial* BaseMaterial = InMaterial->GetBaseMaterial();

        // UI material thumbnails always get a 2D plane centered at the camera which is a better representation of the
        // what the material will look like on UI
        bIsUIMaterial = BaseMaterial && BaseMaterial->IsUIMaterial();
        EThumbnailPrimType PrimitiveType = bIsUIMaterial ? TPT_Plane : ThumbnailInfo->PrimitiveType.GetValue();

        switch( PrimitiveType )
        {
        case TPT_None:
        {
            bool bFoundCustomMesh = false;
            if ( ThumbnailInfo->PreviewMesh.IsValid() )
            {
                UStaticMesh* MeshToUse = Cast<UStaticMesh>(ThumbnailInfo->PreviewMesh.ResolveObject());
                if ( MeshToUse )
                {
                    PreviewActor->GetStaticMeshComponent()->SetStaticMesh(MeshToUse);
                    bFoundCustomMesh = true;
                }
            }

            if ( !bFoundCustomMesh )
            {
                // Just use a plane if the mesh was not found
                Transform.SetRotation(FQuat(FRotator(0, -90, 0)));
                PreviewActor->GetStaticMeshComponent()->SetStaticMesh(GUnrealEd->GetThumbnailManager()->EditorPlane);
            }
        }
        break;

        case TPT_Cube:
            PreviewActor->GetStaticMeshComponent()->SetStaticMesh(GUnrealEd->GetThumbnailManager()->EditorCube);
            break;

        case TPT_Sphere:
            // The sphere is a little big, scale it down to 256x256x256
            Transform.SetScale3D( FVector(0.8f) );
            PreviewActor->GetStaticMeshComponent()->SetStaticMesh(GUnrealEd->GetThumbnailManager()->EditorSphere);
            break;

        case TPT_Cylinder:
            PreviewActor->GetStaticMeshComponent()->SetStaticMesh(GUnrealEd->GetThumbnailManager()->EditorCylinder);
            break;

        case TPT_Plane:
            // The plane needs to be rotated 90 degrees to face the camera
            Transform.SetRotation(FQuat(FRotator(0, -90, 0)));
            PreviewActor->GetStaticMeshComponent()->SetStaticMesh(GUnrealEd->GetThumbnailManager()->EditorPlane);
            break;

        default:
            check(0);
        }

        PreviewActor->GetStaticMeshComponent()->SetRelativeTransform(Transform);
        PreviewActor->GetStaticMeshComponent()->UpdateBounds();

        // Center the mesh at the world origin then offset to put it on top of the plane
        const float BoundsZOffset = GetBoundsZOffset(PreviewActor->GetStaticMeshComponent()->Bounds);
        Transform.SetLocation(-PreviewActor->GetStaticMeshComponent()->Bounds.Origin + FVector(0, 0, BoundsZOffset));

        PreviewActor->GetStaticMeshComponent()->SetRelativeTransform(Transform);
    }

    PreviewActor->GetStaticMeshComponent()->SetMaterial(0, InMaterial);
    PreviewActor->GetStaticMeshComponent()->RecreateRenderState_Concurrent();
}
//! @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;
}
Пример #14
0
void UTexture::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	SetLightingGuid();

	// Determine whether any property that requires recompression of the texture, or notification to Materials has changed.
	bool RequiresNotifyMaterials = false;
	bool DeferCompressionWasEnabled = false;

	UProperty* PropertyThatChanged = PropertyChangedEvent.Property;
	if( PropertyThatChanged )
	{
		static const FName CompressionSettingsName("CompressionSettings");
		static const FName LODGroupName("LODGroup");
		static const FName DeferCompressionName("DeferCompression");
#if WITH_EDITORONLY_DATA
		static const FName MaxTextureSizeName("MaxTextureSize");
#endif // #if WITH_EDITORONLY_DATA

		const FName PropertyName = PropertyThatChanged->GetFName();
		if (PropertyName == CompressionSettingsName || PropertyName == LODGroupName)
		{
			RequiresNotifyMaterials = true;
		}
		else if (PropertyName == DeferCompressionName)
		{
			DeferCompressionWasEnabled = DeferCompression;
		}
#if WITH_EDITORONLY_DATA
		else if (PropertyName == MaxTextureSizeName)
		{
			if (MaxTextureSize <= 0)
			{
				MaxTextureSize = 0;
			}
			else
			{
				MaxTextureSize = FMath::Min<int32>(FMath::RoundUpToPowerOfTwo(MaxTextureSize), GetMaximumDimension());
			}
		}
#endif // #if WITH_EDITORONLY_DATA

		bool bPreventSRGB = (CompressionSettings == TC_Alpha || CompressionSettings == TC_Normalmap || CompressionSettings == TC_Masks || CompressionSettings == TC_HDR || CompressionSettings == TC_HDR_Compressed);
		if(bPreventSRGB && SRGB == true)
		{
			SRGB = false;
		}
	}
	else
	{
		FMaterialUpdateContext UpdateContext;
		// Update any material that uses this texture
		TSet<UMaterial*> BaseMaterialsThatUseThisTexture;
		for (TObjectIterator<UMaterialInterface> It; It; ++It)
		{
			UMaterialInterface* MaterialInterface = *It;
			if (DoesMaterialUseTexture(MaterialInterface, this))
			{
				UMaterial *Material = MaterialInterface->GetMaterial();
				bool MaterialAlreadyCompute = false;
				BaseMaterialsThatUseThisTexture.Add(Material, &MaterialAlreadyCompute);
				if (!MaterialAlreadyCompute)
				{
					UpdateContext.AddMaterial(Material);
					if (Material->IsTextureForceRecompileCacheRessource(this))
					{
						Material->UpdateMaterialShaderCacheAndTextureReferences();
					}
				}
			}
		}
		//If the DDC key was different the material is already recompile here
		RequiresNotifyMaterials = false;
	}

	NumCinematicMipLevels = FMath::Max<int32>( NumCinematicMipLevels, 0 );

	// Don't update the texture resource if we've turned "DeferCompression" on, as this 
	// would cause it to immediately update as an uncompressed texture
	if( !DeferCompressionWasEnabled && (PropertyChangedEvent.ChangeType & EPropertyChangeType::Interactive) == 0 )
	{
		// Update the texture resource. This will recache derived data if necessary
		// which may involve recompressing the texture.
		UpdateResource();
	}

	// Notify any loaded material instances if changed our compression format
	if (RequiresNotifyMaterials)
	{
		TArray<UMaterialInterface*> MaterialsThatUseThisTexture;

		// Create a material update context to safely update materials.
		{
			FMaterialUpdateContext UpdateContext;

			// Notify any material that uses this texture
			TSet<UMaterial*> BaseMaterialsThatUseThisTexture;
			for (TObjectIterator<UMaterialInterface> It; It; ++It)
			{
				UMaterialInterface* MaterialInterface = *It;
				if (DoesMaterialUseTexture(MaterialInterface,this))
				{
					MaterialsThatUseThisTexture.Add(MaterialInterface);

					// This is a bit tricky. We want to make sure all materials using this texture are
					// updated. Materials are always updated. Material instances may also have to be
					// updated and if they have static permutations their children must be updated
					// whether they use the texture or not! The safe thing to do is to add the instance's
					// base material to the update context causing all materials in the tree to update.
					BaseMaterialsThatUseThisTexture.Add(MaterialInterface->GetMaterial());
				}
			}

			// Go ahead and update any base materials that need to be.
			for (TSet<UMaterial*>::TConstIterator It(BaseMaterialsThatUseThisTexture); It; ++It)
			{
				UpdateContext.AddMaterial(*It);
				(*It)->PostEditChange();
			}
		}

		// Now that all materials and instances have updated send necessary callbacks.
		for (int32 i = 0; i < MaterialsThatUseThisTexture.Num(); ++i)
		{
			FEditorSupportDelegates::MaterialTextureSettingsChanged.Broadcast(MaterialsThatUseThisTexture[i]);
		}
	}
		
#if WITH_EDITORONLY_DATA
	// any texture that is referencing this texture as AssociatedNormalMap needs to be informed
	{
		TArray<UTexture*> TexturesThatUseThisTexture;

		for (TObjectIterator<UTexture> It; It; ++It)
		{
			UTexture* Tex = *It;

			if(Tex != this && Tex->CompositeTexture == this && Tex->CompositeTextureMode != CTM_Disabled)
			{
				TexturesThatUseThisTexture.Add(Tex);
			}
		}
		for (int32 i = 0; i < TexturesThatUseThisTexture.Num(); ++i)
		{
			TexturesThatUseThisTexture[i]->PostEditChange();
		}
	}
#endif
}