0
\$\begingroup\$

The first script is the way I'm using now to switch between cameras.

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

public class SwitchCameras : MonoBehaviour
{
    [Header("Cameras Init")]
    public Camera[] cameras;
    public Vector3[] originalPosition;
    [HideInInspector]
    public Vector3 currentCameraOriginalPosition, currentCameraPosition;

    [Space(5)]

    [Header("Cameras Switch")]
    public string currentCameraName;
    public Vector3[] lastCameraPosition;

    private int currentCamera = 0;

    void Start()
    {
        cameras = Camera.allCameras;
        lastCameraPosition = new Vector3[cameras.Length];

        if (cameras.Length >= 1)
        {
            originalPosition = new Vector3[cameras.Length];
            for (int i = 0; i < cameras.Length; i++)
            {
                originalPosition[i] = cameras[i].transform.position;
            }
        }

        if (cameras.Length == 1)
        {
            Debug.LogError("Need more then 1 camera for switching..");
        }
        else
        {
            Debug.Log("Found " + cameras.Length + " cameras");
        }

        for (int i = 0; i < cameras.Length; i++)
        {
            cameras[i].enabled = false;
        }
        cameras[0].enabled = true;
        currentCameraName = cameras[0].name;
        currentCameraOriginalPosition = originalPosition[0];
    }

    void LateUpdate()
    {
        if (Input.GetKeyDown(KeyCode.G))
        {
            cameras[currentCamera].enabled = false;

            if (++currentCamera == cameras.Length)
                currentCamera = 0;

            cameras[currentCamera].enabled = true;
            currentCameraName = cameras[currentCamera].name;

            currentCameraOriginalPosition = originalPosition[currentCamera];
        }
        lastCameraPosition[currentCamera] = cameras[currentCamera].transform.position;
        currentCameraPosition = lastCameraPosition[currentCamera];
    }
}

And this is a script for starting a new game:

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

public class NewGame : MonoBehaviour
{
    public void RestartGame()
    {

    }
}

Both scripts attached to the same GameObject. I'm calling the RestartGame method from On Click in the inspector of a button I have in the main menu.

Now in the SwitchCameras script I'm using the G key to switch between the cameras.

But now I want to do that when a new game start to fade in/out between two cameras inside the RestartGame method. I want to call some method from the SwitchCameras script that will gade in/out between two cameras.

The idea is when starting a new game or resuming a game that the first camera will fade out slowly, fade out I mean will be enabled false slowly and then near the end to enabled true the second camera slowly.

Like switching between the two cameras but slowly.

Should i use startcoroutine ?

\$\endgroup\$
5
  • 1
    \$\begingroup\$ The problem here is not that you need a coroutine (you do) but that camera.enabled only has two values: true and false. If you want them to fade then both need to be active at the same time and one of them needs to render....transparently...which they can't do. You need some kind of transition graphic. \$\endgroup\$ Jan 15, 2018 at 23:39
  • 1
    \$\begingroup\$ Does the scene viewed by the first camera need to continue moving as you fade to the second? Or would it be acceptable to capture a snapshot and fade from that still image to the new live feed? \$\endgroup\$
    – DMGregory
    Jan 15, 2018 at 23:59
  • \$\begingroup\$ @Draco18s I recommend being careful with absolutes like "can't" — I've noticed a number of new game makers tend to take such remarks to mean "the effect you're describing cannot possibly be achieved by any means" when often we really mean "this is not the automatic/default/out-of-the-box behaviour, so to achieve it we'll need to use some custom scripts and/or other kajiggery..." ;) \$\endgroup\$
    – DMGregory
    Jan 16, 2018 at 0:04
  • \$\begingroup\$ @DMGregory No as for now the scene view by the first camera should not be moving to the second camera. Just still fading switching between the cameras. \$\endgroup\$
    – Daniel Lip
    Jan 16, 2018 at 0:24
  • \$\begingroup\$ @DMGregory That's a fair comment. Just that with an effect like this, you need an intermediary of some kind. \$\endgroup\$ Jan 16, 2018 at 2:07

2 Answers 2

3
\$\begingroup\$

Put black 2D planes (or UI images, better to put an image if you want extra effects) in front of your cameras. Make the first one's plane transparent and the second one's plane solid. Disable the second camera at first (along with the 2D plane). When you want to switch between, just slowly decrease the first plane's transparency (increase its color alpha), turn on your second camera, turn off your first camera and decrease the transparency of your second plane (which is on the second camera).

If you've opted for UI images, play around with fillings etc. for more effects.

\$\endgroup\$
2
  • \$\begingroup\$ How can i position the plane to be in front of the camera easy ? I'm playing now with the plane position but it's not in front the camera directly. If for example the camera position is X -7 Y 0 Z -100 then what position the plane should be ? Maybe i can position the plane in front the camera automatic through script ? \$\endgroup\$
    – Daniel Lip
    Jan 16, 2018 at 8:47
  • 2
    \$\begingroup\$ @jdoedoedoedoe If you're using the plane method, just make it a child object of the camera (put it a bit in front of the camera) and it will move with the camera. If you're using UI image method, then you can just put it in a screen space canvas and it will cover the camera. \$\endgroup\$ Jan 16, 2018 at 8:50
1
\$\begingroup\$

If you want to cross-fade straight from one view to the other, rather than fading to black first, we can do it by capturing a snapshot of the first camera before we disable it.

Add a UI canvas to your scene, in Screenspace Overlay mode, with a RawImage that stretches to fill the whole view. It can be disabled for starters, since we'll only use it when doing the cross-fade. Then slap a script something like this on it:

[RequireComponent(typeof(RawImage))]
public class CameraCrossFader : MonoBehaviour {

    // Hold our render target between uses so we don't
    // have to create & destroy it repeatedly.
    RenderTexture _snapshot;

    // Call this when you want to start a cross-fade.
    public void CrossFade(Camera startCam, Camera endCam, float duration) {
        StartCoroutine(FadeSequence(startCam, endCam, duration));
    }

    IEnumerator FadeSequence(Camera startCam, Camera endCam, float duration) {
        // If we haven't made a capture target yet, or our render changed size
        // since we last used it, create a new one at our current resolution.
        if(_snapshot == null 
         || _snapshot.width != Screen.width || _snapshot.height != Screen.height) {
            // If we already had a target, destroy it so we don't leak memory.
            if(_snapshot != null)
                 DestroyImmediate(_snapshot);

             // Make a new render target of the desired size & format.
             _snapshot = new RenderTexture(Screen.width, Screen.height,
                                            RenderTextureFormat.RGBA32);
        }

        // Copy the last rendered frame into this texture.
        _snapshot.ReadPixels(new Rect(0,0,Screen.width,Screen.height), 0,0);

        // Use this image as our stand-in card, and enable this object so it's shown.
        gameObject.SetActive(true);
        var image = GetComponent<RawImage>();
        image.texture = _snapshot;

        // Switch rendering to use the second camera.
        startCam.gameObject.SetActive(false);
        endCam.gameObject.SetActive(true);

        // Gradually fade our stand-in card to transparent.
        Color color = Color.white;
        for(float a = 1f; a > 0; a -= Time.deltaTime/duration) {
               color.a = a;
               image.color = color;
               // Let the game run for another frame.
               yield return null;
        }

        // Fade complete. Switch this object off until the next fade.
        gameObject.SetActive(false);
    }
}
\$\endgroup\$

You must log in to answer this question.

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