#c# #unity3d #unity-webgl #assetbundle
#c# #unity3d #unity-webgl #assetbundle
Вопрос:
У меня очень большой 3D-мир / среда, который
-
Я разделил на плитки размером 1000 x 1000 м (1 км).
-
Создал пакеты активов из всех плиток, и в настоящее время существует только 5 пакетов активов (ожидается значительный рост, возможно, около 1000 пакетов активов).
- Загружая выгружая эти пакеты ресурсов, я вычисляю расстояние моего плеера / камеры до плитки, а затем вызываю загрузку или выгрузку.
Пожалуйста, смотрите ниже простой скрипт (загрузка фрагментов на основе расстояния):
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 деактивирует игровой объект загруженного пакета (если он доступен).
Вот фрагмент кода для загрузки пакета ресурсов:
public void StartDownloadingAB()
{
if (BundleLoadStatus == BundleLoadStatusEnum.bundleNotLoadedYet)
{
BundleLoadStatus = BundleLoadStatusEnum.bundlesLoading;
downloadABRef = StartCoroutine(DownloadAB());
}
else if (bundleObjectsDeactivated == true amp;amp; 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;
}
И для уничтожения (фактически деактивации объекта, поскольку уничтожение является дорогостоящей функцией) пакета.
Проблема с производительностью:
Код работает нормально, и я могу загружать / выгружать пакет активов, но проблемы
-
его производительность невелика (ожидается, что цикл будет расти).
-
Webgl иногда бывает длинноногим, и он не является бесшовным или плавно работает.
- При загрузке контента (пакетов ресурсов) игра зависает, несмотря на использование LoadAssetAsync.
Кто-нибудь может помочь мне написать более эффективный и элегантный способ загрузки / выгрузки пакета активов?
Комментарии:
1. @ MuhammadFaizanKhan , я в замешательстве, почему не использовать GetAssetBundle ? или что-то в этом роде docs.unity3d.com/540/Documentation/Manual/… Я только что взглянул на ваш вопрос… извините..
2. @Fattie На самом деле я использую GetAssetBundle. Я обновил фактический код загрузки пакета активов, который отсутствовал ранее.
3. Чем этот вопрос отличается от того, который вы задавали на GameDev ?
4. Если вы внимательно изучите, есть разница между фрагментом кода, о котором я упоминал.
Ответ №1:
Вы должны прежде всего взглянуть на профилировщик и увидеть точки блокировки вашего приложения, если оно застряло при загрузке пакетов (сопрограммы все еще выполняются в основном потоке и могут вызывать задержки), возможно, вы захотите использовать асинхронную загрузку. Но вы хотели бы вызвать их заранее (когда игрок находится РЯДОМ с другим фрагментом, чтобы он был готов, когда он действительно достигнет фрагмента). Если ваши узкие места находятся где-то в другом месте, например, что-то связанное с рендерингом, вы можете подойти к этому другим способом (меньшие ресурсы с меньшим количеством вершин / треугольников или более агрессивный отбор). В любом случае для лучшего суждения вам нужно определить, в чем проблема, но с первого взгляда кажется, что проблема заключается в загрузке ресурса в основной поток.
Комментарии:
1. На самом деле Unity webgl является однопоточным, поскольку javascript является однопоточным. И я пытаюсь найти его через профилировщик, но моя сборка разработки выполняется успешно. я обнаружил, что мой проигрыватель отлично работает в редакторе.
2. Вам не нужна реальная многопоточность для выполнения асинхронных операций, вы можете просто начать загрузку ресурсов заранее, чтобы избежать проблем.
3. что вы подразумеваете под заранее? Я должен загрузить пакет ресурсов в зависимости от близости камеры / плеера.
4. @MuhammadFaizanKhan 1) Даже если сборка разработки прошла успешно, профилировщик все равно покажет ценную информацию, потому что в большинстве случаев потребление ресурсов (CPU, RAM и т.д.) Пропорционально в разных системах (в основном). Итак, вы действительно должны убедиться, что загрузка активов является проблемой (является ли это основной причиной потребления).
5. 2) Если проблема действительно в ресурсах и скорость проигрывателя настолько велика, что вам не удается загружать ресурс понемногу заранее (например, когда проигрыватель прошел половину блока, или меньше, или больше, в зависимости от размера вашего пакета), в этом случае вы можете либо сжать пакет, чтобы в нем было меньше байтов для передачи через жесткий диск или Интернет, либо вы можете попробовать поиграть с размерами блоков и ограничить скорость проигрывателя.