If you check the debug log, you will see that it is executed multiple times in the same frame.
Confirmed for Unity 2021.3.3f1 and 2021.3.4f1.
Unity 2020.3.35f1 executes only once within the same frame.
I cannot determine if this is due to a spec change in Unity 2021 or a bug.
Can someone please enlighten me on this?
I am of the same understanding that it is executed only once per frame.
However, the reality is that it is executed many times per frame.
What the numbers 2-4 in the image mean is that the same result was output within the same frame.
I believe this means that the process in OnPreRender is executed multiple times in the same frame.
So it was not just my environment.
Thank you for verifying this!
I am a little relieved.
Unity 2020 had a one-to-one relationship between GameObject’s Update and Camera’s OnPreRender, so I had implemented a program that relied on that.
However, we noticed the problem after upgrading to Unity 2021.
Another side effect is the higher processing cost of OnPreRender.
The same thing happened when I changed the rendering pipeline to URP and used RenderPipelineManager.beginCameraRendering, so I guess it is not just an OnPreRender issue.
I will look for a bit to see if there has been a spec change like this, but right now I am wondering if it is a Unity bug.
Did you run the same test in the same project in Unity 2020 to confirm that the behaviour is different?
Also, do you have multiple cameras in the scene? According to the docs it seems to indicate that OnPreRender runs for each Camera.
There is only one camera in the scene.
The following are the results of logs output by Update and OnPreRender of the one GameObject prepared.
(output is an arbitrary string)
668/254=2.62992125984.
If OnPreRender is running twice due to the presence of two cameras, this number should be exactly 2.
If there are three cameras, it should be 3.
EDIT:
Sorry, I forgot to write.
I have run the same tests on the same project and have confirmed that the behavior is different.
I can’t publish my current project file, so I will try to make a sample that I can reproduce.
What happens if you set Application.targetFramerate to 60 or 30?
Also, you are testing this in the editor. I believe the editor fps used to be capped at 30 but this isn‘t the case any longer. Eg I now get 120 fps in the editor, matching the monitor refresh rate. Can you check with a debug build and Debug.LogError (just so the console pops up) whether you can observe the same behaviour in builds? Both for 2020 and 2021.
I suspect that perhaps Update cycle may be locked at 60 Hz whereas rendering occurs more often than that in the editor. That may explain the odd 1:2/1:3 ratio. It‘s a wild guess though.
One thought since this is in the editor, how many scene / game views do you have?
I’m wondering if other scene or game windows will result in additional OnPreRender calls per frame. If true then maybe the behaviour for OnPreRender has changed in Unity when having multiple scene or game view windows open.
Thanks to SteffenItterheim-san I found out two things.
Application.targetFramerate is set to 60.
I also have VSync disabled.
(My display is driven at 60Hz, so I believe the Update and drawing frequency should match.)
I dropped Application.targetFramerate to 30 and the ratio changed.
I then commented out the line Application.targetFramerate = 60.
Then the Update and OnPreRender counts matched.
Also, as you pointed out, I was testing in the editor.
I’m pasting the results of my test with Application.targetFramerate = 60.
There are two things we can learn from the above.
The first is that camera events ignore Application.targetFramerate.
The second is that this phenomenon does not occur in the build.
In other words, since Unity 2021, camera events seem to ignore Application.targetFramerate when running in Editor.
Maybe it’s due to changes to VSYNC, but even then, if the game is running higher than VSYNC, shouldn’t framecount also rise higher? I cannot think of a valid situation where OnPreRender should run more than once per frame, changes to vsync or not.
My guess is it’s a Unity bug. You can try submitting a bug report and hope to have it fixed before the heat death of the universe.
The things people say about multiple cameras and multiple views are not the issue (and OnPreRender doesn’t work like people are assuming here).
Thank you for confirming again!
I too do not see the benefit of running OnPreRender multiple times in the same frame.
I have filed a bug report on this matter.
I have also attached a sample project to the bug report, so I hope it will be addressed during my lifetime.
In the meantime, I will also upload an exported sample.
However, you should be able to reproduce it by simply creating an empty project and attaching the following script.
using System.Collections.Generic;
using UnityEngine;
public class UpdateScript : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 60;
Camera.onPreRender += OnPreRenderCallback;
}
// Update is called once per frame
void Update()
{
// run one times on the same frame
Debug.Log("Update");
}
// Unity calls the methods in this delegate's invocation list before rendering any camera
void OnPreRenderCallback(Camera cam)
{
// run multiple times on the same frame
Debug.Log("OnPreRender");
Debug.Log(Time.frameCount);
}
// Remove your callback from the delegate's invocation list
void OnDestroy()
{
Camera.onPreRender -= OnPreRenderCallback;
}
}