Unity. Тесты скорости разных способов вывода графики.

(Кому лень читать весь пост, читайте вывод в самом конце)

Так как я перехожу на юнити, а в играх перехожу на нормальное игровое поле (а не только интерфейсы как до этого), то сама собой возникла необходимость найти самый быстрый способ вывода графики.

Для теста берется 1000 элементов квадратов 200 на 200 между которыми раскидано 16 текстур (200 на 200) с прозрачными и полупрозрачными кусками.
И рандомно меняем им позицию каждый кадр. Плюс часть вариантом тестировались с тряской общей сцены, а не отдельных элементов.

Статья получилась очень специфичная, так, что тем, кому не интересно, лучше пропустить.

Начальный план тестирования такой:

1) Вывод через Canvas
2) Вывод через SpriteRender
3) Вывод через раздельные Mesh
4) Вывод через комбинированные Mesh

Дополнительно

5) Базовый вывод спрайтов на флеше, через starling.
6) Быстрый вывод графики на флеше, тоже через starling, через класс MeshBatch.

Все это тестирование заняло несколько часов. Куча компиляций и запусков, куча вариантов.

В общем начальные тесты показали такие результаты.
1) Вывод через Canvas 600-800 ms на кадр.

Я уже знал что канва медленная по прежним тестам, но все же повторил его.

2) 270-280 ms при раздельном перемещении спрайтов. И 257ms если трясти всю карту (засунуть все спрайты, как дочерние, к другому объекту и перемещать весь объект).

Ускорение при общем перемещении приятно удивило. Видимо юнити очень хорошо оптимизирован при работе с спрайтами.

3) 303 ms при раздельном перемещении отдельных mesh. И 340ms если трясти родительский объект.

А тут я наоброт был удивлен неприятно. Я был уверен, что голые меши будут быстрее спрайтов. Ну и замедление при объединенном перемещении тоже не приятно.

4) Дальше я перешел к самому важному и сложному тесты. Вообще про комбинированные mesh надо чуток пояснить. Я просто собирал плитку из 16 элементов. И так как каждая плитка 16 элементов, то самих таких плиток ввел только 63. перемещал плитками. В общем тест получился не чистым, но все же какие-то ориентиры.

268ms.

Я ожидал радикального ускорения, хотя бы до 150! Что ж это говорит о том, что оптимизация работы со спрайтами очень хорошая проделана.

Написал те же тесты на флеше (starling)

5) Базовые спрайты соотносимы с Canvas и дают те же 600ms с лишним.

Из этого можно сделать вывод, что переход со спрайтов starling на спрайты unity уже сам по себе даст прирост скорости!

6) Быстрый вывод.
270ms при фиксированных квадратах. Что значит, что флеш все же не так уж и плох. (Я итак на быстром выводе делал игровые поля)
Однако можно при упаковке спрайтов обрезать прозрачные куски и тем самым уменьшить размеры текстур. Если использовать такую обрезку то скорость уже идет 180ms, потому, что по сути мы заранее обрезаем то, что итак будет обрезано, упрощая обработку.

В итоге первые выводы можно сделать такие:

1) Спрайты в юнити достаточно оптимизированны, чтобы не гоняться за мешами.
2) Юнити без дополнительных ухищрений быстрее чем флеш без дополнительных ухищрений.
3) Однако при всем при этом юнити пока еще не умеет сам обрезать лишнее от текстур, и если гнаться за скоростью, то нужно придумать способ минимизировать прозрачные участки.

___

Однако

Так бы я и остался с 270-280ms на спрайтах, но тут мне в голову пришла идея потыкать в шейдеры.

В итоге я создал материал с шейдером: «Unlit/Transparent«.
Присваивал его всем генерируемым объектам и потом к готовому материалу прикреплял нужную мне текстуру


obj.GetComponent().material = Resources.Load("Созданный материал");
obj.GetComponent().material.mainTexture = Resources.Load("Файл текстуры", typeof(Texture2D)) as Texture2D;

Если это можно сделать еще более оптимально, то буду благодарен за подсказку )

Тестирование проводилось для спрайтов, раздельных мешей, и комбинированного меша.

1) Спрайты показали 169ms /157ms (раздельное перемещение/совместное)

Очень приятный результат! Что же тогда дальше?

2) Раздельные меши показали 267ms / 292ms.

Тут я удивился. Я думал, что меши наоборот будут больше подвержены влиянию шейдеров. А скорость почти не поменялась.

3) Ок последний тест комбинированный меш из 16 квадратов.

102ms. Рекорд! Но так, как комбинированный меши изначально отличались от других способов (У него банально меньше вершин, чем в других вариантах), надо переписать этот тест, чтобы сделать его идентичным спрайтовому.

Увеличиваем количество вершин, чтобы каждый квадрат имел 4 самостоятельных угла… Добавляем перестановку вершин каждый кадр, чтобы сымитировать анимацию.

И… только 203ms
Но наверное сделаю все же еще один тест. А именно, вся тысяча квадратов в одном меше!
182ms. И артефакты с прозрачностью.

Вывод?

1) Можно использовать обычные спрайты (компонент Sprite Renderer) и ни о чем не переживать, юнити все сделает сам и сделает очень хорошо.
2) Нужно потестировать разные шейдеры. Так шейдер «Unlit/Transparent» показал ощутимое увеличение скорости при незаметном изменении качества.
3) Избегать прозрачности. Если прозрачности нет, то можно использовать шейдер «Mobile/Unlit (Supports Lightmap)» на нем спрайты хоть и отображаются неправильно (прозрачность не обсчитывается), но показывают 93ms
4) Если спрайты группировать, то они работают еще быстрее.
5) Однако если гнаться за скоростью, то для сцен, в которых объекты расположены впритык друг к другу все же целесообразно использовать генерируемый Mesh (и прикрепить к нему в текстуру соответствующий графичесский атласс).

На самом деле мне до сих пор не верится, что самый быстрый вариант — одновременно самый простой.
Конечно приятно, что не придется писать свой класс для рисовки через mesh, мне как-то лень. Но может я все же что-то упускаю и есть вариант еще быстрей?

 

____
UPD. Я таки упустил один нюанс.
Так например при тестировании спрайтов юнити делает порядок отображения как ему хочется, и если задать тот порядок который требует, то скорость падает в два раза, полностью перечеркивая результаты теста.

Итого в данный момент лучшую скорость показывает объединение всех объектов в один меш, с описанием каждого квадрата и рисование с одной текстуры.

Для полной чистоты эксперимента надо попробовать заставить спрайты рисоваться с одной текстуры.

UPD2.
Сделал еще два теста.
1) Спрайты упакованные с нарезкой на полигоны через TexturePacker
2) Самостоятельная генерация цельного меша с раздельными квадратами(и их треугольниками разумеется) на базе полигональной нарезки полученной от TexturePacker (Да я заморочился и написал именно это)

У меня спрайты с атлассом дали 40% прирост от варианта без атласса.
Вариант с самостоятельной генерацией меша быстрее варианта спрайтов с атласса на 2%. Но сложнее для реализации в разы.

Вывод:
Атлас через TexturePacker (Полигональная нарезка) + SpriteRender + Шейдер «Unlit/Transparent» показывают лучший результат, и лучше остановаиться на этом варианте (или я опять что-то упускаю)
При этом самостоятельная генерация цельного меша может быть чуть быстрее, но не стоит потраченных усилий.


Автор: Elsper.ru


VN:F [1.9.14_1148]
Rating: 10.0/10 (1 vote cast)
Unity. Тесты скорости разных способов вывода графики., 10.0 out of 10 based on 1 rating

23 thoughts on “Unity. Тесты скорости разных способов вывода графики.

  1. Элспер, ты можещь выложить гифку результата теста и исходные ресурсы, которые использовал при тестировании? Хочеться повторить этот же тест на чистом Canvas-е. Еще такой вопрос, тестировал на ПК или мобильном?

  2. Посмотрел тесты, подумал еще. И пришел к выводу что я совершил ошибку.

    Так например при тестировании спрайтов юнити делает порядок отображения как ему хочется, и если задать тот порядок который требует, то скорость падает в два раза, полностью перечеркивая результаты теста.

    Итого в данный момент лучшую скорость показывает объединение всех объектов в один меш, с описанием каждого квадрата и рисование с одной текстуры.

    Для полной чистоты эксперимента надо попробовать заставить спрайты рисоваться с одной текстуры.

  3. Хотя попробовать без атласа все же можно.

    Подкорректировал и картинки и сам код.
    http://elsper.ru/wp-content/uploads/2017/12/test_500_sprites.zip
    Тут apk, что бы было с чем сравнивать, и текстуры.

    Условие теста: ландшафтная ориентация, 500 квадратов с гранью в 50% от высоты устройства. Прозрачность, правильный порядок отрисовки, все вершины в кадре.

    Код

    List<GameObject> objs;
    List<Transform> tr;
    
    void Start()
    {
    objs = new List<GameObject>();
    tr = new List<Transform>();
    for (int i = 0; i < 500; i++)
    {
        GameObject obj = new GameObject();
        string nomer = (i % 16 + 1).ToString();
    
        obj.AddComponent<SpriteRenderer>().material = Resources.Load<Material>("New Material");
        obj.GetComponent<SpriteRenderer>().sprite = Sprite.Create(Resources.Load("img" + nomer, typeof(Texture2D)) as Texture2D, new Rect(0, 0, 200, 200), new Vector2(0f, 0f), 1f);
    
        obj.transform.SetParent(this.transform);
        objs.Add(obj);
        tr.Add(objs[i].transform);
        tr[i].localScale = new Vector2(1.2f, 1.2f); //Растягиваю объекты чтобы они занимали 50% высоты.
    
        obj.AddComponent<SortingGroup>().sortingOrder = i; //Выставляю порядок отображения.
    }
    }
    
    void Update()
    {
        for (int i = 0; i < objs.Count; i++)
        {
            tr[i].localPosition = new Vector2(180 + Random.value * 300, Random.value * 200);
        }
    }
    
  4. Спасибо Элспер, сегодня проверю. Вчера занимался созданием тестов. Сначала хотел использовать AVA, его даже сам разработчик Phaser использует. Но мне не подошнл, так как не позволяет создать главный объект game, которому необходимо наличие самой html страницы. Написать автору и ждать ответа, долго… написал несколько методов сравнения переменных и мне вроде хватает (уже нашел пару ошибок в словарях).

    У меня еще неожиданный подводный камень ожидал с тайским языком. У них же пробелов между слов нет… как Phaser-у разбивать такое длинное предложение, по факту слово на несколько строк? Пришлось писать свой собстенный метод мягкого переноса слов 🙁 Хорошо что на производительность не повлияло (в отличии от метода подгона размера шрифта).

  5. elsper, напиши потом плз про Unity PlayMaker или Blueprints.

    Как тебе эти приблуды для визуального программирования?

  6. Жека, Как человек использующий мышку в юнити настолько мало, насколько это возможно, я конечно использовать эти инструменты не буду.

    Но пару лет назад, я где-то на чьем-то мониторе видел какой-то аналог Blueprints, я тогда не понял, что это (и понял в итоге только недавно, начав разбираться с юнити), но предположил что это связано с программированием. И сама идея визуализации некоторой части программирования меня вдохновила, чтобы начать писать свой фреймворк и инструментарий.

    Я первым делом правда подумал о идее реализации/отображения зависимостей классов, чтобы меньше в них путаться. Эту задачу я так и не решил через визуализацию, я просто создал общий файл импортируемых классов и подключал его всем остальным классам, решив этим проблему на корню.

    Сейчас «упростители» такого рода мне не нужны. Мой инструментарий: дизайнер интерфесов, совмещенный с кодогенерацией для меня лучшее решение. Лучшее даже, чем инструменты самого юнити (именно поэтому, я все делаю кодом, потому, что, чтобы моя система работала, я должен полностью понимать, какой код она должна выдавать)

    Однако чужие инструменты я тоже использую. Сегодня купил программу, прочитав вот эти статьи и здраво рассудив, что легче заплатить, чем самому писать.
    https://habrahabr.ru/company/playrix/blog/306554/
    https://www.codeandweb.com/blog/2015/09/21/optimizing-unity-sprite-meshes

  7. А вообще, конечно и без того низкий уровень новичков от этого становится еще хуже.

    Встречал на каком-то форуме, человек спрашивает, как сделать что-то в коде, а местный «профи» из средней школы объясняет, что в юнити надо работать только мышкой, и если кто-то с этим не согласен, то должен прекратить использовать юнити.

  8. А вот и мои результаты, твоя программа стабильно держит 5-7 фреймов на моем слабом смартфоне. У меня фреймы скачут от 3.5 (самый низкий показатель) до 10. По началу больше 4-5, потом постепенно подымаеться и больше 8-10. Код повторил, но в вертикальном варианте + развернул x, y координаты, что бы кубики двигались по тому же алгоритму на экране.

    preload() {
    this.load.atlasJSONHash(‘test’, ‘assets/images/test.png’, ‘assets/images/test.json’);

    this.sprite_list = [];
    for (var i=0; i<500; i++) {
    this.sprite_list.push(this.game.add.sprite(0, 0, 'test', i % 16 + 1));
    }
    }

    update() {
    this.sprite_list.forEach(function(sprite) {
    sprite.x = this.game.rnd.integerInRange(0, 200);
    sprite.y = 180 + this.game.rnd.integerInRange(0, 300);
    }, this)
    }

    Что бы особо не тратить время, тест вставил прямо в свою игру и скомпилировал в apk на мобилу.

    Я бы сделал такое заключение: юнити более ПЛАВНО распределяет ресурсы, когда как HTML5 импульсивный. По этоу на Юнити даже глючный мобильник будет просто плавно тормозить, а вот на HTML5 будут скочки. Я даже 10 сек виде снял, если есть желание мог выложить.

    Послушай ваши рассуждения про визуаьную часть Unity, у меня сложилось впечатление что Unity это не среда разарботки, а среда сборки игры. Это не плохо, но и не хорошо… Все зависит от того, что ты делаешь. Unity это конструктор Lego, ты можешь быстро собрать конструкцию, но только из тех кубиков которые у тебя есть и по правилам Lego. Я лично от PhoneGap-а отказался только потому, что я не мог даже добавить свои плагины… а ведь такие как запрет на разворот экрана, полный экран и т.д. все это делают плагины + ручное редактироване манифеста для андроид проекта. Unity = профи вариант Game Maker-а. Произовительность игры он НЕ повышает, только сглаживает

  9. Вижу ты использовал атлассы. Я их сначала не использовал (Не знал как и сначала вообще думал, что юнити сам мне его слепит). Вот тут использовал. (Разобрался)
    http://elsper.ru/wp-content/uploads/2017/12/test_500_sprites_50percent_height_fast.zip

    И оно стало быстрее чем версия без атласа на 40%. Для полной чистоты эксперимента стоит еще этот файл глянуть.
    ___

    Юнити это и то и то. Я же написал, что использую код и у меня получается.
    Да система компонентов производит впечатление лего, но редактор достаточно гибкий. Можно писать свои вещи. При чем если например объявить публичную переменную в каком-нибудь классе (наследуемом от MonoBehaviour, но все скрипты что цепляются к объектам сцены наследуются от него), то в редакторе появляется поле и можно менять значение через редактор.

    На самом деле, когда я переходил в свой ранее любиый FlasDevelop чтобы написать тесты на флеше, у меня было ощущение похожее, как когда с нового компа возвращаешься на старый.
    Я рекомендую юнити.

    (Запрет разворота, точнее разрешенные положения я правда выставил в настройках проекта, и ручное редактирование манифеста еще не искал)

  10. По манифесту. Погуглил, есть легкий способ сделать мерж того, что делает юнити с тем, что нужно разработчику. Так, что тоже не проблема.

  11. Проверил новую версию. Работает быстрей, держит стабильно минимум 7 но позже понялось до 8. В целом Юнити сглаживает графику идеально. Нет скачков… главное ведь не сколько кадров, а насколько они приятны для глаза.

    На счет визуальной части — Элспер, есть ли возможность в Юнити визуально созавать интерфейс сцены? Допустим по примеру твоей игры, у меня есть класс кнопки, хомяка и просто графика (этажи, лестницы и т.д). Можно ли все это распложить на «экране» (сцене) визуально (мышкой) или надо координаты прописывать программно (как например с Flash, Phaser).

  12. p.p.s. развернул для экран и обновил логику, теперь частота у меня вообще подскакивает к 17-20. Но визуально, анимация Юнити плавней… тут как бы сначала все быстро, быстро… потом пауза на 50-100мс и потом все продолжается. Пробовал задать максимальный фреймрейт 7 (думал что бы плавно сработало) — фиг, Фейзеру плевать =) Пока все же я бы назвал Юнити победителем (хотя у него и меньше фрейм рейт или ты его считаешь не совсем верно)

  13. Нашел как в самом Phaser показать fps. Они показывают сренее значение и оно колеблиться от 5 до 7, но больше 5,6. Я если честно не верю… у Юнити 7 выглядит намного мягче. Может дело в типе обновления канвы? Элспер, можешь посмотреть, может в Юнити есть такая фишка и если отключить плавное обновление, fps повысится?

  14. «есть ли возможность в Юнити визуально созавать интерфейс сцены?»
    Как я понял — это не только возможно, но и самый предпочтительный путь.

    Это у меня все через… мой софт ))

    Хотя визуальная среда юнити мне тоже помогает, в ней удобно смотреть работающее приложение.

    «у тебя какое расширение выставлено для игры?»
    Расширение же вроде телефон дает. У меня 1920 x 1080

    «800 на 480.»
    Я кстати собираюсь переходить при проектировании на 854 х 480, как базовое, сделать внутреннюю зону 720х480, а не 640х480, как раньше. Но некоторые планшеты будут обрезать внутреннюю зону, поэтому если соотношение сторон захочет обрезать мне ширину дальше 720, то просто добавлю полосы сверху и снизу.

    double screen_aspect = (double)Screen.height / (double)Screen.width;
            if (screen_aspect > (double)2 / (double)3)
            {
                GetComponent<Camera>().orthographicSize = (float)(240 * screen_aspect * 3 / 2);
            }
            else
            {
                GetComponent<Camera>().orthographicSize = 240;
            }
    

    «Элспер, можешь посмотреть, может в Юнити есть такая фишка и если отключить плавное обновление, fps повысится?»
    Я ничего такого не нашел.

  15. Элспер, ты часто про свой софт говоришь, но особо сркиншоты не палишь =) Я конечно понимаю, секрет фирмы… но все же, зачем тебе использовать свой генератор сцен, когда у Unity есть хороший визуальный редактор + превю в реальном времени?

  16. «Расширение же вроде телефон дает»
    Я наверно не совсем точно выразился… я про рассширение самой сцены игры. Resize относительно мобилы у нас одинаковый, но я хотел убедится что сама сцена, где спраиты у нас одного размера. Ведь на самом деле происходит ее полнный redraw и чем она больше, тем больше на это унжно времени. Пока визуальный результат Unity мне нравится

  17. Вот прошлогодний кадр http://elsper.ru/wp-content/uploads/2016/09/0109work.jpg
    С тех пор расширилось и меню, и верхняя, и левая, и правая панель. Но основа была создана тогда.

    Сейчас переходя на юнити я конечно колебался использовать свою инструмент или юнитевский. Но спустя пару дней раздумий четко решил, что мой для меня лучше.
    1) Удобное перетаскивание картинок мышкой сразу в окно.
    2) Удобное позиционирование клавиатурой.
    3) Удобное управление текстами, в юнити относительно удобно работать с текстами только через канвас. Но канвас медленный и я по возможности его избегаю. Кодом же можно более быстрый mesh текст использовать.
    4) Удобная генерация кода сцен на основе всего этого, к тому же и элементами генерированными кодом потом легче и удобней управлять.
    5) В разы более удобная работа с типовыми сложными элементами типа зоны скролинга или прогресбара.
    6) Разделение на сцены, и удобный механизм их управления. Сцены которые есть в юнити имеют очень мало общего с моим разделением на сцены. Мои сцены скорее ближе к группам в юнити.
    7) Максимальная гибкость и возможность писать что хочу и работать так, как удобней мне, а не так, как считают удобным авторы юнити.

    С другой стороны, если бы у меня не было системы и я начал работать на юнити, то микрофреймворк я бы наверное слепил, но полноценную систему вряд ли стал бы.

  18. Про расширение я так до конца и не понял.
    Я все равно считаю, что графичесский процессор будет пересчитывать все.
    Но ок, разработка велась в 854х480
    К квадратам потом применялось растягивание до 240х240. (50% высоты, я писал об этом в условии)

  19. «Элспер, можешь посмотреть, может в Юнити есть такая фишка и если отключить плавное обновление, fps повысится?»
    Попробуй отключить вертикальную синхронизацию. Edit — Project Settings — Quality — V Sync Count (Don’t Sync)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Спoнcopcкиe ссылки