UPROPERTY value not available in constructor?

I’m trying to set the color of a MaterialInstanceDynamic (MID) that is created in my constructor. I want to use the color that a user sets in the details panel, however, it looks like it is not picking up this value and instead is giving it a default FLinearColor(0,0,0,1). Here is the relevant code:

.h


private:
UMaterialInterface *MasterMaterialRef;			//reference to parameterized material template
UMaterialInstanceDynamic* WaterMaterialInstance;	//reference to parameterized material instance that will be used to manipulate vertex locations and normal map

public:
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Oasis")
TSubobjectPtr<UStaticMeshComponent> SurfaceMesh;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Oasis")
FLinearColor SurfaceColor;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Oasis")
float DampingFactor;

.cpp


SurfaceMesh = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("SurfaceMesh"));
SurfaceMesh->SetSimulatePhysics(false);
PrimaryActorTick.bCanEverTick = true;
//SurfaceColor = FColor(0, 0, 255, 255); //this works, but I can't change the color through details panel!

static ConstructorHelpers::FObjectFinder<UStaticMesh> waterMesh(TEXT("StaticMesh'/Game/Shapes/Shape_Plane.Shape_Plane'"));
static ConstructorHelpers::FObjectFinder<UMaterial> waterMaterial(TEXT("Material'/Game/Materials/M_Interactive_Water.M_Interactive_Water'"));

MasterMaterialRef = waterMaterial.Object;
SurfaceMesh->SetStaticMesh(waterMesh.Object);
WaterMaterialInstance = UMaterialInstanceDynamic::Create(MasterMaterialRef, this);
WaterMaterialInstance->SetVectorParameterValue(FName(TEXT("Color")), SurfaceColor);
SurfaceMesh->SetMaterial(0, WaterMaterialInstance);

RootComponent = SurfaceMesh;

Here is my MID setup:

https://dl.dropboxusercontent.com/u/33133319/M_Interactive_Water.jpg

Here, I’ve set the color to be lime green in the details panel, but as you can see, the surface is black:

https://dl.dropboxusercontent.com/u/33133319/Oasis.jpg

What’s interesting is that the DampingFactor works, however, the DampingFactor is used at every Tick whereas the color is only used in the constructor.

Anyone have ideas about what I’m doing wrong?

TIA

Values set in the editor aren’t set on the object until after the objects constructor is done. Based on what I’ve seen in the Shooter example I’ve been waiting until PostInitializeComponents and doing any set up that needs to wait for editor values there.

Thanks ChrisJD, that worked.

For others who may be interested, I did the following:

.h


virtual void PostInitializeComponents() override;     //added this

.cpp


//and defined it like so
void AOasisInteractiveWater::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	WaterMaterialInstance->SetVectorParameterValue(FName(TEXT("Color")), SurfaceColor);
	SurfaceMesh->SetMaterial(0, WaterMaterialInstance);
	setOasisTexture();
}

So I guess uproperties aren’t available to the c++ constructor.

The constructor is not called every time you modify a property on an object, only when it is initially created. The PostEditChange virtual is called when a property is changed in the editor, which also re-registers all components, hence the call to PostInitializeComponents, so that is a reasonable place to propagate changes.

This is a great answer, but where should I put similar code in classes that don’t derive from AActor? (UObject-derived stuff like assets)

Actually this doesn’t quite work for me, since PostInitializeComponents isn’t called in the editor.

Here is the horrible hack I ended up with:

.h:


UCLASS()
class AMyActor {
    ...
    virtual void Serialize(FArchive &Ar) override;
};

.cpp:


void AMyActor::Serialize(FArchive& ar)
{
    Super::Serialize();

    if(ar.IsLoading())
    {
        // initialization code that depends on editor properties here
    }
};

I need to go wash up, I feel dirty after this…

PostInitializeProperties() is the function that you want to override if you are going to do fixup or calculated values based upon property serialization. Otherwise, as James said, use the PostEditChange hooks in the editor to know when a property that you are interested in has changed.

Is there a similar call for when the editor loads? With your advice I have code that updates properly when properties change in the editor, and initializes properly on game startup, but on a fresh editor load my transient objects aren’t created, and so it’s broken until the first property modification.

There’s also PostLoad() you can use