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. 

Could I get some help with CanvasRenderTarget2D?

Hi all! Just got the new preview code for 4.2 and got it compiled to try the new UCanvasRenderTarget2D. But I can't make it work.

My class' header :

 #pragma once
 
 #include "GameFramework/Actor.h"
 #include "TestTarget.generated.h"
 
 UCLASS()
 class ATestTarget : public AActor
 {
     GENERATED_UCLASS_BODY()
 public:
     UFUNCTION()
     virtual void OnReceiveUpdate(class UCanvas* Canvas, int32 Width, int32 Height);
 
     UPROPERTY(BlueprintReadOnly, Category = TestTarget)
     class UCanvasRenderTarget2D* CanvasTarget;
 
     UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = TestTarget)
     UTexture* TestTile;
 };

And cpp file :

 #include "MyFlightSim.h" // Placeholder game name
 #include "TestTarget.h"
 
 #include "Engine/CanvasRenderTarget2D.h"
 
 ATestTarget::ATestTarget(const class FPostConstructInitializeProperties& PCIP)
     : Super(PCIP)
 {
     CanvasTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(UCanvasRenderTarget2D::StaticClass(), 1024, 1024);
     CanvasTarget->OnCanvasRenderTargetUpdate.AddDynamic(this, &ATestTarget::OnReceiveUpdate);
     CanvasTarget->ClearColor = FLinearColor::Black;
 }
 
 void ATestTarget::OnReceiveUpdate(class UCanvas* Canvas, int32 Width, int32 Height)
 {
     if (GEngine)
         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TestTarget Received Update!"));
     Canvas->SetDrawColor(0, 255, 0);
     Canvas->DrawTile(TestTile, 0, 0, Width, Height, 0, 0, TestTile->GetSurfaceWidth(), TestTile->GetSurfaceHeight());
 }

But the message is never shown! I inherit from this Actor in Blueprint with a root StaticMesh component (Cube Shape) with a simple instance from a material which has a single Texture2D parameter. In the Blueprint's construction graph, I assign to this parameter the property CanvasTarget. The ClearColor is not even updated!

Please help!

Product Version: Not Selected
Tags:
more ▼

asked May 16 '14 at 01:35 AM in C++ Programming

avatar image

Numsgil
33 4 7 10

avatar image Rama May 16 '14 at 10:44 PM

I've notified the author of this update about your concern.

It might take a few days but he should get back to you

Rama

avatar image Numsgil May 17 '14 at 01:14 PM

I made some changes to my code and the Blueprint now does nothing except assigning default values, setting the root component to be a Cube and assigning the target to my material instance.

The new class cpp : UCanvasRenderTarget2D* ATestTarget::ConstructTarget(int32 Width, int32 Height) { if (Width > 0 && Height > 0) { UCanvasRenderTarget2D* NewCanvasRenderTarget = ConstructObject(UCanvasRenderTarget2D::StaticClass(), GetTransientPackage()); if (NewCanvasRenderTarget) { NewCanvasRenderTarget->InitAutoFormat(Width, Height); return NewCanvasRenderTarget; } }

     return nullptr;
 }
 
 ATestTarget::ATestTarget(const class FPostConstructInitializeProperties& PCIP)
     : Super(PCIP)
 {
 }
 
 void ATestTarget::OnReceiveUpdate(class UCanvas* Canvas, int32 Width, int32 Height)
 {
     if (GEngine)
         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TestTarget Received Update!"));
 }
 
 void ATestTarget::BeginPlay()
 {
     Super::BeginPlay();
     CanvasTarget = ConstructTarget(1024, 1024);
     CanvasTarget->OnCanvasRenderTargetUpdate.AddDynamic(this, &ATestTarget::OnReceiveUpdate);
     CanvasTarget->ClearColor = FLinearColor::Black;
     CanvasTarget->UpdateResource();
 
     if (GEngine)
         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TestTarget Received BeginPlay!"));
 }

The ConstructTarget is a static function that is copied from the UCanvasRenderTarget2D::CreateCanvasRenderTarget2D because, for unknown reasons, the parameters are garbage (used VS2013 debugger to find out , i.e. Width = 44 & Height = -12754). My debug messages are shown but the material is not black (it is brownish). Made some checks using the debugger and the UCanvasRenderTarget2D functions don't seem to be called properly (null variables when a value is expected, weird parameters). I'm completely lost but there is progress.

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

5 answers: sort voted first

I found a way to make it work, thanks to @Solid-Snake! Here is my Actor's C++ code for future reference.

TestTarget.h :

 #pragma once
 
 #include "GameFramework/Actor.h"
 #include "TestTarget.generated.h"
 
 UCLASS()
 class ATestTarget : 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;
 };

TestTarget.cpp :

 #include "MyFlightSim.h" // Placeholder Game Name
 #include "TestTarget.h"
 
 #include "Engine/CanvasRenderTarget2D.h"
 #include "RenderUtils.h"
 
 ATestTarget::ATestTarget(const class FPostConstructInitializeProperties& PCIP)
     : Super(PCIP), SurfaceWidth(512), SurfaceHeight(512), MaterialInstance(nullptr), ParameterName(TEXT("Texture"))
 {
 }
 
 void ATestTarget::BeginPlay()
 {
     Super::BeginPlay();
     CanvasTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(UCanvasRenderTarget2D::StaticClass(), SurfaceWidth, SurfaceHeight);
     CanvasTarget->OnCanvasRenderTargetUpdate.AddDynamic(this, &ATestTarget::OnReceiveUpdate);
     CanvasTarget->UpdateResource();
 
     if (MaterialInstance != nullptr)
         MaterialInstance->SetTextureParameterValue(ParameterName, CanvasTarget);
 
     if (GEngine)
         GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TestTarget Received BeginPlay!"));
 }
 
 void ATestTarget::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!"));
 }

To make it work, create a material with a named Texture2DParameter, assign it to an Actor Blueprint subclassing this class, adjust the defaults (surface size and parameter name). In the Construction Script, create a DynamicMaterialInstance and assign it to the property MaterialInstance.

I might be doing a Wiki page on this later. Thanks, awesome community!

more ▼

answered May 18 '14 at 12:47 PM

avatar image

Numsgil
33 4 7 10

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

Here is a minimum test case example that I quickly whipped up to test.

BlankCPPHUD.h:

 #pragma once
 
 #include "RenderUtils.h"
 #include "Engine/CanvasRenderTarget2D.h"
 #include "GameFramework/HUD.h"
 #include "BlankCPPHUD.generated.h"
 
 /**
  * 
  */
 UCLASS()
 class ABlankCPPHUD : public AHUD
 {
     GENERATED_UCLASS_BODY()
 
 public:
     /** PostRender is the main draw loop. */
     virtual void PostRender() OVERRIDE;
 
     /** Delegate bound to the canvas render target to draw onto it. */
     UFUNCTION()
     virtual void DrawCanvasRenderTarget(class UCanvas* RenderTargetCanvas, int32 Width, int32 Height);
 
     /** Pointer to the canvas render target. */
     UPROPERTY()
     class UCanvasRenderTarget2D* MyCanvasRenderTarget;
 };

BlankCPPHUD.cpp:

 #include "BlankCPP.h"
 #include "BlankCPPHUD.h"
 
 ABlankCPPHUD::ABlankCPPHUD(const class FPostConstructInitializeProperties& PCIP)
 : 
 Super(PCIP)
 {
     MyCanvasRenderTarget = nullptr;
 }
 
 void ABlankCPPHUD::PostRender()
 {
     Super::PostRender();
 
     if (MyCanvasRenderTarget == nullptr)
     {
         MyCanvasRenderTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(UCanvasRenderTarget2D::StaticClass(), 256, 256);
 
         if (MyCanvasRenderTarget != nullptr)
         {
             MyCanvasRenderTarget->OnCanvasRenderTargetUpdate.AddDynamic(this, &ABlankCPPHUD::DrawCanvasRenderTarget);
             MyCanvasRenderTarget->UpdateResource();
         }
     }
     
     if (MyCanvasRenderTarget != nullptr)
     {
         Canvas->SetDrawColor(255, 255, 255);
         Canvas->DrawTile(MyCanvasRenderTarget, 0.0f, 0.0f, MyCanvasRenderTarget->GetSurfaceWidth(), MyCanvasRenderTarget->GetSurfaceHeight(), 0.0f, 0.0f, MyCanvasRenderTarget->GetSurfaceWidth(), MyCanvasRenderTarget->GetSurfaceHeight(), BLEND_Opaque);
     }
 }
 
 void ABlankCPPHUD::DrawCanvasRenderTarget(class UCanvas* RenderTargetCanvas, int32 Width, int32 Height)
 {
     if (RenderTargetCanvas != nullptr)
     {
         FCanvasTileItem WhiteBox = FCanvasTileItem(FVector2D(0.0f, 0.0f), GWhiteTexture, FVector2D(Width, Height), FLinearColor(1.0f, 1.0f, 1.0f));
         RenderTargetCanvas->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));
         RenderTargetCanvas->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));
         RenderTargetCanvas->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));
         RenderTargetCanvas->DrawItem(BlueBox);
     }
 }

If you wish to copy this code into your project, make sure to add RenderCore to PrivateDependencyModuleNames array in your project's build configuration. ClearColor is also only an inherited variable from Render Targets and are not used in Canvas Render Target.

I get the feeling that it may be due to the mixture of Blueprints and C++ causing the problems as I only tested either a full Blueprint method or a full C++ method. However, I can't imagine that it would cause too many issues if the order of operations is done correctly.

Lastly remember when you debug things to ensure you are running in Debug Editor. Debugging in Development Editor usually leads to Visual Studio reporting strange values for variables.

Hopefully this code examples helps you to solve the problem on your end.

more ▼

answered May 17 '14 at 02:53 PM

avatar image

Solid Snake
41 1 2 2

avatar image Numsgil May 17 '14 at 09:22 PM

Cool! This is working! Now, how do I assign this material to an in-game Actor?

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

You should not be using the Actor's C++ constructor to create the canvas render target.

Try overriding AActor::BeginPlay() and putting it in there instead.

more ▼

answered May 16 '14 at 11:23 PM

avatar image

Solid Snake
41 1 2 2

avatar image Numsgil May 17 '14 at 03:02 AM

Thanks! Now the event is called but there is still nothing to see...Could anyone post a quick Canvas draw listing for a test, please?

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

Pretty sure DrawTile now uses normalized coordinates for UV.

more ▼

answered May 17 '14 at 03:09 AM

avatar image

Solid Snake
41 1 2 2

avatar image Numsgil May 17 '14 at 04:06 AM

Tried it on DrawTexture, but is DrawTile better?

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

Hmm, I'm looking at your code and what is it that calls UCanvasRenderTarget2D::UpdateResource()? I also assume that TestTile is also valid?

I haven't yet synched with 4.2 preview yet, but I'll check it out when it has been released. However, when I was developing this feature it was working for me for both C++ and Blueprints.

more ▼

answered May 17 '14 at 05:54 AM

avatar image

Solid Snake
41 1 2 2

avatar image Numsgil May 17 '14 at 06:45 AM

The UpdateResource was called from the Blueprint in a BeginPlay event, but I moved it to the class' BeginPlay function. I assign a texture to TestTile in the Blueprint's Defaults.

(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