Search Unity

Best Practices for Unity WebGL with Asset Bundles

Discussion in 'Web' started by MFKJ, May 22, 2019.

  1. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    What are some of the best practices to use asset bundles in WebGL. Keeping in mind the fact that Webgl is single thread, my player get stuck/freez when asset bundles is loading. And after loading the initial asset bundle, my player/camera almost completely freeze for 2 or 3 minutes. For optimization purpose I found somewhere in unity forum that I should use non compress asset bundles. is that right?
    Here is my asset bundle loading code that load different chunks of model based on player position:
    Code (CSharp):
    1. public IEnumerator DownloadAB()
    2.     {
    3.  
    4.         if (isBundleLoading == true)
    5.             yield return false;
    6.  
    7.         BundleLoadStatus = BundleLoadStatusEnum.bundlesLoading;
    8.         isBundleLoading = true;
    9.  
    10.         www = UnityWebRequestAssetBundle.GetAssetBundle(finalABLoaderURL);
    11.         yield return www.SendWebRequest();
    12.  
    13.         if (www.error != null)
    14.         {
    15.             Debug.LogError("assetBundleURL : " + finalABLoaderURL);
    16.             Debug.LogError("www error : " + www.error);
    17.             www.Dispose();
    18.             www = null;
    19.             yield break;
    20.         }
    21.  
    22.         bundle = ((DownloadHandlerAssetBundle)www.downloadHandler).assetBundle;
    23.         //GameObject bundlePrefab = null;
    24.         //bundlePrefab = (GameObject)bundle.LoadAsset(bundle.name);
    25.  
    26.         //bundlePrefab = (GameObject)bundle.LoadAsset(bundle.GetAllAssetNames()[0]);
    27.         AssetBundleRequest bundlePrefabAsync = bundle.LoadAssetAsync(bundle.name, typeof(GameObject));
    28.         //yield return bundlePrefab;
    29.         yield return bundlePrefabAsync;
    30.  
    31.         // if we got something out
    32.         if (bundlePrefabAsync != null)
    33.             //if (bundlePrefab != null)
    34.         {
    35.             //First Off the Origin S***fting
    36.             environmentOriginSetter.EnvironmentOriginSetterFeatureActive(false);//TODO
    37.             //assetBundleToLoadObj = (GameObject)Instantiate(bundlePrefab);
    38.          
    39.             //Then Instantiate the Bundel Object and make it child to environment parent object.
    40.             assetBundleToLoadObj = Instantiate(bundlePrefabAsync.asset as GameObject);
    41.             assetBundleToLoadObj.transform.parent = envParent.transform;
    42.             //assetBundleToLoadObj.transform.parent.transform.position = this.transform.localPosition;//new
    43.  
    44.             //Then Enable the Origin Setter feature again
    45.             environmentOriginSetter.EnvironmentOriginSetterFeatureActive(true);
    46.  
    47.             //disable the floor L7 Mesh
    48.             floorL7MeshRenderer.enabled = false;//TODO
    49.         }
    50.  
    51.         www.Dispose();
    52.         www = null;
    53.  
    54.         // try to cleanup memory
    55.         //Resources.UnloadUnusedAssets();//TODO open if memory problem occur
    56.         bundle.Unload(false);//TODO open if memory problem occur
    57.         bundle = null;
    58.  
    59.         isBundleLoading = false;
    60.         BundleLoadStatus = BundleLoadStatusEnum.bundlesHasLoaded;
    61.     }
     
    Last edited: May 23, 2019
  2. kognito1

    kognito1

    Joined:
    Apr 7, 2015
    Posts:
    331
    So a couple things...on webgl it's going to be hard to load an asset bundle smoothly while simultaneously playing a game because, as you noted, webgl is currently single threaded. Doing any non-trivial "background jobs" are going to be difficult to pull off. Having said that using uncompressed asset bundles is the best choice for this situation, but I'm just not sure even that will yield you the results you're looking for.

    As for the code given above, I'd just note that you can dispose of the UnityWebRequest immediately after assigning the assetbundle to a reference. You're currently doing it after you're "finished" with the bundle when really it should happen before you start using the bundle. That's only going to impact memory though and not so much loading performance (freezing).
     
  3. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Yes, I can understand that webgl player will freeze during asset bundle loading but the problem is the player still get stuck even after loading the asset bundles. At my side it taking 40-60 seconds to smoothly run and at client side sometime it takes 3-4 minutes even after completely loading the bundle. I am loading a sequence of asset bundle and showing a loading bar, but my loading bar get disappear and after that user have to wait around one minute and sometime 3-4 minute to smothly move the player/camera. Is this also normal?
    Lets assume it is acceptable to wait/freeze as asset bundles are loading but after even finishing the bundle loading the user have to wait for 1 minutes (at my pc testing) or 3 minutes (at client pc testing).

    And Thanks for the recommendation, I will dispose the unitywebrequest after bundle assignment and will let you know that it makes any impact or not.
     
  4. kognito1

    kognito1

    Joined:
    Apr 7, 2015
    Posts:
    331
    Then there is something else at play here that's causing the 1-3 minutes of freezing. There should be no freezing after you have downloaded an asset bundle, loaded its contents, and then unloaded it. So just to be clear, when loading the same level/scene "normally" (no asset bundles), there's no 1-3 minutes of freezing?
     
  5. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Yeah, i am thinking the same that why it freeze even after loading the bundle, is there any background related work in progress for bundles ?. I try to profile and found that the profiler also get stuck for that time duration, then it start again with a renderer spike. I have get stuck in this problem from last 3/4 days but unable to solve it, even unable identify it.
     
  6. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    My issue is related to this forum thread. The build working fine in editor.
     
  7. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    There is no freeze when i am initially load the scene.
     
  8. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    The lag/freeze after loading the asset bundle is not occurring in Edge browser while it persistent in chrome and firefox.
     
  9. kognito1

    kognito1

    Joined:
    Apr 7, 2015
    Posts:
    331
    Interesting...Edge is WebGL 1 whereas chrome/firefox are WebGL 2. Perhaps the lock/freeze you are seeing is due to a shader being compiled?
     
  10. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    A while back I had a strange issue where if I used GPU instancing it would cause a very long freeze the first time a mesh was rendered with that shader, only in the web build (and only WebGL 2 since it isn't supported in WebGL 1) - any chance you've got a shader in your asset bundle that uses GPU instancing?
     
    mowax74 and MFKJ like this.
  11. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    I need to check that if any shader using gpu instancing or not. I will let you know soon.
     
  12. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    If i remember it correctly, I am using only standard shaders. Anyway i will check it. Do you have any idea which shader is taking time?
     
  13. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Thanks buddy, initial test suggest the positive outcome (I am very very grateful for you, how did you debug it? I have get stuck in this issue from last 10 days). Yes, there are different materials set to gpu instance(I don't know how this property was checked) which i have unchecked now and new asset bundles are developed. Now the build is not taking time after loading the bundle. I will make more test and let you inform. Thanks anyway.
     
  14. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    I'm actually surprised that ended up being the issue, to the point I wasn't sure if it was worth posting but glad it helped. I found it some time ago when I noticed long freezes when loading a particular mesh. After some investigation the only different thing about this was that its material used GPU instancing. I ended up using a non-instancing solution instead.

    I did submit a bug report at the time (Case 1053737) but it looks to have been closed. I can't find it in the public issue tracker to see what the reason was but it doesn't appear to have been fixed unfortunately. I'd say if you don't actually benefit from GPU instancing for your use case, just turn it off - if you do, I'm afraid I don't know of any workarounds.
     
    MFKJ likes this.
  15. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    My project has large number of repeated assets like buildings, trees, tracks and grass and some of materials was using gpu instancing (I don't exactly remember that i checked them previously or not) but definitely it was taking benefit of this feature(i didn't compare the performance yet).
    I request to unity to look into this matter.
     
  16. jli262

    jli262

    Joined:
    Jun 24, 2020
    Posts:
    1
    But one problem is the process of "GetAssetBundle" will be blocked by CORS :(
     
  17. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    I guess you can allow CORS setting in your webserver.