Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Unity WebGL freezes when loading files

Discussion in 'Web' started by DreamDelerium, Oct 24, 2023.

  1. DreamDelerium

    DreamDelerium

    Joined:
    Jan 14, 2017
    Posts:
    17
    Hello. I am trying to build a scene that will load an OBJ file and JPG texture file, from Azure Storage, and display in the scene. This code works fine when running in Unity, but when I export it as WebGL and run it in my browser, it freezes the browser and doesn't seem to run. For the setup, I have a virtual Azure Cloud emulator running (Azurite). No error is thrown, it just freezes. Here is my Unity code:

    public void RunCode(string key)
    {
    Console.WriteLine("Running code with key: " + key);
    string authorization, date;
    Key = key;

    try
    {
    Blobs(out authorization, out date, "MyObj_1.obj");
    using (WebClient client = new WebClient())
    {
    client.Headers.Add("Authorization", authorization);
    client.Headers.Add("x-ms-date", date);
    client.Headers.Add("x-ms-version", apiversion);
    var res = client.DownloadString(objURL + "MyObj_1.obj");

    MemoryStream textStream = new MemoryStream(Encoding.UTF8.GetBytes(res));
    if (model != null)
    {
    Destroy(model);
    }
    model = new OBJLoader().Load(textStream);
    model.transform.localScale = new Vector3(-1, 1, 1);
    model.transform.localPosition = new Vector3(10, -1164, 530);
    LoadTexture();
    }

    }
    catch(Exception e)
    {
    Console.WriteLine(e);
    }
    }

    private void LoadTexture()
    {
    string authorization, date;
    Blobs(out authorization, out date, "MyImg.jpg");

    using (WebClient client = new WebClient())
    {
    client.Headers.Add("Authorization", authorization);
    client.Headers.Add("x-ms-date", date);
    client.Headers.Add("x-ms-version", apiversion);
    byte[] textureData = client.DownloadData(objURL + "MyImg.jpg");
    Texture2D texture = new Texture2D(2, 2);
    texture.LoadImage(textureData);

    Renderer renderer = model.GetComponentInChildren<Renderer>();
    if (renderer != null)
    {
    renderer.material.mainTexture = texture;
    }

    }
    }

    private void Blobs(out string auth, out string date, string blob)
    {
    DateTime dt = DateTime.UtcNow;
    string StringToSign = String.Format("GET\n"
    + "\n" // content encoding
    + "\n" // content language
    + "\n" // content length
    + "\n" // content md5
    + "\n" // content type
    + "\n" // date
    + "\n" // if modified since
    + "\n" // if match
    + "\n" // if none match
    + "\n" // if unmodified since
    + "\n" // range
    + "x-ms-date:" + dt.ToString("R") + "\nx-ms-version:" + apiversion + "\n" // headers
    + "/{0}/{0}/{1}/{2}", Account, Container, blob);

    string signature = SignThis(StringToSign, Key, Account);

    auth = string.Format(
    CultureInfo.InvariantCulture,
    "{0} {1}:{2}",
    "SharedKey",
    Account,
    signature);

    date = dt.ToString("R");
    }

    static String SignThis(String StringToSign, string Key, string Account)
    {
    String signature = string.Empty;
    byte[] unicodeKey = Convert.FromBase64String(Key);
    using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
    {
    Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
    signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
    }

    return signature;
    }

    On the JS side, I then call the function like this:

    let GameInstance = null;

    window.UnityFunction = () => {
    GameInstance.SendMessage("ObjModel", "RunCode", "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");


    };
    window.initializeUnity = () => {
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    function unityShowBanner(msg, type) {
    function updateBannerVisibility() {
    warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
    }
    var div = document.createElement('div');
    div.innerHTML = msg;
    warningBanner.appendChild(div);
    if (type == 'error') div.style = 'background: red; padding: 10px;';
    else {
    if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
    setTimeout(function () {
    warningBanner.removeChild(div);
    updateBannerVisibility();
    }, 5000);
    }
    updateBannerVisibility();
    }

    var buildUrl = "Build/Build";
    var loaderUrl = buildUrl + "/Build.loader.js";
    var config = {
    dataUrl: buildUrl + "/Build.data",
    frameworkUrl: buildUrl + "/Build.framework.js",
    codeUrl: buildUrl + "/Build.wasm",
    streamingAssetsUrl: "StreamingAssets",
    companyName: "DefaultCompany",
    productName: "AzureRemoteRendering",
    productVersion: "0.1",
    showBanner: unityShowBanner,
    };
    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
    var meta = document.createElement('meta');
    meta.name = 'viewport';
    meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
    document.getElementsByTagName('head')[0].appendChild(meta);
    container.className = "unity-mobile";
    canvas.className = "unity-mobile";


    unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
    canvas.style.width = "960px";
    canvas.style.height = "600px";
    }

    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
    createUnityInstance(canvas, config, (progress) => {
    progressBarFull.style.width = 100 * progress + "%";
    }).then((unityInstance) => {
    loadingBar.style.display = "none";
    fullscreenButton.onclick = () => {
    unityInstance.SetFullscreen(1);
    };
    GameInstance = unityInstance;
    }).catch((message) => {
    alert(message);
    });
    };
    document.body.appendChild(script);
    };
     
  2. DreamDelerium

    DreamDelerium

    Joined:
    Jan 14, 2017
    Posts:
    17
    Nevermind. I moved these methods into a Coroutine and it works well. thanks!
     
    bugfinders likes this.
  3. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,028
    Ungh. Unity has UnityWebRequest class for this. You can yield it in a coroutine.

    PS: please use code tags next time.