OnRenderImage() - How to avoid performance hit when not in use?

I’m working on a glow/outline post processing effect. It’s very much based on this one:

But I noticed that I use resources even when no objects are highlighted. I guess that’s because all the code inside OnRenderImage() is run no matter what. So I tried putting a conditional return in there, but that broke it and after reading here:

It seems you have to do actual work in that method if you use it. I tried just having a
Graphics.Blit(src, dest) with nothing else in there, but that still seems to use some resources.

So how do I make my effect only use resources when I’m actually highlighting something? Do I have to turn the entire component on/off?

I realize that there’s a million ways of doing post processing effects or shaders inside Unity and I have no idea about the pros/cons of the different approaches, I’m just trying to make this one do what I want and perhaps learn something in the process. :stuck_out_tongue:

Why not disable the script while not in use?

That’s what I meant by turning the component on/off. It’s what I’m doing now, I just felt it was a bit hacky, but perhaps it’s the standard way of having an effect like this that’s only supposed to be visible when you for example mouseover something?

Yes, that’s correct AFAIK.

Performance tips / other workaround from my own adventures in designing a similar outline:

As mentioned in this thread on OnRenderImage(), if you do not assign a RenderTexture to the camera your script is attached to, it reads the entire screen to give you your source RenderTexture which is highly inefficient.

As an alternative, you can do something like:

// Set these up on your own
private Rendertexture _rt;
private Camera _camera;

    private void OnPreRender()
    {
        _camera.targetTexture = _rt;
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (_shouldOutline)
        {
            DoOutline(source);
        }
        _camera.targetTexture = null;
        Graphics.Blit(source, null as RenderTexture);
    }

This won’t have a performance hit like OnRenderImage() normally does because you are rendering to the texture (and not the screen) and then blitting to the screen. This assumes that you will blit your outline to combine with the source texture as your last blit so you can then blit that result to the screen by first nulling the RenderTexture on the camera (necessary) and then blitting to null (which blits to the screen)

Hope this helps!

4 Likes

This does not sound correct to me. Where are you getting this information from?

Though I guess I’ve always assumed that if Unity detects you are using imageEffects it will render to a renderTexture instead of the backbuffer. Then of course on Android Unity is already rendering to RT due to some hardware bug on specific devices and for deferred rendering it has to go into RenderTextures anyway.

To double check I tweeted Aras about this, his reply ‘I don’t think so’ - which unfortunately is not really a concrete answer, maybe because it varies based on renderer and target device?

So anyway i’m intrigued and would like to know more, as if true, even if under specific circumstances it would be very useful knowledge to have.

You can check it out in the Unity’s Scripting Reference page: