Hi,
I have an AActor derived C++ class which contains many Scene Components. Four of these are cable components.
I initialise them in the constructor using this code:
UMaterial* RedCable = LoadObject<UMaterial>(nullptr, TEXT("/Game/Materials/ElectricalCable_Red"));
....
Arm1Cable = CreateDefaultSubobject<UCableComponent>(TEXT("Arm1Cable"));
....
Arm1Cable->AttachToComponent(Arms_1_2_Sphere, FAttachmentTransformRules::KeepRelativeTransform);
Arm1Cable->AttachEndTo.ComponentProperty = FName(TEXT("MidArm1"));
Arm1Cable->EndLocation = FVector(0.000000, -20.000000, 0.000000);
Arm1Cable->CableLength = 60;
Arm1Cable->NumSegments = 15;
Arm1Cable->CableWidth = 3;
Arm1Cable->SetMaterial(0, BlueCable);
However, when i do this, the material remains as the default material, rather than the material “BlueCable”.
If i do the following, which is how “Nativize Blueprint” does it, it works fine, but somehow seems to have code smell as it directly addresses members:
Arm1Cable->OverrideMaterials = TArray<UMaterialInterface*> ();
Arm1Cable->OverrideMaterials.Reserve(1);
Arm1Cable->OverrideMaterials.Add(BlueCable);
Is this a bug? Should i be approaching the initialization of the cable actor in a different way? The same SetMaterial works fine for static meshes…
Thanks!
I went to read the source and try and identify the problem myself and came across this in MeshComponent.h:
/** Per-Component material overrides. These must NOT be set directly or a race condition can occur between GC and the rendering thread. */
UPROPERTY(EditAnywhere, AdvancedDisplay, Category=Rendering, Meta=(ToolTip="Material overrides."))
TArray<class UMaterialInterface*> OverrideMaterials;
So, what you’re saying here is you shouldn’t EVER directly write to this property, or ‘here be dragons’, yet the code produced by ‘Nativize Assets’ does so… and works? I’m confused! Perhaps something else to look into?
Hello ,
That warning is there to let you know not to set it, as it can be only be set at certain times and on the correct thread. Technically can be done but you need to know what you’re doing otherwise it can cause problems. When looking at your original code, where is BlueCable being initialized and how is it being done?
BlueCable is initialised in the constructor in the same way as RedCable, I miss pasted the wrong line and wanted to paste the BlueCable line. It’s initialised above the CreateDefaultSubobject call in the same function.
I apologize for the delay, . I’ve not had time to look at this. I attempted to put together a similar project today and noticed what the problem is. Please change BlueCable to be a UMaterialInterface instead of a UMaterial. UMaterialInterface is what the SetMaterial function is looking for. After doing this, it should work correctly. If it isn’t, please try creating another blueprint based off the class and see if it works with the new one.
Thanks, that has fixed it!
How come using UMaterial* works fine everywhere else? Shouldn’t UMaterial work, as it is directly inherited from UMaterialInterface?
Thanks again!
Oddly enough, trying to reproduce this to bug the fact that UMaterials won’t work is ending up with it working correctly. I’m actually not able to get it to have the same behavior as before when using UMaterial instead of UMaterialInterface.
That’s strange. Did you ever get to the bottom of why it suddenly started working for you? (as it never worked for me when using UMaterial and still requires use of UMaterialInterface).