Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

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

Discussion in 'UI Toolkit' started by yusuf_isik, Jul 22, 2023.

  1. yusuf_isik

    yusuf_isik

    Joined:
    Feb 14, 2014
    Posts:
    21
  2. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,111
    You should be able to cast Texture to Texture2D:
    Code (CSharp):
    1. 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.
     
  3. yusuf_isik

    yusuf_isik

    Joined:
    Feb 14, 2014
    Posts:
    21
    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.
     
  4. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,111
    This setup worked for me (tested right now, Unity 2021.3.8f1):

    Script:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UIElements;
    3.  
    4. public class WebcamTest : MonoBehaviour
    5. {
    6.     protected UIDocument _document;
    7.     public UIDocument Document
    8.     {
    9.         get
    10.         {
    11.             if (_document == null)
    12.             {
    13.                 _document = this.GetComponent<UIDocument>();
    14.             }
    15.             return _document;
    16.         }
    17.     }
    18.  
    19.     void Start()
    20.     {
    21.         var devices = WebCamTexture.devices;
    22.  
    23.         if (devices.Length == 0)
    24.             return;
    25.  
    26.         var name = devices[0].name;
    27.         Debug.Log($"Using Webcam {name}");
    28.         WebCamTexture webcam = new WebCamTexture(name);
    29.         webcam.Play();
    30.  
    31.         Texture texture = (Texture)webcam;
    32.  
    33.         var img = Document.rootVisualElement.Q<Image>();
    34.         if (img != null)
    35.         {
    36.             img.image = texture;
    37.         }
    38.     }
    39. }
    40.  
    Layout:
    Code (CSharp):
    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    2.     <ui:Image />
    3. </ui:UXML>
    4.  
    Scene:
    upload_2023-7-22_15-6-59.png


    You can add it via code or in the xml.
     
    yusuf_isik likes this.
  5. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,111
    Here is an updated version which also sets the background of a visual element. Though we have to copy the texture manually every frame.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4.  
    5. public class WebcamTest : MonoBehaviour
    6. {
    7.     protected UIDocument _document;
    8.     public UIDocument Document
    9.     {
    10.         get
    11.         {
    12.             if (_document == null)
    13.             {
    14.                 _document = this.GetComponent<UIDocument>();
    15.             }
    16.             return _document;
    17.         }
    18.     }
    19.  
    20.     protected WebCamTexture _webcam;
    21.     Texture2D _texture2D;
    22.  
    23.     void Start()
    24.     {
    25.         // Find device an bort if none was found, else use first.
    26.         var devices = WebCamTexture.devices;
    27.         if (devices.Length == 0)
    28.             return;
    29.  
    30.         // Get webcam texture from webcam
    31.         var name = devices[0].name;
    32.         Debug.Log($"Using Webcam {name}");
    33.         _webcam = new WebCamTexture(name);
    34.         _webcam.Play();
    35.  
    36.         // Apply to image
    37.         var img = Document.rootVisualElement.Q<Image>();
    38.         if (img != null)
    39.         {
    40.             img.image = _webcam;
    41.         }
    42.  
    43.         // Now about that bg image
    44.         _texture2D = new Texture2D(
    45.             _webcam.width, _webcam.height,
    46.             TextureFormat.ARGB32, 1, false);
    47.  
    48.         // Make the texture 2D the bg image.
    49.         var bgImage = Document.rootVisualElement.style.backgroundImage.value;
    50.         bgImage.texture = _texture2D;
    51.         Document.rootVisualElement.style.backgroundImage = bgImage;
    52.     }
    53.  
    54.     private void Update()
    55.     {
    56.         // Sadly we have to copy from the webcam to the texture2D manually.
    57.         // Maybe this could be avoided if there is a way to hook up the webcam
    58.         // texture to a render texture (backgroundImage has a renderTexture target).
    59.         Graphics.CopyTexture(_webcam, _texture2D);
    60.     }
    61. }
    62.  
    I hope
    Graphics.CopyTexture
    uses Graphics.Blit() to copy the texture and does not read and write every pixel as that would be slow.
     
    Last edited: Jul 22, 2023
    yusuf_isik likes this.
  6. yusuf_isik

    yusuf_isik

    Joined:
    Feb 14, 2014
    Posts:
    21
    Thanks a lot. I have created an Image via code and have assigned my WebCamTexture. And it has worked like a charm.

    Code (CSharp):
    1. Graphics.CopyTexture(_webcam, _texture2D);
    This line is also a nice idea. I will consider it if I need it for different scenarios.

    Thanks again.
     
    _geo__ likes this.