пятница, 24 мая 2013 г.

Так, ни о чем

один файл, а внутри: два энама, три класса, две руками написанные стейт-машины, 400 строк кода. Здравствуй, быдлокод:


вторник, 14 мая 2013 г.

Some materials from knowledge sharing seminar



Two months ago we started our unity knowledge sharing seminars. I forgot to share materials I promised to, so let me do it here.


2D UI - NGUI (Presentation on russian)


2D in Unity3D from Рустам Ганеев

Useful links:


Unity shaders (Presentation on russian)


Useful links:

UPD: Dustin Lee, the Unity evangelist kindly shared awesome slides about shaders, just check it out:

среда, 17 апреля 2013 г.

Dynamic texts in ngui

The only problem I have to deal with 2D UI in NGUI plugin is text fonts. In details, there's a bunch of problems:

  • Dynamic font support (UPD: from NGUI 2.5 dynamic fonts are supported out-of-box)
  • Localization(arabic, hebrew languages, chinese etc).
  • Input texts
As I'm working on localization in deep, I found some useful things to solve problems described above:
  • for dynamic font, use https://github.com/imkira/unity-sysfont. It seems to be out-of-date (it hasn't been updated for 9 months), but it works and you need just to tweak it for youself. Maybe I'll finish it in holidays.
  • for chinese, japanese dynamic fonts works ok, use plugin above. If you intent to support arabic languages,  use http://u3d.as/content/abdullah-konash/unity-arabic-support/2B8. This asset allows you to write in rtl mode. Now I'm looking for hebrew plugin, or if I find someone who can read hebrew, I'll write it for myself. 
  • Situation about input text is troublesome. Changing uiinput component will cause problems with supporting and I don't like to do it. But there's no other way to cope with it.

суббота, 6 апреля 2013 г.

Кто виноват и что делать?

Не знаю почему, но когда появляется проблема, мы задаем два исконно русских вопроса именно в таком порядке:

  • кто виноват?
  • что делать?
А теперь маленький лайфхак - инвертируем порядок. То есть сначала думаем, что делать, как решить вопрос, а потом уже ищем виноватых, если в этом осталась какая-либо нужда.

P.S. Мысль вроде как и капитанская, но, если применять в жизни, получается очень эффективно, намного эффективней первого способа. 

пятница, 5 апреля 2013 г.

//TODO, //HACK, FIXME

В мире спортивного программирования всегда все просто: у тебя всегда валидные данные, обо всем позаботились организаторы. В промышленных масштабах это далеко не так: по закону Мерфи если что-то может пойти не так, так обязательно и будет. Поэтому ты тупо пишешь кучу проверок на случай ядерной войны. Или не пишешь. Оставляешь //TODO: check c надеждой на то, что когда будет скучно и не захочется ничего делать, будешь писать эти глупые проверки.

Сегодня запустили игру, она падает на уровне. Смотрим, где падает: null-reference exception. Смотрим код:
public void DoAction(Transform t) {
 //todo check before setting
 t.localPosition = foo;
 t.localRotation = bar;
 t.localScale = foobar;
}

Падало как раз при присвоении, потому что t - null. Как говорится, без комментариев. Хотя есть один: "//TODO:" существует не для того, что его оставляли и забывали, а для того, чтобы это фиксили и делали это как можно быстрее. И для //HACK, //FIXME инженерный закон "работает - не трогай" не катит - это просто бомба замедленного действия, который когда-нибудь рванет в совсем неожиданное время и неожиданном месте(ну, к примеру, во время презентации или, не дай Бог, релиза).

пятница, 29 марта 2013 г.

Оптимизация Unity на мобильниках(3D графика)

update: (practical "hacks" -  http://rustam-kot.blogspot.ru/2013/09/optimize-performance-in-unity3d.html)

В последний месяц только и занимаюсь тем, что провожу предельную оптимизацию и глобальный рефакторинг. Поэтому начинаю описывать типичные техники, которые использую каждый день, в стиле маленьких советов. Все нижесказанное опробовано на собственном опыте и могут быть в корне неверны, поэтому если кто хочет обсудить что-либо, оспорить - you're welcome! А кто после прочтения поста не понял, почему его FPS шутер превратился в пошаговую стратегию - тот артист :)

Итак, у нас есть готовая рабочая версия игры, но она безбожно тормозит. Какие телодвижения в каком порядке произвести, чтобы выиграть процессорное и графическое время:

  1. В ПЕРВУЮ ОЧЕРЕДЬ юзаем профайлер. Даже если знаешь, где можно сделать быстрее, к примеру, уменьшить асимптотику у какой-нибудь структуры, все равно смотреть профайлер. Часто думаешь, что тормозит по одной причине, а на самом деле вылезает совершенно левый оверхед.
  2. Лидеры тормозов:
    • отрисовка - 70%
    • расчет физики - 20%
    • скрипты - 10%.
    И это совершенно понятно: графические карты на мобильниках слабы и весь боттлнек складывается именно в отрисовке. Поэтому дальнейшие оптимизации будут касаться в основном графики.
  3. Первый признак того, что все плохо: много draw-call-ов(далее dc). Немного теории: рисованием чего-либо занимается компонент Renderer(и различные его вариации: MeshRenderer, SkinnedMeshRenderer, ParticleRenderer, LineRenderer, etc), который принимает на вход материал с заданными параметрами(шейдер, текстура и т.д.) и отрисовывает. Видеокарта для каждого материала делает отдельный проход рисования, что и является dc. Ну так вот, чем больше материалов на сцене, тем больше страдает видеокарточка девайса-> тем больше страдает пользователь -> тем больше единичек в app store.
  4. А еще есть такая вещь, как batching, смысл его заключается в том, что несколько объектов, использующих один и тот же материал отрисуются за один проход. То есть, к примеру,  выгодней делать двадцать однотипных домов, как в Набережных Челнах, чем 4 дома как в центре Санкт-Петербурга, потому что двадцать однотипных домов отрисуется за один проход. Поэтому везде, где возможно, используем один и тот же материал.
  5. У батчинга есть проблемы:
    • если у двух объектов разный scale - батчинг не работает. Возможные пути решения:
      •  менять размер mesh-a, а не объекта, если это meshrenderer(к примеру, так делается в NGUI ).
      • строго следить за однотипными объектами и бить по рукам любого, кто не любит стандартные числа.
    • если объекты принимают тень в реалтайме(читай: не лайтмапятся) - батчинг не работает. 
    • если меш очень сложный(больше 900 вершин для тупо вершин, 300 вершин для uv, 180 вершин для uv1, uv2), то батчинг не работает. 
    • если объекты используют один и тот же материал, но у одного материала какое-нибудь свойство отличается - unity создает новый инстанс материала - тут разные материалы - не может быть и речи о батчинге
    • если шейдер использует более одного прохода - батчинг не работает. 
  6. На тему материалов: используем мобильные шейдера вместо обычных. Обычные шейдера используем только тогда, когда реально приспичит. Сегодня как раз столкнулись с веселой ситуацией: есть 50 совершенно одинаковых объектов(различаются только позицией и поворотом), они все помечены батчиться статически, при этом в игре с ними получается +50 dc. Начали искать, где проблема. Случайно решили вместо diffuse шейдера поставить mobile/diffuse - объекты забатчились. Вообще, юнитеки божатся, что мобильные шейдеры в десятки-сотни, а в некоторых случаях и тысячи раз быстрее десктопных.
  7. Потолок dc(буду судить только по ios, в android-е там совсем зоопарк):
    • iphone 3gs, ipod 4: 70 dc
    • iphone 4: 90 dc 
    • iphone 4s: 200 dc
    Тут еще несколько замечаний: 3gs парится больше относительно количества полигонов, для 4 айфона больше важно количество dc. 
  8. Оптимизировать количество материалов можно благодаря использованию текстурных атласов. Смысл очень прост: много картинок засовываем в одну большую, рендерерам говорим использовать определенные участки карты и видеокарта может отрисовывать это все в один проход. Я просто оставлю это здесь: http://www.digitalopus.ca/site/mesh-baker/, http://www.codeandweb.com/texturepacker.
  9. С атласами не все может быть так круто: четыре атласа 2048x2048, но загружаемые и разгружаемые в памяти лучше, чем один атлас 4096x4096. Пока хотя бы один материал использует  текстуру, видеокарта держит текстуру в памяти.
  10. Теперь придем к отрисовке текстур: используем сжатие на 146%. PVRTC для ios, ETC/DXT для android, mip-map-ы обязательно и тогда есть вероятность, что  видеокарточка не повесится, а скажет вам спасибо.
  11. 2D - это отдельная тема.
  12. Instantiate/Destroy объектов дорого не только для CPU, видеокарта тоже обязана загружать/освобождать ресурсы. Не заставляйте ее делать слишком часто, используйте  паттерн object pool.
  13. Ну и самая противная кнопка, подставленная на твой стул - это отрисовка где-нибудь в Update/FixedUpdate. На примере: вот так чуваки обновляют визуальный компонент подсчета очков:
    private void Update(){
      pointsMesh.text = Model.points.ToString();
    }
    
    Для далеких из мира Unity3d: Update вызывается каждый кадр! Вместо того, чтобы просто обновить один раз вьюшку, когда модель обновится, мы устраиваем маленький ddos мобильника. И вообще, нужно минимизировать количество Update/FixedUpdate и переходить к event-логике, а еще лучше к конечным автоматам.
  14. Да, совсем забыл про свет: везде, где возможно, заранее запекаем свет, предпосчитываем тени. Если тени не принципиальны(например, 2D графика), то убираем по возможности везде, где только возможно. Производительность увеличивается прямо на глазах!
Про графику вроде все. Вспомню, напишу еще. На следующей неделе напишу некоторые советы по оптимизации скриптовой части.

Вот что можно почитать у юнитеков на эту тему:

понедельник, 25 марта 2013 г.

Особенности национальной верстки или привет зоопарк устройств

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

Итак, как нарезать дизайнерам, а также как это вставить программистам, чтобы на всех девайсах все выглядело одинаково. Но сначала предупреждение:

  • (дизайнерам) Забудьте о pixel-perfect верстке. Ее не будет. Но именно благодаря этому на всех экранах все будет выглядеть одинаково.
  • (программистам) Свыкнитесь, что будут грязные хаки. Это вначале все будет идти гладко да хорошо, а потом вдруг запустишь аpk на 320x240 и удивляешься, что все друг на друга наплыло.
А теперь описание процесса, как мы достигаем вселенского счастья:
  • Есть UI (кнопки, слайдеры, менюшки), а есть бэкграунд(бэк). Ну так вот, бэк - это просто картинка(чаще всего однородная) на заднем фоне. Она нужна для того, чтобы по бокам не было черных фонов.
  • Мы делаем картинку бэка максимально большим и широким, а потом на каждом девайсе скейлим вниз пропорционально по высоте. К примеру, у нас бэк размером 2764 x1536.  На айфоне 5 отрисуется центральные 2726x640 пикселей. Таким образом, получается, что на самом деле наш бэк будет выходить за границы отрисовки. Скейл вверх нежелателен, но если есть ограничение по памяти, то тут никуда не денешься - никто не даст тебе рисовать картинки 4096x4096.
  • Бэк центрируется. Ваш кэп.
  • В нарезке UI сюрпризов нет, нарезаем по обычному.
  • При верстке UI абсолютно все располагаем относительно UIAnchor-ов. Каждый элемент экрана должен принадлежать к какой-то отдельной части. Да, на каждый чих индивидуального пространства создаем отдельный якорь. Типично используемых якорей хотя не так уж и много: центр, левый верхний угол, правый верхний угол, нижние углы по краям, верх и низ. Остальные используются редко.
Да, еще одно ограничение: надо уложиться в 50МБ выходного файла. Это было интро, а теперь требования и настоятельные рекомендации:
  • (дизайнерам) Размеры бэкграундов: 1460x768(HD), 1090x460(SD).
  • (дизайнерам) Верстка под экраны: 1024x768(HD), 2048x1536(если совсем не жалко памяти). 
  • (дизайнерам) Формат картинок: png
  • (дизайнерам) По максимуму избегать альфы (особенность unity - чем больше площадь наложения альф, тем сильнее просаживается fps)
  • (дизайнерам) По максимуму избегать градиента (из-за проблем со скейлом)
  • (дизайнерам) По возможности, используем nine-patch везде, где только можно.
  • (дизайнерам) Шрифты в растровом формате. Более подробно: на ютубе
  • (программистам) UI элементы пакуем в одну текстуру с помощью NGUI, бэки оставляем как отдельные картинки(преимущество от запаковки бэков теряется при огромном размере атласа).
  • (программистам) Сжатие текстур: PVRTC для ios, ETC/DXT(1/5) для android.
  • (программистам) Атласы имеют размеры 2^N
  • (программистам) Все используемые картинки - квадратные.
Может быть, что-то забыл. Что забыл, напишу позже.