void UMaterialParameterCollection::PostLoad() { Super::PostLoad(); if (!StateId.IsValid()) { StateId = FGuid::NewGuid(); } CreateBufferStruct(); // Create an instance for this collection in every world for (TObjectIterator<UWorld> It; It; ++It) { UWorld* CurrentWorld = *It; CurrentWorld->AddParameterCollectionInstance(this, true); } }
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); }