Canvas render target functionality changed

Hey guys,

So around 4.5 Epic changed something behind the scenes, breaking some code I was using for a couple projects. They used render targets with a canvas to draw onto a texture, a handy trick for masking between shaders. I grumped and groused over this, asked help from a few friends as well as the IRC, and nobody could work out how to use this functionality now. I put off asking here because :mad: but I’ve got the itch to revive these projects that got killed.

I figure to start with, I’d post some code showing two methods I worked out to accomplish this. The first uses the CanvasRenderTarget2D class, which as far as I worked out had a limitation. The code cleared the texture every frame, making persistent drawing onto the texture impossible.

The finished product (minus shaders) can be seen here:


The code just draws a given texture centered on the given coordinates, and expands it over time. It worked great for this water rings effect.

The second method I worked out preserves the texture, allowing you to draw over what was already written onto the texture. It doesn’t use CanvasRenderTarget2D, instead setting up the texture resource and Canvas at runtime. This was a bear to get together, as C++ and I have a mutual hatred. But I got it working from poring over half-baked examples on the Answerhub.

The finished product (Again just showing the raw texture) is here:


I used this effect for masking between dirty/fresh ice in a Zamboni game I’ve been tinkering with for ages, but when I went to mess about with another project using this system I was a bit suprised to find it crashed the engine.

The second method crashes with the following error:
Fatal error: [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.5\Engine\Source\Runtime\RenderCore\Private\RenderingThread.cpp] [Line: 641]
Rendering thread exception:
Assertion failed: IsInGameThread() [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.5\Engine\Source\Runtime\Engine\Private\GlobalShader.cpp] [Line: 341]

I guessed the issue is the Canvas->Flush() call, since according to the documentation there’s an alternative to this to flush in the rendering thread. It requires a convoluted argument, which it took myself and about 3 people on IRC to figure out how to even get. And using that it still crashes.

The first method just crashes on this line in BeginPlay()


CanvasTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(UCanvasRenderTarget2D::StaticClass(), 1024, 1024);

Any ideas? Canvas render targets are useful things, and whatever got changed pretty much sunk one project of mine that I was working on.

This looks really useful for me too so I really hope they fix this, or that there is a solution, but I don’t have a clue… Good luck

Hey Enos,

Thank you for sharing your code. I tried your snippets with the latest engine binary build (4.8.1). All went well until I tried to actually flush the canvas, like you said.

Can we get some Epic Staff member to provide some info on the following functionality:

How and where is the following call supposed to be made:

FCanvas::Flush_GameThread()

OR

FCanvas::Flush_RenderThread()

I personally tried the GameThread method and that caused the IsInGameThread() check assertion to fail.

If we can get this working, I think it could be quite useful in handful of situations. If anyone else has any ideas or experience with this, please feel free to share.

Enosshenk, can you please message me… I’ve been trying to track you down with a question about your Oculus Rift tower climbing game… Much appreciated!