How can I assign WebCamTexture as a background of a VisualElement ?

Hello. I want to show the phone camera feed on a visual element. I’m trying to assign it, but VisualElement’s background style is not accepting a WebCamTexture object.

There is no WebCamTexture as a constructor. So I can’t assign a WebCamTexture object reference to a VisualElement.

How can I do it?

You should be able to cast Texture to Texture2D: Texture2D tex2D = (Texture2D)YourTexture;

Or maybe you could use a spearate Image element. Assigning it to the “image” property should work since that one takes a Texture and WebCamTexture is derived from the Texture class so it should work.

There is no direct casting from WebCamTexture to Texture2D. So first, I have cast from WebCamTexture to Texture. Then I cast from Texture to Texture2D. And as a result, It is giving an invalid casting error from Texture to Texture2D.

In the UI Builder, there is no Image element.

Normally, I should be able to pass WebCamTexture object reference to VisualElement. Because If I can’t, It won’t update the image, and I can’t see the camera feed.

There is something that I don’t know. But I could not figure it out.

This setup worked for me (tested right now, Unity 2021.3.8f1):

Script:

using UnityEngine;
using UnityEngine.UIElements;

public class WebcamTest : MonoBehaviour
{
    protected UIDocument _document;
    public UIDocument Document
    {
        get
        {
            if (_document == null)
            {
                _document = this.GetComponent<UIDocument>();
            }
            return _document;
        }
    }

    void Start()
    {
        var devices = WebCamTexture.devices;

        if (devices.Length == 0)
            return;

        var name = devices[0].name;
        Debug.Log($"Using Webcam {name}");
        WebCamTexture webcam = new WebCamTexture(name);
        webcam.Play();

        Texture texture = (Texture)webcam;

        var img = Document.rootVisualElement.Q<Image>();
        if (img != null)
        {
            img.image = texture;
        }
    }
}

Layout:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <ui:Image />
</ui:UXML>

Scene:
9164075--1275152--upload_2023-7-22_15-6-59.jpg

You can add it via code or in the xml.

1 Like

Here is an updated version which also sets the background of a visual element. Though we have to copy the texture manually every frame.

using System;
using UnityEngine;
using UnityEngine.UIElements;

public class WebcamTest : MonoBehaviour
{
    protected UIDocument _document;
    public UIDocument Document
    {
        get
        {
            if (_document == null)
            {
                _document = this.GetComponent<UIDocument>();
            }
            return _document;
        }
    }

    protected WebCamTexture _webcam;
    Texture2D _texture2D;

    void Start()
    {
        // Find device an bort if none was found, else use first.
        var devices = WebCamTexture.devices;
        if (devices.Length == 0)
            return;

        // Get webcam texture from webcam
        var name = devices[0].name;
        Debug.Log($"Using Webcam {name}");
        _webcam = new WebCamTexture(name);
        _webcam.Play();

        // Apply to image
        var img = Document.rootVisualElement.Q<Image>();
        if (img != null)
        {
            img.image = _webcam;
        }

        // Now about that bg image
        _texture2D = new Texture2D(
            _webcam.width, _webcam.height,
            TextureFormat.ARGB32, 1, false);

        // Make the texture 2D the bg image.
        var bgImage = Document.rootVisualElement.style.backgroundImage.value;
        bgImage.texture = _texture2D;
        Document.rootVisualElement.style.backgroundImage = bgImage;
    }

    private void Update()
    {
        // Sadly we have to copy from the webcam to the texture2D manually.
        // Maybe this could be avoided if there is a way to hook up the webcam
        // texture to a render texture (backgroundImage has a renderTexture target).
        Graphics.CopyTexture(_webcam, _texture2D);
    }
}

I hope Graphics.CopyTexture uses Graphics.Blit() to copy the texture and does not read and write every pixel as that would be slow.

1 Like

Thanks a lot. I have created an Image via code and have assigned my WebCamTexture. And it has worked like a charm.

Graphics.CopyTexture(_webcam, _texture2D);

This line is also a nice idea. I will consider it if I need it for different scenarios.

Thanks again.

1 Like