
Предисловие
В недавнем скриншотнике мы говорили, что работали над оптимизацией. Slash Polygon: Tournament предназначен прежде всего для мобильных платформ, поэтому вопрос производительности для нас почти номер 1.
Mesh Composer
Мы сделали небольшой скрипт, который сшивает меши в один, экономя отрисовку на устройстве. Инструкция использования простая:

- Создайте пустой Game Object
- В качестве Child к созданному объекту добавьте те модели, которые хотите сшить (для них должен использоваться 1 материал, иначе от сшивание нет смысла)
- Добавьте компонент на Game Object - Mesh Composer
- (опционально) Для подчиненных объектов можно включить Mesh Collider

Вcпомогательная информация:
- Total Childs (сколько подчиненных объектов в группе)
- Total Verts (сколько в итоге вертексов получается в сшитом объекте)
- Ругань, если подчиненные сшитые объекты имеют разный материал
- Ругань, если максимальное количество вершин в одном сшитом объекте > 65536
Код
using UnityEngine; namespace Visual { [RequireComponent(typeof(MeshFilter))] [RequireComponent(typeof(MeshRenderer))] public class MeshComposer : MonoBehaviour { public MeshFilter MyFilter; public MeshRenderer MyRenderer; public MeshFilter[] InternalFilters; public Material SharedMaterial; [SerializeField] private bool _useMeshCollider; private void Awake() { Compose(); } private void Compose() { var combineMeshes = new CombineInstance[InternalFilters.Length]; for (int i = 0; i < combineMeshes.Length; i++) { combineMeshes[i].mesh = InternalFilters[i].mesh; combineMeshes[i].transform = InternalFilters[i].transform.localToWorldMatrix; InternalFilters[i].gameObject.SetActive(false); } MyFilter.mesh = new Mesh(); MyFilter.mesh.CombineMeshes(combineMeshes, true, true, false); MyRenderer.material = SharedMaterial; if (_useMeshCollider) { var collider = gameObject.AddComponent<MeshCollider>(); collider.sharedMesh = MyFilter.mesh; } } } }
using System.Linq; using UnityEditor; using UnityEngine; namespace Visual.Editor { [CustomEditor(typeof(MeshComposer))] public class MeshComposerInspector : UnityEditor.Editor { private MeshComposer _instance; private void OnEnable() { _instance = (MeshComposer) target; } public override void OnInspectorGUI() { base.OnInspectorGUI(); _instance.MyFilter = _instance.GetComponent<MeshFilter>(); _instance.MyRenderer = _instance.GetComponent<MeshRenderer>(); // fetch childs _instance.InternalFilters = _instance.GetComponentsInChildren<MeshFilter>() .Where(filter => filter != _instance.MyFilter).ToArray(); EditorUtility.SetDirty(_instance); EditorGUILayout.HelpBox($"total childs:{_instance.InternalFilters.Length}", MessageType.Info); if (_instance.InternalFilters == null || _instance.InternalFilters.Length == 0) return; var totalVerts = _instance.InternalFilters.Select(filter => filter.mesh.vertices.Length) .Aggregate((total, next) => total += next); var messageType = MessageType.Info; if (totalVerts > uint.MaxValue) messageType = MessageType.Error; EditorGUILayout.HelpBox($"total verts: {totalVerts}", messageType); var useSameMaterial = true; var material = _instance.InternalFilters[0].GetComponent<MeshRenderer>().sharedMaterial; foreach (var meshFilter in _instance.InternalFilters) { var rend = meshFilter.GetComponent<MeshRenderer>(); if (rend.sharedMaterial != material) { useSameMaterial = false; break; } } if (!useSameMaterial) { EditorGUILayout.HelpBox($"Internal meshses uses different materials, must be the same!", MessageType.Error); } else { _instance.SharedMaterial = material; } EditorUtility.SetDirty(_instance); } } }
Скачать Mesh Composer
Два готовых скрипта для использования в Unity.
Результат
В видео показан игровой процесс с устройства. В видео стоит ограничитель на максимальный FPS - 30 кадров. Количество Batches и Tris уменшилось на порядок, игра из конкретно нестабильного куска гов билда превратилась в нормальный рабочий прототип.
Смотрите также:
Комментарии
Возможно глупый вопрос, но я пока только вникаю в юнити.
Лоды при этом методе у мешей сохраняются? Какие объекты выгоднее всего таким образом объединять?
Возможно глупый вопрос, но я пока только вникаю в юнити.
Лоды при этом методе у мешей сохраняются? Какие объекты выгоднее всего таким образом объединять?
LOD-ы нет вроде, не делали.
Все существующие меши отключаются на старте, остается только инстансы внутри группировки.
Лучше всего объединять мелкие объекты (мы сшивали лесной участок).
vadya_ivan, рад, что вам игра показалась интересной : )
P.S. Кстати уже доступна бесплатная демо-версия в Steam