Search code examples
c#androidunity-game-engineaugmented-reality

How to get Live feed from phone camera to Unity


I need a live camera feed from my phone to unity. Ive tried webcamTexture but it doesn't work the way I want it. It is way too much zoomed and I have to built and run every time to see the results of the changes that I made to the resolution. Also if someone is expert and helps me to built my Final Year Project for my degree, it would be appreciated. Here is the code that I used for using camera:

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

public class CameraScript : MonoBehaviour
{
    private bool camAvailable;
    private WebCamTexture backCam;
    private Texture defaultBackground;
    public RawImage background;
    public AspectRatioFitter fit;
    public int width = 1080;
    public int height = 2400;
    // Start is called before the first frame update
    void Start()
    {
        defaultBackground = background.texture;
        WebCamDevice[] devices = WebCamTexture.devices;
        if(devices.Length ==0)
        {
            Debug.Log("No Camera Available");
            camAvailable = false;
            return;
        }
        for (int i =0; i<devices.Length; i++)
        {
            if(!devices[i].isFrontFacing)
            {
                backCam = new WebCamTexture(devices[i].name, width, height);
            }

        }
        if(backCam == null)
        {
            Debug.Log("Unable to find the Back Camera");
            return;
        }
        backCam.Play();
        background.texture = backCam;
        camAvailable = true;
       
    }

    // Update is called once per frame
    void Update()
    {
        if (!camAvailable)
            return;
        float ratio = (float)backCam.width / (float)backCam.height;
        fit.aspectRatio = ratio;
        float scaleY = backCam.videoVerticallyMirrored ? -1f: 1f;
        background.rectTransform.localScale = new Vector3(1f, scaleY, 1f);
        int orient = -backCam.videoRotationAngle;
        background.rectTransform.localEulerAngles = new Vector3(0, 0, orient);
        
    }

Solution

  • It's simply math issue, which I could share you this script for correct calculation. It's already been used in many projects in many years.

    You only need to assign a Quad, and the Quad will be in the far background plane of your main camera.

    Similar idea could be applied for UI Rect too. In theory, you should be able to achieve this result(video call testing in C#).

    void CalculateBackgroundQuad()
    {
        Camera cam = Camera.main;
        ScreenRatio = (float)Screen.width / (float)Screen.height;
    
        BackgroundQuad.transform.SetParent(cam.transform);
        BackgroundQuad.transform.localPosition = new Vector3(0f, 0f, cam.farClipPlane / 2f);
    
        float videoRotationAngle = webCamTexture.videoRotationAngle;
    
        BackgroundQuad.transform.localRotation = baseRotation * Quaternion.AngleAxis(webCamTexture.videoRotationAngle, Vector3.forward);
    
        float distance = cam.farClipPlane / 2f;
        float frustumHeight = 2.0f * distance * Mathf.Tan(cam.fieldOfView * 0.5f * Mathf.Deg2Rad);
    
        BackgroundQuad.transform.localPosition = new Vector3(0f, 0f, distance);
        Vector3 QuadScale = new Vector3(1f, frustumHeight, 1f);
    
        //adjust the scaling for portrait Mode & Landscape Mode
        if (videoRotationAngle == 0 || videoRotationAngle == 180)
        {
            //landscape mode
            TextureRatio = (float)(webCamTexture.width) / (float)(webCamTexture.height);
            if (ScreenRatio > TextureRatio)
            {
                float SH = ScreenRatio / TextureRatio;
                float TW = TextureRatio * frustumHeight * SH;
                float TH = frustumHeight * (webCamTexture.videoVerticallyMirrored ? -1 : 1) * SH;
                QuadScale = new Vector3(TW, TH, 1f);
            }
            else
            {
                float TW = TextureRatio * frustumHeight;
                QuadScale = new Vector3(TW, frustumHeight * (webCamTexture.videoVerticallyMirrored ? -1 : 1), 1f);
            }
        }
        else
        {
            //portrait mode
            TextureRatio = (float)(webCamTexture.height) / (float)(webCamTexture.width);
            if (ScreenRatio > TextureRatio)
            {
                float SH = ScreenRatio / TextureRatio;
                float TW = frustumHeight * -1f * SH;
                float TH = TW * (webCamTexture.videoVerticallyMirrored ? 1 : -1) * SH;
                QuadScale = new Vector3(TW, TH, 1f);
            }
            else
            {
                float TW = TextureRatio * frustumHeight;
                QuadScale = new Vector3(frustumHeight * -1f, TW * (webCamTexture.videoVerticallyMirrored ? 1 : -1), 1f);
            }
        }
        BackgroundQuad.transform.localScale = QuadScale;
    }