Search Unity

*Manually* Rendering a disabled Camera cannot render to the main display

Discussion in 'General Graphics' started by swanickj, Jun 15, 2019.

  1. swanickj

    swanickj

    Joined:
    May 15, 2019
    Posts:
    28
    So i want to have VR camera, and a camera that's visible on the computer monitor. The computer monitor doesn't need to run at 90fps or 60fps because it's just for observers who are not at risk of motion sickness, so to save a TON of render time, i disable the second camera and render it manually at 30fps.
    unfortunately the result is that the camera not longers appears on the main display/monitor(edited)
    i assumed this is because the VR camera keeps updating and overwriting the other one
    but i tested it by having an empty scene with one disabled camera being manually rendered at 30fps
    the result is a black screen "No Cameras Rendering"
    but the camera doesn't have a render target texture.
    so if it's not rendering to the screen
    is it rendering nowhere?
    how can i get the 30fps manual-render camera to show up on the main display, without having yet another camera just sees a quad showing the 30fps camera's most recent frame
    a nice alternative would be directly setting the framerate of a camera.


    Code (CSharp):
    1. public class RenderWithInterval : MonoBehaviour
    2. {
    3.  
    4.     Camera cam;
    5.     // Start is called before the first frame update
    6.     void Start()
    7.     {
    8.         cam = GetComponent<Camera>();
    9.         if (cam == null) {
    10.             return;
    11.         }
    12.         else {
    13.             StartCoroutine(RenderInterval());
    14.         }
    15.     }
    16.  
    17.     public float offset = 0f;
    18.     public float interval = .033f;
    19.     private IEnumerator RenderInterval() {
    20.         WaitForSeconds delay = new WaitForSeconds(interval);
    21.         yield return new WaitForSeconds(offset);
    22.         while (gameObject.activeInHierarchy) {
    23.             cam.Render();
    24.             yield return delay;
    25.         }
    26.     }
    27. }
     
  2. swanickj

    swanickj

    Joined:
    May 15, 2019
    Posts:
    28
    I tried manually Blitting to null as in this post
    (and of course called OnPostRender and OnRender manually because those callbacks only occur for enabled cameras)

    I then tried the same thing in OnRenderImage. No such luck. I still won't render to the main display.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Have your camera that you want to run at 30 hz render to a render texture.

    Use a second camera that has it’s mask set to draw nothing, but renders to the screen. Use a script to Blit() the render texture to the screen via OnRenderImage of that camera.
     
  4. swanickj

    swanickj

    Joined:
    May 15, 2019
    Posts:
    28
    Thank you! This is indeed what I ended up doing, with good enough results. I'm still curious though - why does the render to null get trashed if the camera is disabled? Where does the render go when you call Camera.Render() with a null target?
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    It is probably not rendering no where, it is most likely still rendering to the frame buffer. But it is also probably rendering before Unity clears the framebuffer, or might be getting overwritten by that "no cameras" screen to prevent a hall of mirrors.

    Understand that every game frame that's run, Unity will try to render something to the display. It probably looks and sees that there are no cameras enabled to render to the main display and throws up the warning message regardless of what's already there. Like I mentioned above, it may even clear the frame buffer. I believe Unity clears the frame buffer just before the scene rendering starts, but coroutine yield null or WaitForSeconds happens far earlier.
    https://docs.unity3d.com/Manual/ExecutionOrder.html

    I suspect rendering a camera to the main display's frame buffer only during the game logic loop isn't something Unity handles well.

    Even if the warning didn't display, and the camera rendered after the frame buffer clear (like if you call Render() from the VR camera's OnPreCull), Unity would probably still clear the frame buffer every update. This would mean you'd see the image flash on screen once every so often when the main display and the HMD's update sync up, and otherwise render black. You can skip this with an SRP, but I don't think it's possible with the built in rendering paths, so having a dummy camera that just re-renders that render texture to screen is the best option.
     
    Last edited: Jun 20, 2019
    Clonkex and swanickj like this.
  6. yugen1

    yugen1

    Joined:
    Dec 17, 2019
    Posts:
    4
    Could you post the code how you fix it? I might have a similar problem
     
  7. NegativeZero

    NegativeZero

    Joined:
    Jul 27, 2013
    Posts:
    23
    According to this post, your original setup might just work in a Build.
    I have a different situation (not VR), but just calling
    cam.Render();
    in LateUpdate() worked for me in a Build.
     
  8. Asgarde26

    Asgarde26

    Joined:
    Jul 24, 2019
    Posts:
    3
    Doesn 't work for me. When i disable my camera, and i call myCamera.Render(), i have a strangy frame on Android.