Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Bug In Unity 2021, why does OnPreRender run multiple times on the same frame?

Discussion in 'General Graphics' started by ushui, Jun 6, 2022.

  1. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    Write the following code within OnPreRender.

    Code (CSharp):
    1. UnityEngine.Debug.Log(Time.deltaTime)
    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?

    debuglog.png
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,191
    Log Time.frameCount instead. ;)

    02:57:10 does not imply „same frame“.
     
  3. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    You are right, you did not mean the same frame.

    I tried to output using Time.frameCount, but the result is still the same.
    Oh, why......

    timeframecount.png
     
  4. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,064
    No they're not. The framecount keeps increasing, which means it only runs once per frame.

    EDIT: just noticed there are similar identical debugs that are collapsed into one. That's curious. Can you share a sample scene and script?
     
  5. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    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.

    painted.png
     
  6. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,064
    Did a test of my own. I can confirm your findings in 2021.

    upload_2022-6-7_9-34-57.png
     
    Last edited: Jun 7, 2022
  7. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    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.
     
  8. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,191
    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.
     
  9. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    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)

    debuglog_in_update_and_onprerender.png

    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.
     
    Last edited: Jun 7, 2022
  10. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,191
    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.
     
  11. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,005
    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.
     
  12. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    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.
    Unity2021Frame30.png

    I then commented out the line Application.targetFramerate = 60.
    Then the Update and OnPreRender counts matched.
    Unity2021FrameNospec.png

    Also, as you pointed out, I was testing in the editor.
    I'm pasting the results of my test with Application.targetFramerate = 60.

    [Unity 2020 Editor]
    Unity2020Editor.png

    [Unity 2020 Debug build (Android)]
    Due to a bug in the project, I could not debug for Android...

    [Unity 2021 Editor].
    See previous exchanges.

    [Unity 2021 Debug build (Android)]
    Unity2021Build.png


    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.
     
  13. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    As for the scene / game view, I thought about it too, but it didn't change even if I only had one game view.
     
  14. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,064
    I can also confirm that 2020 LTS with an identical setup does not exhibit the same behaviour:

    upload_2022-6-7_16-8-1.png

    2020 runs, correctly, once per frame.

    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).
     
  15. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    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.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class UpdateScript : MonoBehaviour
    5. {
    6.     // Start is called before the first frame update
    7.     void Start()
    8.     {
    9.         QualitySettings.vSyncCount = 0;
    10.         Application.targetFrameRate = 60;
    11.  
    12.         Camera.onPreRender += OnPreRenderCallback;
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         // run one times on the same frame
    19.         Debug.Log("Update");
    20.     }
    21.  
    22.     // Unity calls the methods in this delegate's invocation list before rendering any camera
    23.     void OnPreRenderCallback(Camera cam)
    24.     {
    25.         // run multiple times on the same frame
    26.         Debug.Log("OnPreRender");
    27.         Debug.Log(Time.frameCount);
    28.     }
    29.  
    30.     // Remove your callback from the delegate's invocation list
    31.     void OnDestroy()
    32.     {
    33.         Camera.onPreRender -= OnPreRenderCallback;
    34.     }
    35. }
    Thank you very much for all your help.
     

    Attached Files:

  16. ushui

    ushui

    Joined:
    Jul 25, 2020
    Posts:
    14
    This bug has been fixed in Unity 2021.3.6f1.

    > Scripting: Fixed issue where OnPostRender is called multiple times per frame when setting Application.targetFrameRate.

    This is a bug fix for OnPostRender, but it seems that the OnPreRender bug in this case has been fixed as well.
     
    Cairne-D likes this.