Huge world loading/unloading in unity webgl using

2019-07-07 17:01发布

问题:

I have a very large 3D world/Environment which

  1. I have divided into 1000 x 1000 m (1km) tiles.

  2. Made assetbundles of all tiles and currently there are only 5 asset bundles (Expected to grow significantly maybe around 1000 asset bundles).

  3. Loading\unloading these asset bundles, i am calculating the distance of my player/camera with the tile and then calling for load or unload.

Please see below simple script (Loading tiles based on distance):

        public Vector3 tileSize;
        public int maxDistance;
        public MultipleAssetBundleLoader[] tiles;

        void Start()
        {
            this.tiles  = FindObjectsOfType<MultipleAssetBundleLoader>();
        }

        void DeactivateDistantTiles()
        {
                foreach (MultipleAssetBundleLoader tile in tiles)
                {
                    Vector3 tilePosition = tile.gameObject.transform.position + (tileSize / 2f);

                    float xDistance = Mathf.Abs(tilePosition.x - playerPosition.x);
                    float zDistance = Mathf.Abs(tilePosition.z - playerPosition.z);

                    if (xDistance + zDistance > maxDistance)
                    {
                        tile.DestroyBundleObject();
                        //tile.SetActive(false);
                    }
                    else
                    {
                        tile.StartDownloadingAB();
                    }
                }  
        }

        void Update()
        {
            DeactivateDistantTiles();
        }

The function StartDownloadingAB simply download the asset bundles and instantiate game object from server or cache while DestroyBundleObject deactive the game object of the loaded bundle (if available). Here are code snippet for download the asset bundle:

public void StartDownloadingAB()
        {
            if (BundleLoadStatus == BundleLoadStatusEnum.bundleNotLoadedYet)
            {
                BundleLoadStatus = BundleLoadStatusEnum.bundlesLoading;
                downloadABRef = StartCoroutine(DownloadAB());
            }
            else if (bundleObjectsDeactivated == true && BundleLoadStatus == BundleLoadStatusEnum.bundlesHasLoaded)
            {
                BundleObjectActive(true);
            }
        }

public IEnumerator DownloadAB()
{

    if (isBundleLoading == true)
        yield return false;

    BundleLoadStatus = BundleLoadStatusEnum.bundlesLoading;
    isBundleLoading = true;

    //Debug.Log("loading " + url);
    www = UnityWebRequestAssetBundle.GetAssetBundle(url);
    yield return www.SendWebRequest();

    if (www.error != null)
    {
        Debug.LogError("assetBundleURL : " + url);
        Debug.LogError("www error : " + www.error);
        www.Dispose();
        www = null;
        yield break;
    }

    AssetBundle bundle = ((DownloadHandlerAssetBundle)www.downloadHandler).assetBundle;

    GameObject bundlePrefab = null;
    bundlePrefab = (GameObject)bundle.LoadAsset(bundle.name);
    AssetBundleRequest bundlePrefabAsync = bundle.LoadAssetAsync(bundle.name, typeof(GameObject));
    yield return bundlePrefab;

    if (bundlePrefab != null)
    {

        //assetBundleToLoadObj = (GameObject)Instantiate(bundlePrefab);
        assetBundleToLoadObj = Instantiate(bundlePrefabAsync.asset as GameObject);
        assetBundleToLoadObj.transform.parent = envParent.transform;

        floorL7MeshRenderer.enabled = false;
    }

    www.Dispose();
    www = null;

    // try to cleanup memory
    Resources.UnloadUnusedAssets();
    bundle.Unload(false);
    //bundle = null;

    isBundleLoading = false;
    BundleLoadStatus = BundleLoadStatusEnum.bundlesHasLoaded;
}

And For Destroying (actually deactivating the object as destroy is expensive function) the bundle.

Performance Issue:

The code is working fine and I am able to load/unload the asset bundle But the problems are

  1. its performance is not good (The loop is expected to grow).

  2. The Webgl is leggy sometime and it is not seamless or smoothly runs.

  3. When downloading the content(asset bundles) the game freeze despite using LoadAssetAsync.

Can anyone help me to write more efficient and elegant way to load/unload asset bundle ?

回答1:

You should first of all look at the profiler and see the choke points of your application, if it is stuck at loading bundles (coroutines are still run on the main thread and might cause lags) you might want to use async loading. But you would want to call those ahead of time (when player is NEAR the other chunk, so its ready when he actually reaches the chunk). If your bottlenecks lies somewhere else, for example something to do with rendering you might approach it some other way (smaller assets with less vertices/triangles or more aggressive culling). Either way for better judgement you need to locate where the problem is, but from the first look it seems that loading the asset on main thread is the problem.