x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Office Holiday

Epic Games' offices will be on holiday from June 22nd to July 7th. During this period support will be limited. Our offices will reopen on Monday, July 8th. 

Why is my C++ UMaterialInstanceDynamic not accepting parameter changes?

Hey everyone!

EDIT: Further investigation reveals that the material is updating fine - variables edited on the instance of the component attached to the actor just aren't updating.

I'm working on a character customization system component in C++, and I'm having trouble getting my MIDs to update. I have materials declared in my header like this:

     UPROPERTY(BlueprintReadOnly, Category = "Owning Actor")
         USkeletalMeshComponent* Mesh;
 
     UPROPERTY(EditDefaultsOnly, Category = "Materials")
         UMaterial* HairMaterial;
 
     UPROPERTY(EditDefaultsOnly, Category = "Materials")
         UMaterial* SkinMaterial;
 
     UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Materials")
         UMaterial* AlphaMaterial;
 
     UPROPERTY(BlueprintReadOnly, Category = "Materials")
         UMaterialInstanceDynamic* Hair;
 
     UPROPERTY(BlueprintReadOnly, Category = "Materials")
         UMaterialInstanceDynamic* Skin;
 

and I'm attempting to set vector and texture parameter values from both C++ and Blueprint. However, any change I try to make to the instance is silently rejected, and the actor I have this component attached to doesn't update. I've tried changing my MID variables from BlueprintReadOnly to BlueprintReadWrite, but that didn't help.

My source file looks like this. The last two functions are a product of desperation, and they aren't applying any changes either. The last function contains some debug that should print the updated colour, but only prints out the default value.

 // Sets default values for this component's properties
 UCharacterCustomizationComponent::UCharacterCustomizationComponent()
 {
     // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
     // off to improve performance if you don't need them.
     bWantsInitializeComponent = true;
     PrimaryComponentTick.bCanEverTick = true;
 
     PrimaryComponentTick.bStartWithTickEnabled = false;
     bReplicates = true;
     bAutoActivate = true;
 
     // ...    
 }
 
 
 // Called when the game starts
 void UCharacterCustomizationComponent::InitializeComponent()
 {
     Super::InitializeComponent();
 
     // ...
     
 }
 
 
 // Called every frame. Is not enabled by default.
 void UCharacterCustomizationComponent::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
 {
     Super::TickComponent( DeltaTime, TickType, ThisTickFunction );
 
     // ...
 }
 
 void UCharacterCustomizationComponent::PostInitProperties()
 {
     Super::PostInitProperties();
 
     ACharacter* Character = Cast<ACharacter>(GetOwner());
     if (Character)
     {
         Mesh = Character->GetMesh();
 
         //Apply the skin to all skin elements        
         Skin = UMaterialInstanceDynamic::Create(SkinMaterial, this);        
         if (Skin)
         {
             for (auto Iter(SkinElements.CreateIterator()); Iter; Iter++)
             {
                 Mesh->SetMaterial(*Iter, Skin);
             }
         }
         
         //Apply the hair to all hair elements
         Hair = UMaterialInstanceDynamic::Create(HairMaterial, this);
         if (Hair)
         {
             for (auto Iter(HairElements.CreateIterator()); Iter; Iter++)
             {
                 Mesh->SetMaterial(*Iter, Hair);
             }
         }
     }
 
     //make sure the overriding blueprint sets all of its values proper in this event.
     OnSettingsChanged();
 }
 
 void UCharacterCustomizationComponent::SetSkinVectorParameter(FName Key, FLinearColor Colour)
 {
     if (Skin)
     {
         Skin->SetVectorParameterValue(Key, Colour);
     }    
 }
 
 void UCharacterCustomizationComponent::SetHairVectorParameter(FName Key, FLinearColor Colour)
 {
     if (Skin)
     {
         Hair->SetVectorParameterValue(Key, Colour);
         if (GEngine)
         {
             GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, TEXT("stuff"));
             FLinearColor Colour2;
             Hair->GetVectorParameterValue(Key, Colour2);
             GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, Colour2.ToString());
         }
     }    
 }
Product Version: Not Selected
Tags:
more ▼

asked Apr 10 '15 at 06:53 AM in C++ Programming

avatar image

Jargon
808 39 30 65

avatar image Moss Apr 10 '15 at 07:27 AM

Could it be that the loop is not setting the instance to the actual mesh?

avatar image Jargon Apr 10 '15 at 07:58 AM

No, the mesh is definitely getting the material set - it shows up, and if I change any settings in the component (and not the instance attached to my actor) the change is applied.

avatar image staticvoidlol Apr 10 '15 at 07:48 AM

Not sure if this will help, but I set my params slightly differently, e.g.

 UStaticMeshComponent* meshComp = mesh->GetStaticMeshComponent();
 
 if (meshComp)
 {
     UMaterialInstanceDynamic* meshCompMat = meshComp->CreateAndSetMaterialInstanceDynamic(0);
 
     if (meshCompMat)
     {
         meshCompMat->SetScalarParameterValue(YourStaticMeshMaterialParamFName, newValue);
     }
 }

i.e. I create a MaterialInstanceDynamic from the existing material (in slot 0) and then set param values from that reference.

avatar image Jargon Apr 10 '15 at 08:00 AM

Thanks for the suggestion! This would have me creating a new instance for every element, though, and I'd like to avoid that.

avatar image staticvoidlol Apr 10 '15 at 08:12 AM

Sure, makes sense.

However, I recall vaguely from UE3 that this was actually the only way to do it, as there is a lot of black magic going on in the background. I honestly don't know the details, but maybe it's worth trying out to see if it works?

avatar image Moss Apr 10 '15 at 08:14 AM

have tried creating the material in the construction script? Try it first in BP and then in C++ within the OnContruct method, just to check that the base logic is ok.

avatar image Jargon Apr 10 '15 at 09:23 AM

This was originally all in the character's blueprint (where I did create the instances in the constructor) and it worked fine there. If I move the Skin and Hair assignments to the constructor in C++, the asset references haven't been properly loaded yet and they're set to null.

avatar image Moss Apr 10 '15 at 09:31 AM

You create them in the constructor in BP? You mean the construction script I guess.

avatar image Jargon Apr 10 '15 at 09:35 AM

Originally, yes, but that was before I made this functionality a component instead. It's all in C++ now, save for the parameter changes which are in the component's BP. Additionally, I can't seem to assign any materials to the mesh from BP either.

avatar image Jargon Apr 10 '15 at 12:03 PM

Okay, after some additional testing it seems like the values aren't even getting updated on the instance when I fiddle with them on the actor.

I changed my debug function to this:

 void UCharacterCustomizationComponent::SetHairVectorParameter(FName Key, FLinearColor Colour)
 {
     if (Skin)
     {
         Hair->SetVectorParameterValue(Key, Colour);
         if (GEngine)
         {
             GEngine->AddOnScreenDebugMessage(-1, 5, Colour, TEXT("InValue"));
             FLinearColor Colour2;
             Hair->GetVectorParameterValue(Key, Colour2);
             GEngine->AddOnScreenDebugMessage(-1, 5, Colour2, TEXT("ReadValue"));
         }
     }    
 }

and hooking it up like this in BP produces an output where InValue and Result are the same, no matter what value I set it to.

alt text

Attempting to connect a print string to some of my Enums produces a hard crash, and the colour value never changes from its default. what the fuuu

componentbp.png (294.6 kB)
(comments are locked)
10|2000 characters needed characters left
Viewable by all users

2 answers: sort voted first

Okay, I managed to fix it!

The problem was a classic PLBCAC (problem lies betwen chair and computer), and I had misunderstood how InitializeComponent was fired. I was under the assumption that it only fired on BeginPlay and was as such not useable for me. This is not the case, and it fires as a last-step construction event.

Moving all of my logic to InitializeComponent allows all values to be loaded and initialized correctly before I attempt to access them, and my mesh gets everything assigned properly. Having the logic in PostEditChangeProperty sort of worked, but it produced a quick flash of my MID before all materials reset.

So, in short - PLBCAC, move logic to InitializeComponent to fix most anything.

A big thanks to everyone who helped out on the way!

more ▼

answered Apr 10 '15 at 01:07 PM

avatar image

Jargon
808 39 30 65

avatar image emperor_katax Oct 05 '17 at 11:53 AM

Can you please check my post? I have exact same iissue and not sure how to fix....

link text

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Where is the Value "Key" set?

Make sure you use the text menu and that the names match the parameter in the material perfectly. It IS case-sensitive in some cases.

You could just replace "Key" with : TEXT("ParamName")

more ▼

answered Apr 10 '15 at 08:43 AM

avatar image

TheJamsh
815 59 97 140

avatar image Jargon Apr 10 '15 at 09:25 AM

The last two functions aren't used anywhere but my attempts to get this working - normally, the parameter logic is all in BP where it's a normal SetVectorParameter node from either the Skin or Hair variable.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question