Search code examples
c#unity-game-engineunity-editor

Using Unity Editor, how do i upload a file from my computer and have it appear on a 3D object or plane?


I found a tutorial on YouTube that accurately added File Explorer and image upload to a 'RawImage' on a canvas using Unity 2017.3.1f1.

enter image description here

What I'm trying to do is add the same image after 'button press' to a 3D object like a cube or plane as shown by the colored cube. When I run the below code, it registers as being present on the cube but doesn't render. Any help is appreciated.

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

public class Explorer : MonoBehaviour
{
    string path;
    public RawImage image;

    public void OpenExplorer()
    {
        path = EditorUtility.OpenFilePanel("Overwrite with png", "", "png");
        GetImage();
    }

    void GetImage()
    {
        if (path != null)
        {
            UpdateImage();
        }
    }
    void UpdateImage()
    {
        WWW www = new WWW("file:///" + path);
        image.texture = www.texture;
    }
}

Solution

  • There is a tiny bug in your code. It should work sometimes and fail other times. The chances of it working or not depends on the size of the image. It will work if the image is really small but fail when it is a large image.

    The reason for this is because of the code in your UpdateImage function. The WWW is supposed to be used in a coroutine function because you need to yield or wait for it to finish loading or downloading the file before accessing the texture with www.texture. Your are not doing this now. Change it to a coroutine function then yield it and it should work fine,.

    void GetImage()
    {
        if (path != null)
        {
            StartCoroutine(UpdateImage());
        }
    }
    
    IEnumerator UpdateImage()
    {
        WWW www = new WWW("file:///" + path);
        yield return www;
        image.texture = www.texture;
    }
    

    If some reason you can't use a coroutine because it's an Editor plugin then forget about the WWW API and use use File.ReadAllBytes to read the image.

    void GetImage()
    {
        if (path != null)
        {
            UpdateImage();
        }
    }
    
    void UpdateImage()
    {
        byte[] imgByte = File.ReadAllBytes(path);
        Texture2D texture = new Texture2D(2, 2);
        texture.LoadImage(imgByte);
    
        image.texture = texture;
    }
    

    To assign the image to a 3D Object, get the MeshRenderer then set the texture to the mainTexture of the material the renderer is using:

    //Drag the 3D Object here
    public MeshRenderer mRenderer;
    
    void UpdateImage()
    {
        byte[] imgByte = File.ReadAllBytes(path);
        Texture2D texture = new Texture2D(2, 2);
        texture.LoadImage(imgByte);
    
        mRenderer.material.mainTexture = texture;
    }