0
\$\begingroup\$

This is my first post here and I'm not too experienced with Unity, so keep that in mind. I am working on a project (a virtual streaming app specifically) where I have four cameras that the user can switch between with number keys.

The program has a room with a table in it, and a character is located in front of that table. The character is controlled using outside software and the VMC protocol.

The four different cameras are located in the front of the room, pointing toward the character's head, on a table, and a first person camera with a fixed position, but whose rotation corresponds to that of one of the character's bones.

I wrote a simple C# script that allows the user to switch between the four:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CamSwitch : MonoBehaviour
{
    public GameObject cam1, cam2, cam3, cam4;
    public GameObject headBone;
    public int camera = 1;

    void Start() 
    {
        cam1.SetActive(true);
        cam2.SetActive(false);
        cam3.SetActive(false);
        cam4.SetActive(false);
    }

    void Update()
    {
        if (Input.GetButtonDown("Key1")) 
        {
            camera = 1;
            cam1.SetActive(true);
            cam2.SetActive(false);
            cam3.SetActive(false);
            cam4.SetActive(false);
        } 
        if (Input.GetButtonDown("Key2")) 
        {
            camera = 2;
            cam2.SetActive(true);
            cam1.SetActive(false);
            cam3.SetActive(false);
            cam4.SetActive(false);
        }
        if (Input.GetButtonDown("Key3")) 
        {
            camera = 3;
            cam3.SetActive(true);
            cam1.SetActive(false);
            cam2.SetActive(false);
            cam4.SetActive(false);
        }
        if (Input.GetButtonDown("Key4")) {
            camera = 4;
            cam4.SetActive(true);
            cam1.SetActive(false);
            cam2.SetActive(false);
            cam3.SetActive(false);
        }

        if (camera == 4) 
        {
            cam4.transform.rotation = headBone.transform.rotation;
        }
    }
}

What I want is to make a picture-in-picture display something like this when the 1st-person view is turned on: enter image description here I've tried adding a second smaller camera, but to no avail. Also for what it matters, I found this script doesn't work unless all of the cameras are turned on before the project is run.

Thanks in advance.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

The key is Render Textures.

A render texture is an "asset" which can be assigned to a camera to capture its render output and then be used as a texture to display that camera output in any context where a texture can be used. For example an image in the UI.

So the idea is:

  1. Create your cameras
  2. Create a Render Texture asset
  3. Assign that render textures to the field "Target Texture" of your cameras.
  4. Create a UI canvas with a Raw Image (not regular images, because those don't support render textures). Position that images on the canvas where you want the "picture in picture" to appear on the screen.
  5. Assign the render texture as the texture of that image.

You should now have a tiny "mini-screen" on the screen which shows the output of the cameras. When multiple cameras are active, then you are probably going to see the output of the last camera, because it's going to overwrite all the others. So make sure you only have one camera active at the same time.

\$\endgroup\$
6
  • \$\begingroup\$ How does that work? Can the raw image be placed somewhere specific in the camera's field of view? \$\endgroup\$
    – zenzicubic
    Oct 10, 2022 at 13:48
  • \$\begingroup\$ @PythonTester Have you worked with the Unity UI system before? \$\endgroup\$
    – Philipp
    Oct 10, 2022 at 13:50
  • \$\begingroup\$ No, I haven't. I think I see how it works though. \$\endgroup\$
    – zenzicubic
    Oct 10, 2022 at 13:52
  • \$\begingroup\$ @PythonTester The Unity UI system is one of those core features every Unity developer should be familiar with. You are going to need it for any kind of ingame HUD or menu screen. And I really recommend to learn it in-depth, because some of its aspects are not that intuitive. Unless of course you want to use the new UI system which also supports images with render textures. But that's even less intuitive to use (unless you are a web developer). \$\endgroup\$
    – Philipp
    Oct 10, 2022 at 13:58
  • \$\begingroup\$ @PythonTester But to answer the question, yes, a RawImage is a UI object that lives on a UI Canvas. When the canvas is set to "Screen Space" (default setting) then you can place anything on that canvas freely on the screen. \$\endgroup\$
    – Philipp
    Oct 10, 2022 at 14:04
0
\$\begingroup\$

If you want your picture-in-picture view to occupy a fixed, screen-aligned rectangle, you can also achieve this effect without a render texture by using the camera's viewport rect.

Take your camera that renders the "main" scene view and set its Depth parameter to something like 0.

Then take your picture-in-picture camera and set its Depth to a greater value, like 1, so it renders after the main camera has finished drawing.

Set this PiP camera's viewport rect to occupy just a corner of the screen, something like:

x: 0  w: 0.25
y: 0  h: 0.25

These values are measured in relative coordinates, so "0" is the bottom/left corner of the screen, and "1" is the top/right or full width/height.

You can set these values in a script if you want to adapt the size and position of the PiP window to respond to changes in the size of the game window.

The advantage of rendering to a render texture is you're not limited to blitting the image directly to the screen — you can display that render texture in perspective, or map it to a virtual monitor that exists as a 3D model in your game world, or project it onto your geometry like a slide show, or render it distorted, translucent, or with arbitrary shader effects.

The downside of rendering to a render texture is that it's slightly more expensive to save and then sample that texture than to just dump pixels directly to the frame buffer in one go. You may also have to do some work to match the texture resolution to the display size, otherwise you might render more pixels to the texture than you ultimately display, or observe sampling artifacts where the grid of the texture's texels is mismatched to the grid of the screen's pixels.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .