3

What do I want to achieve ?

I'd like to achieve an effect in Unity3D, where I superpose a few cameras on top of each other. Each cameras would draw to a specific area of the screen. If possible, I'd like these areas to change dynamically. I am using unity (latest version), and URP.

How technically I see it :

For implementation and performances reasons, it seems writing to the stencil buffer is the way to go. That way, I can only render what part of the screen I want for each camera. It is also quite easy once the stencil is made, cause the ForwardRendering settings in Unity offer such capabilities out of the box.

What I can't figure out :

The problem is, I don't know to efficiently write to the whole stencil buffer (each frame). The best way would be to use a compute shader (or maybe a simple script), that directly write the values after some calculations. Is there a way for that ? If yes, How ?

Another alternative may be to use a transparent quad in front of one of each camera, and to write to the stencil buffers like that. But 1) It seems there exist a SV_StencilRef keyword in the fragment buffer, but not supported by Unity yet ? 2) I will still lose performance nevertheless.

Thanks for any help / ideas about how to tackle this problem.

Edit (Clarification) : I'd like to be able to render free shapes, and not only rects, which prevent the use of the standard ViewportRect. After some search, I found the Voronoi split screen to be quite similar (with a technical view) to what I'd like to achieve (See here)

Eyap
  • 754
  • 1
  • 7
  • 22
  • what about...https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.2/manual/camera-stacking.html? – Lotan Oct 27 '22 at 08:58
  • 1
    @Lotan that is probably what OP is already using as it is **the** default way of having multiple Camera's in a URP scene ;) – derHugo Oct 27 '22 at 13:06

2 Answers2

3

If I understand correctly, you only need to play with the different camera Viewport Rect (https://docs.unity3d.com/ScriptReference/Camera-rect.html) to determine what camera should render what part of the screen.

Response to comment: no, it's not stretched. Here is an example with four cameras:

Create a scene with four cameras, add this script to it and add the cameras to the array on the script. I added the _movingObject just to see something moving, but it's not necessary.

using UnityEngine;

public class CameraHandler : MonoBehaviour
{
    [SerializeField] private Transform _movingObject;
    [SerializeField] private float _posMod = 10.0f;

    [SerializeField] private float _cameraPosMod = 0.1f;
    [SerializeField] private Camera[] _cameras;

    private void Update()
    {
        float t = Time.time;
        float x = Mathf.Sin(t);
        float y = Mathf.Cos(t);

        if (_movingObject) _movingObject.position = new(x * _posMod, 1.0f, y * _posMod);

        Vector2 center = new(0.5f + x * _cameraPosMod, 0.5f + y * _cameraPosMod);

        // bottom left camera
        _cameras[0].rect = new(0.0f, 0.0f, center.x, center.y);

        // bottom right camera
        _cameras[1].rect = new(center.x, 0.0f, 1.0f - center.x, center.y);

        // upper left camera
        _cameras[2].rect = new(0.0f, center.y, center.x, 1.0f - center.y);

        // upper right camera
        _cameras[3].rect = new(center.x, center.y, 1.0f - center.x, 1.0f - center.y);
    }
}
h4ri
  • 359
  • 2
  • 9
  • This most probably won't do the trick. Changing the rect - as you say - will change which part of the scene that camera will render .. but due to the Camera stack it will still be streched to the entire screen afaik – derHugo Oct 27 '22 at 13:07
  • Well, using this means I have to use rectangles for each cameras. In my case, I would like to be able to have free forms - thus using the camera Viewport Rect is not enough/possible. If there is a way it would be the solution to go though, but I don't think that's possible. – Eyap Oct 28 '22 at 16:12
2

Not exactly an answer to your question about stencil buffer but I had a (hopefully) similar use case recently.

The main issue: In the URP Camera stack

  • If your camera is set to Base it will overdraw the entire screen
  • you can not adjust the Viewport on any Overlay camera

You can actually try to set the viewport via code -> result your camera renders only the correct part of the scene ... but it gets stretched to the entire screen ^^


What I did in the end was

  • Leave all content and cameras at the origin position

  • Apply according masks to filter the content per camera

  • Make your camera Overlay (as usual)

  • go through a custom Camera.projectionMatrix

    m_Camera.projectionMatrix = Matrix4x4.Translate(projectionOffset) * Matrix4x4.Perspective(m_Camera.fieldOfView, m_Camera.aspect, m_Camera.nearClipPlane, m_Camera.farClipPlane);
    

    where the projectionOffset is an offset in viewport space (normalized 0 - 1) from the bottom left corner.

    For example in my case I wanted a minimap at 400, 400 pixels from the top-right corner so I did

    var topRightOffsetPixels = new Vector2(400, 400);
    var topRightOffsetViewport = Vector2.one - new Vector2(topRightOffsetPixels.x * 2 / Screen.width, topRightOffsetPixels.y * 2 / Screen.height);
    m_Camera.projectionMatrix = Matrix4x4.Translate(topRightOffsetViewport) * Matrix4x4.Perspective(m_Camera.fieldOfView, m_Camera.aspect, m_Camera.nearClipPlane, m_Camera.farClipPlane);
    

See also Matrix4x4.Perspective

derHugo
  • 83,094
  • 9
  • 75
  • 115
  • That is definitely interesting ! But as said in the other comment, I need to be able to draw free forms (mostly triangles, but interested in various types). AFAIK your method can only be used with rects – Eyap Oct 28 '22 at 16:34
  • Well this isn't really bound to rects .. the camera yes is always a rect .. but you can render whatever form you want with this .. or maybe I understand your concerns wrong? – derHugo Oct 29 '22 at 10:18
  • In other words: Only whatever object you render through the overlay camera will be overwriting the first cameras Image => if your object is of any form only those pixels will be replaced .. the background etc is only rendered by the main camera – derHugo Oct 29 '22 at 13:08