【问题标题】:Huge world loading/unloading in unity webgl using asset bundles使用资产包在统一 webgl 中加载/卸载巨大的世界
【发布时间】:2019-04-08 09:26:17
【问题描述】:

我有一个非常大型 3D 世界/环境

  1. 我已分成 1000 x 1000 m (1km) 的图块

  2. 制作所有图块的assetbundles,目前只有5个asset bundles(预计会大幅增长,可能在1000左右 资产包)。

  3. 加载\卸载这些资产包,我正在计算我的播放器/相机与瓷砖的距离,然后调用 加载或卸载。

请看下面的简单脚本(根据距离加载图块):

        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();
        }

StartDownloadingAB 函数只需从服务器或缓存下载资源包并实例化游戏对象,同时 DestroyBundleObject 停用加载包的游戏对象(如果可用)。 以下是用于下载资产包的代码 sn-p:

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;
}

为了销毁(实际上将对象作为销毁是昂贵的功能而停用)捆绑包。

性能问题:

代码运行良好,我可以加载/卸载资产包但问题是

  1. 它的性能不好(循环预计会增长)。

  2. Webgl 有时会很长,而且运行不流畅。

  3. 下载内容(资产包)时,尽管使用了 LoadAssetAsync,但游戏仍会冻结

谁能帮我写出更高效、更优雅的方式来加载/卸载资产包?

【问题讨论】:

  • @MuhammadFaizanKhan ,我很困惑,为什么不使用 GetAssetBundle ?或者这种事情docs.unity3d.com/540/Documentation/Manual/…我只是看了你的问题...对不起..
  • @Fattie 实际上我正在使用 GetAssetBundle。我已经更新了之前缺少的实际资产包加载代码。
  • 这个问题和the one you asked on GameDev有什么不同?
  • 如果你仔细观察,我提到的编码 sn-p 是有区别的。

标签: c# unity3d unity-webgl assetbundle


【解决方案1】:

您应该首先查看分析器并查看应用程序的阻塞点,如果它在加载包时卡住(协程仍在主线程上运行并且可能导致延迟),您可能想要使用async loading .但是你会想要提前调用那些(当玩家靠近另一个块时,所以当他实际到达块时它就准备好了)。 如果您的瓶颈在其他地方,例如与渲染有关,您可能会以其他方式处理它(具有更少顶点/三角形或更积极的剔除的较小资产)。无论哪种方式,为了更好地判断,您都需要定位问题所在,但乍一看,似乎在主线程上加载资产是问题所在。

【讨论】:

  • 其实unity webgl 是单线程的,因为javascript 是单线程的。我尝试通过探查器找到它,但我的开发构建正在成功执行。我发现我的播放器在编辑器中运行良好。
  • 你不需要真正的多线程来运行异步操作,你可以提前开始加载资产以避免阻塞点。
  • 预先是什么意思?我必须根据相机/播放器的接近程度来下载资产包。
  • @MuhammadFaizanKhan 1) 即使开发构建成功,分析器仍然会显示有价值的信息,因为在大多数情况下,资源消耗(CPU、RAM 等)在整个系统中是成比例的(大多)。所以你真的应该确保资产的加载是问题(它是主要的消费原因)。
  • 2) 如果问题确实出在资产中,并且播放器的速度非常快,以至于您无法事先一点一点地下载资产(当播放器已经完成一半时)例如,块,或更少或更多,取决于您的包大小),在这种情况下,您可以压缩包,使其通过 HDD 或 Web 传输的字节更少,或者您可以尝试使用块大小并限制播放器速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多