1
\$\begingroup\$

I have a project where I'm playing with a video feedback effect by rendering a camera to a RenderTexture and pointing the camera at a quad displaying that RenderTexture.

This works great normally, but when trying out HDRP, LWRP, (and upgrading materials) or upgrading the entire project to 2018.3, the RenderTexture just stops working and shows black. I also tried with a completely new project and just had a camera, a quad, and a cube. That also didn't work.

Is there any obvious reason this wouldn't be working? I spent a while trying out various settings but couldn't find anything that had any effect, so I really don't even know where to start.

\$\endgroup\$
  • \$\begingroup\$ Usually we solve this by "ping-ponging" two render targets: one to read from.this frame, and one to write to. Next frame, we flip their roles. It's possible Unity used to do this automatically for you (or create a copy for reading) when you tried to draw to a render texture that's in use, and the new pipelines don't, and just skip reading instead. Do you find any difference if you try creating your feedback effect through ping-ponging this way? \$\endgroup\$ – DMGregory Mar 25 at 8:36
  • \$\begingroup\$ I figured it could be done manually like that, but I was trying to avoid it because I assumed Unity's internal rendering code would be much faster than whatever I came up with. I'll give it a shot tomorrow and see what happens, but it still seems odd that seeing an RT would go from a feedback effect as expected to just rendering nothing at all. \$\endgroup\$ – Appleguysnake Mar 25 at 11:34
  • \$\begingroup\$ Detecting that you're trying to do this (by checking the visibility of every RT in every render pass) and making the necessary copies costs performance, so this is one area where doing it yourself might actually be faster than counting on the engine to fix it automatically. \$\endgroup\$ – DMGregory Mar 25 at 11:39
  • \$\begingroup\$ Hmm, I was assuming it worked the other way and the feedback effect was from the engine not caring there was an RT in front of it (because it would only add one layer of recursion per frame) and maybe they specifically prevented it in the new rendering engine. Now I don't know what to think! \$\endgroup\$ – Appleguysnake Mar 25 at 11:54
  • \$\begingroup\$ I remembered I had a script that did something similar so I modified that instead of going to sleep, and it seems to work fine if you just render the camera to an RT and copy that to a second RT in the scene. I'm still really confused by why it doesn't work by default, I can't really think of a reason why you'd need to actively prevent feedback like that? \$\endgroup\$ – Appleguysnake Mar 25 at 12:45
0
\$\begingroup\$

I wasn't able to find out exactly what changed in the Unity rendering that caused this to stop working, but I did create a simple workaround. This post talks about some low-level rendering changes, but I don't understand them enough to know if they're related. Note: this won't work if you use the new Lightweight or High-Definition Render Pipelines, because they don't support OnRenderImage(), but the built-in render pipeline still does for now.

The workaround is actually simpler than my original implementation. Just attach this script to any camera and assign a rendertexture to it and the same rendertexture to a quad the camera is pointed at. I added the if statement to enable a frame delay effect, it isn't necessary for the script to work.

public class FeedbackTexture : MonoBehaviour
{
    public RenderTexture rt;
    [Range(0,5)] public int frameDelay;

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (frameDelay == 0 || Time.frameCount % frameDelay == 0) { Graphics.Blit(source, rt); }
        Graphics.Blit(source, destination);
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.