I have a pretty simple setup for a RenderCanvasTarget2D in Blueprint which I am trying to recreate in C++, but it’s not working for some reason.
Here is the BP version:
In a BP derived from RenderCanvasTarget2D, this is the ‘Event Receive Update’ delegate function:
https://i.imgur.com/U8jMfjs.png
And then in a BP actor, I have this in BeginPlay:
https://i.imgur.com/ystjNyN.png
This successfully creates a CanvasRenderTarget2D of 128x128 pixels, writes a diagonal line across it, and saves it to the hard disk. All working perfectly.
In the C++ version, I am doing everything in a single actor called ‘HDRWriter’. Here is the full relevant code:
HDRWriter.h
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Runtime/Engine/Classes/Engine/CanvasRenderTarget2D.h"
#include "Runtime/Core/Public/Delegates/Delegate.h"
#include "Runtime/Engine/Classes/Engine/Canvas.h"
#include "Runtime/Engine/Classes/Kismet/KismetRenderingLibrary.h"
#include "HDRWriter.generated.h"
UCLASS()
class DRAWLINEBP_API AHDRWriter : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AHDRWriter();
// The Canvas Render Target 2D
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UCanvasRenderTarget2D* CanvasRenderTarget;
// Update Function
UFUNCTION()
void WhenCanvasUpdated(UCanvas* Canvas, int32 Width, int32 Height);
UFUNCTION(BlueprintCallable)
void CallUpdate();
UFUNCTION(BlueprintCallable)
void SetupCanvas();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
};
HDRWriter.cpp
#include "HDRWriter.h"
// Sets default values
AHDRWriter::AHDRWriter()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
}
void AHDRWriter::WhenCanvasUpdated(UCanvas* Canvas, int32 Width, int32 Height)
{
Canvas->K2_DrawLine(FVector2D(0.0f, 0.0f), FVector2D(Width, Height));
UKismetRenderingLibrary::ExportRenderTarget(GEngine->GetWorld(), CanvasRenderTarget, "D:\\", "CPPLine.hdr");
}
void AHDRWriter::CallUpdate()
{
CanvasRenderTarget->UpdateResource();
}
void AHDRWriter::SetupCanvas()
{
CanvasRenderTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(GEngine->GetWorld(), UCanvasRenderTarget2D::StaticClass(), 128, 128);
CanvasRenderTarget->OnCanvasRenderTargetUpdate.AddDynamic(this, &AHDRWriter::WhenCanvasUpdated);
}
// Called when the game starts or when spawned
void AHDRWriter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AHDRWriter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
So I run SetupCanvas to create the CanvasRenderTarget2D and bind a function (WhenCanvasUpdated) to the delegate OnCanvasRenderTargetUpdate. When I then call CallUpdate() it calls UpdateResource() on the CanvasRenderTarget.
When the function WhenCanvasUpdated() is then run, it should draw a line and save the file to the hard disk, as with the Blueprint version.
However, a file is indeed saved, but it is totally black - no line is drawn. I feel like I’m missing some important connection between the RenderCanvasTarget and the UCanvas that is passed in the delegate function, but I can’t see how they should be connected.
I tried nativizing the BP into C++ code, but found it to be completely illegible.
Does anyone know what I’m doing wrong here?
Thanks!