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 C++ and I hate each other, 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 UCanvasRenderTarget2D class, which as far as I worked out had a limitation. The class clears the texture every frame, making persistent drawing onto the texture impossible.
[SinkWater.h][1]
[SinkWater.cpp][2]
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. When used in 4.6 it crashes the engine as follows:
CanvasTarget = UCanvasRenderTarget2D::CreateCanvasRenderTarget2D(UCanvasRenderTarget2D::StaticClass(), 1024, 1024);
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 UCanvasRenderTarget2D, 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.
[RenderTargetDemo.h][4]
[RenderTargetDemo.cpp][5]
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. After the update that introduced non-experimental UMG I went back into this project to work on the UI, and was suprised to find the code that worked fine previously crashes the engine.
The second method crashes with the following error:
Fatal error: [File:\BuildFarm\buildmachine_++depot+UE4-Releases+4.5\Engine\Source\Runtime\RenderCore\Private\RenderingThread.cpp] [Line: 641]
Rendering thread exception:
Assertion failed: IsInGameThread() [File:\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. I don’t have exact errors for this, because it was done over the course of a couple days of trying everything I could think of, while getting progressively angrier at C++.
Any ideas? Canvas render targets are useful things, and whatever got changed pretty much sunk one project of mine that I was working on.