Named material paramaters not being found (help with CanvasRenderTarget2D)

Hey guys,

Huge UE4 noob here, coming from various other engines.

I’m trying to make a game where you paint on the world, so I’m looking to leverage CanvasRenderTarget2D to have some code paint the textures in my game.

So far I’ve found this guy looking for a tutorial, the same guy reported a crash TTP #349656, and most helpfully this guy had a back and forth discussion with the user solid-snake who I believe was the origonal author of this feature.

I’ve attempted to implement what was roughly outlined in this discussion and am having an issue. Before I describe the issue too much, here’s what I’ve tried:

TestPaintActor.h

UCLASS()
class FPS_API ATestPaintActor : public AActor
{
	GENERATED_UCLASS_BODY()

public:
	UFUNCTION()
	virtual void OnReceiveUpdate(class UCanvas* Canvas, int32 Width, int32 Height);

	virtual void BeginPlay() override;

	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = Target)
	int32 SurfaceWidth;

	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = Target)
	int32 SurfaceHeight;

	UPROPERTY(BlueprintReadWrite, Category = Target)
	class UMaterialInstanceDynamic* MaterialInstance;

	UPROPERTY(EditDefaultsOnly, Category = Target)
	FName ParameterName;

protected:
	UPROPERTY()
	class UCanvasRenderTarget2D* CanvasTarget;
};

TestPaintActor.cpp

ATestPaintActor::ATestPaintActor(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP), SurfaceWidth(512), SurfaceHeight(512), MaterialInstance(nullptr), ParameterName(TEXT("Texture"))
{

}

void ATestPaintActor::BeginPlay()
{
	Super::BeginPlay();
	CanvasTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(UCanvasRenderTarget2D::StaticClass(), SurfaceWidth, SurfaceHeight);
	CanvasTarget->OnCanvasRenderTargetUpdate.AddDynamic(this, &ATestPaintActor::OnReceiveUpdate);
	CanvasTarget->ClearColor = FLinearColor::Black;

	if (MaterialInstance != nullptr)
		MaterialInstance->SetTextureParameterValue(ParameterName, CanvasTarget);

	CanvasTarget->UpdateResource();

	if (GEngine)
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TestTarget Received BeginPlay!"));
}

void ATestPaintActor::OnReceiveUpdate(class UCanvas* Canvas, int32 Width, int32 Height)
{
	FCanvasTileItem WhiteBox = FCanvasTileItem(FVector2D(0.0f, 0.0f), GWhiteTexture, FVector2D(Width, Height), FLinearColor(1.0f, 1.0f, 1.0f));
	Canvas->DrawItem(WhiteBox);

	FCanvasTileItem RedBox = FCanvasTileItem(FVector2D(Width * 0.1f, Height * 0.1f), GWhiteTexture, FVector2D(Width * 0.8f, Height * 0.8f), FLinearColor(1.0f, 0.0f, 0.0f));
	Canvas->DrawItem(RedBox);

	FCanvasTileItem GreenBox = FCanvasTileItem(FVector2D(Width * 0.2f, Height * 0.2f), GWhiteTexture, FVector2D(Width * 0.6f, Height * 0.6f), FLinearColor(0.0f, 1.0f, 0.0f));
	Canvas->DrawItem(GreenBox);

	FCanvasTileItem BlueBox = FCanvasTileItem(FVector2D(Width * 0.3f, Height * 0.3f), GWhiteTexture, FVector2D(Width * 0.4f, Height * 0.4f), FLinearColor(0.0f, 0.0f, 1.0f));
	Canvas->DrawItem(BlueBox);

	if (GEngine)
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TestTarget Received Update!"));
}

And in unreal I’ve created this material, TestPaintMat
I’m using WorldAlignedTexture because I couldn’t find a way to actually sample the ParamTexObject I created…

I created this blueprint, TestPaintBP which is setup to reference PaintParam and is parented to TestPaintActor.h it also has a static mesh referencing the material above. This ‘mMesh’ is what I’m using in the construction script too, for what that’s worth. :slight_smile:

Of course I have an instance of TestPaintBP in the scene. My C++ class is being hit just fine and when I update my material I see the changes in the scene. So as far as I can tell everything is linked properly…

The issue is when I call SetTextureParameterValue on my material instance. It gets to UMaterialInstanceDynamic::SetTextureParameterValue and then into SetTextureParameterValueInternal and finally to GameThread_FindParameterByName which finds zero parameters, returning null.

I’m not sure if this is the root of my issue, but this is as far as I’ve gotten and it seems problematic that no named parameters are found at all. Of course since I mentioned above that I’m a bit derpy in the material editor, I’m guessing I just setup my material wrong.

Any help is appreciated! Thanks.

Simple enough, I just had to assign the material to the mesh once the dynamic material was created.

I was also getting issues where I was unable to save my scene with this blueprint code in the constructor script. To fix this I moved the entire blueprint code executing out of the purple construction script wire and moved it into its own new function “Assign Test Paint Material”. Then in my level blueprint I hooked the function up to the “Event Begin Play” as seen below. This seemed to solve my issue of being unable to save.

22040-2014-11-24_11-58-43.png