Unity: Всё, что вы не знали о разработке – Telegram
Unity: Всё, что вы не знали о разработке
1.74K subscribers
40 photos
101 links
Авторский канал о разработке в Unity от Alex Silaev (CTO в Zillion Whales). Mushroom Wars 2 моих рук дело.
Рассказываю об интересный кейсах, делюсь лайфхаками, решениями.
Download Telegram
Extension и Receive

У меня все;)

#misspelling
😁8🤣2
this или не this - вот в чем вопрос.

Немного о себе 🙂
Я начал программировать лет в 10, а зарабатывать на этом в 14. С тех пор прошло уже больше 20 лет, мне будет уже 36 (ох, какой же я старый стал).

Начинал я с pascal в школе, там были ассемблерные вставки и я познакомился с man. Потом перешел на visual basic, на котором делал всякие интересные штуки, познакомился с winapi. С приятелем в школе нашли dark basic и стали на нем писать какую-то фигню, но дело быстро свернулось, в основном из-за непонимания происходящего и что такое update loop, в visual basic такого не было 🙂
Потом в универе занимался плюсами, года 4 на них потратил.

В последние годы универа увлекся php, настолько, что в итоге первая фултайм работа была связана именно с этим. Помимо php ессно я занимался разными бд, full-text-search движками и прочими штуками, т.к. без этого стека выжить было нереально.

Потом решил, что бэк - это уже не так интересно, в софт идти совсем не хотелось, а игры я тогда вообще не понимал как делаются (хотя под directx еще на vb писал какие-то штуки), поэтому пошел в понятную область - в js. Пытался рендер делать на js, но с приходом первого html5 - перестал пытаться.

И вот тут, как не сложно догадаться, я все же решился пойти в игры. Не буду описывать подробности этого непростого периода, но в итоге я нашел Unity (хотя даже тогда выбор был из нескольких движков, в том числе и UE). В Unity меня привлекли мобилки (хотя что я тогда о них знал, недавно только вышел iphone 3G) и самое главное - js. Да, я быстро понял, что это никакой не js, а скорее нечто среднее между js и action noscript, но Unity уже была скачана, первый видос на ютубе посмотрен, где человек упроно называл сцену "скин" (как сейчас помню), так что куда деваться - надо писать свою ММОРПГ (шучу, терпеть их не могу, если честно). Конечно же я начал делать свою RTS 🙂

Ну так вот. К чему я это все. Я писал this, пишу this и буду писать this.

#story #life #this
🔥36👍9🌚5👏3❤‍🔥2👨‍💻2👎1🥰1
Триангулятор

Нам часто нужно из точек сделать меш, чтобы потом отрисовать его.
Для этой цели нужно использовать алгоритм триангуляции (например, вот этот ). Вообще реализаций полно, так что не думаю что с этим будут проблемы.

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

#triangulator #math #mesh
👍6🔥2👌2🥱2
Texture2D.GenerateAtlas

Я уже писал про PackTextures, но эта штука ломается, если невозможно запаковать текстуры, т.к. их размер превышает максимальный размер атласа. Для этого можно использовать GenerateAtlas, т.к. этот метод ничего не делает с текстурами, а только работает с ректами и возвращает true, если все объекты поместятся в атлас. То есть можно сначала вызвать его, а потом использовать PackTextures, либо запаковать самостоятельно, используя SetPixels.

#api #code #unity
🔥15👍3
Instantiate<T>()

Я часто встречаю в коде вот такой вариант:

var instance = Instantiate(prefabGo);
instance.GetComponent<MyComponent>();

Дело в том, что можно использовать такой вариант:

var instance = Instantiate(prefabMyComponent);

Который сразу вернет нам ссылку на инстанс нашего объекта.

#lifehack #basics #instantiate #code
🥱67👍18🔥6🥴5🌚1💯1
Год назад мы решили записать нашу главную тему игры в виде простого клипа:
https://www.youtube.com/watch?v=RtR4E0z5Sys
При этом музыканты - это все люди из нашей компании.

А вы делали что-нибудь подобное в своих студиях или проектах?
Делитесь ссылками в комментах!

#clip #video #soundtrack #mushroomwars2
🔥272🥰1
Для каких платформ вы делаете проект?
Anonymous Poll
41%
PC/Steam
54%
iOS
77%
Android
5%
Switch
6%
PS
6%
XBOX
16%
Другие
👍4🥰2🤨2🍓2
Может показаться, что я забыл (или забил) делать посты для канала, но на самом деле - нет, у нас просто релиз в этом месяце, а вы знаете как это запарно, ведь нужно успеть сделать 90% проекта за последние 2 недели.
На самом деле выходит очень даже неплохо и я обязательно поделюсь результатом, когда проект выйдет в релиз (будет софт).

#release #newproject #news
👍51🔥10🫡52👾2
Texture2DArray

Недавно столкнулся с проблемой, что у нас в проекте перестали влезать все юниты в один атлас, а нам прям надо, чтобы все юниты рисовались в один проход. Тут я вспомнил, что была такая древняя штука как Texture2DArray. Принцип простой: по сути у вас вместо 2д текстуры, она становится 3д, в шейдере нужны минимальные изменения для поддержки этого.

На практике же всплыло 2 проблемы:
1. Слои должны быть одного размера, т.е. нельзя сделать один слой 2к, а другой - 1к;
2. Эта штука не работает на андроиде.

Если первую проблему решить довольно просто, переписав пакер, то вот со второй проблемой никакого решения собственно и нет.
Пришлось уходить от массивов в сторону кучи сэмплеров, благо нам нужно по требованиям рисовать не так много атласов.

#shaders #texture2darray #android
🔥8👍5🤯2
Есть такой мемчик, где люди делятся на 2 типа и вот это все. Ну там где у человека выключено отображение ворнингов и там где включено.
Я отношусь к тем, у кого они включены и вообще не люблю когда в логах мусор.

Так вот, в шарпе есть такая штука:

#pragma warning disable
#pragma warning restore


Она позволяет включать и выключать либо все ворнинги, либо конкретные, если указано какие конкретно нужно отключить.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#pragma-warning

Вообще я предпочитаю исправлять предупреждения, а не использовать эти директивы, но тем не менее иногда без этого никуда.

Поддерживайте ваш код в чистоте и без лишних логов и предупреждений.

#logs #pragma #warnings
🔥15👍11😐3🤡1
В редакторе можно писать простые выражения в поля для чисел:
Например, чтобы сдвинуть объект, который находится в x=10, на 100 юнитов вправо, нужно написать 10+100 и нажать enter.

#editor #basics #formula
👍25🤡6🤯5🥴5🍓3
Array.Empty

Используйте вместо new T[0]; статичный массив, который не нужно создавать каждый раз.

#lifehack #optimization #basics
👍24😐8🔥3🗿2
ВОПРОСЫ

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

#questions
🔥7
memcmp

С помощью такой простой штуки можно определить насколько совпадают структуры между собой.
На практике такое я применяю для определения равны ли структуры (функция вернет 0) или же отличаются (функция вернет значение больше или меньше нуля, что покажет какая из структур "меньше").

#unsafe #memcmp
🔥14🤯5
Разбираемся с профайлером

Вообще я уже писал немного про это раньше, но решил расписать более подробно про каждый сэмплер, чтобы было понятно где искать проблему.

WaitForTargetFPS: Время, потраченное на ожидание целевого значения FPS, указанного в Application.targetFrameRate. Редактор не использует VSync на GPU, а вместо этого использует WaitForTargetFPS для имитации задержки VSync.

Gfx.ProcessCommands: Поток рендеринга охватывает всю обработку команд рендеринга. Часть этого времени может быть потрачена на ожидание VSync или новых команд из основного потока, что можно увидеть в Gfx.WaitForPresent.

Gfx.WaitForCommands: Поток рендеринга готов к новым командам, и может указывать на узкое место в основном потоке.

Gfx.PresentFrame: Поток рендеринга представляет собой время, затраченное на ожидание рендеринга и представления кадра графическим процессором, что может включать ожидание VSync.

Gfx.WaitForPresent: Когда основной поток готов начать рендеринг следующего кадра, но поток рендеринга еще не завершил ожидание представления кадра GPU. Это может указывать на то, что узкое место в GPU. Посмотрите на представление временной шкалы, чтобы узнать, проводит ли поток рендеринга одновременно время в Gfx.PresentFrame. Если поток рендеринга все еще проводит время в Camera.Render, узкое место в CPU, т.е. тратит слишком много времени на отправку вызовов отрисовки/текстур на GPU.

#profiler #profiling #performance #gpu #cpu
👍37🔥141😐1
Fluent-interface

Вы, наверное, слышали и встречали такую штуку, а некоторые даже писали.

instance.Method1().Method2()

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

Как?
Ну это довольно просто:
void Method() {…}
Меняем на
T Method() { return this; }
Где T может быть текущим типом, может быть интерфейсом (как в оригинале было и задумано, но структуры все портят).

Где?
Я использую такое в API своих ME.ECS/BECS для сборки фильтров и запросов.
Вне ecs я передаю настройки в виде структуры, которую я собираю как раз через такой подход. Ну и твинер у нас написан с таким же походом.

Зачем?
Лаконичность кода и легкость восприятия.

Пишите в комментах где вы используете fluent-interface подход.

#architecture #fluent #interface
👍6🔥5🥴4🐳2🤡1
AOT статик методы для компиляции

Совсем недавно ко мне обратился коллега с просьбой помочь с ошибкой, когда json не мог распаковаться и падал с ошибкой примерно такой по смыслу:
"Не могу найти конструктор с передаваемыми параметрами", а стек показывает, что где-то там через рефлексию создается инстанс (через Activator) и при вызове конструктора чет все падает.

И тут знаете, как в шуточках за 300, люди делятся на несколько групп:
1. Неопытные с ужасом идут гуглить ошибку, ничего не находят, идут дергать вторую группу;
2. Более опытные понимают, что тут как-то не очень все тривиально, идут в место где рефлексией создается какой-то объект и пытаются понять как же можно было накосячить создателям плагина, что оно не работает;
3. Ну и такие как мы с вами, которые в принципе уже понимают, что билд скорее всего il2cpp, что рефлексия - это плохо, что il2cpp ничего об этом знать не знает, а значит проблема просто в том, что метода нет после компиляции.

К чему я это все. Для исправления подобных ситуаций, il2cpp нужно "подсказать", что существует метод (или конструктор), для чего я обычно делаю в проекте файл AOT.cs:


public static class AOT {
[Preserve]
public static void Dummy() {
new SomeClass().Method(); // не вырезаем конструктор и метод из билда
...
}
}


Т.е. мы никогда не вызываем этот метод, но при сборке эти методы будут добавлены.
Вообще это касается всех вызовов через reflection и когда в проекте не указывается вызов.

#aot #il2cpp #error
🔥38👍9
https://news.1rj.ru/str/madcsharp

@alexmtq создал канал про оптимизации и unsafe приколдэсы на шарпе и в дотнете.
Сейчас пилю либу для унификации ансефа по всем рантаймам. Будет работать как в Mono/IL2CPP, так и в настоящем дотнете, т.е когда юнитеки завезут .NET Core всё продолжит работать.
Основные фичи:
1. вызов методов без .Invoke (т.е без аллокаций), вызов нативных методов без обёртки через нэйтив.
2, Изменение длины и типа массивов — это полезно для бинарной сериализации, рентерпретации данных без дополнительных аллокаций итд
3. Изменение типа размера листов + thread-safe способ для добавления элементов, в том числе через Burst, без дополнительной аллокации NativeList<T>
4. Изменение стрингов без переаллокации
И много всякого другого.
👍20🙈4
В Unity есть возможность Indirect рендеринга: Graphics.RenderMeshIndirect

Начну чуть издалека.

Что есть дроуколл?

Это запуск GPU пайплайна по неким параметрам.
Вот вспомните ту самую картинку, которую вы видели:
вертексный шейдер -> геометрический -> .... -> фрагментный

Для дроуколла надо выставить эти параметры:
-переключатели на гпу для НЕпрограммируемых stages
-программы для программируемых
-забиндить буферы и прочие ресурсы

Основные буферы - это вертексный (позиции) и индексный (индексы вертексов).

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

Что есть инстансинг?

это когда мы не делаем новые дроуколлы, а просто перезапускаем пайплайн X раз в рамках одного дк.
Для каждого перезапуска пайплайна мы просто меняем SV_InstanceID (видеокарта сама его меняет) - SV_InstanceID от 0 до X.
Мы не перебиндиваем ничего и не ждём команд от цпу - поэтому инстансинг очень быстрый.

Что есть индирект?

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

Но в рамках одного вызова, даже вызова индирект - мы не можем забиндить разные индексные оффсеты.

(p.s. схожим образом, кстати, работают Task и Mesh шейдера)

Что есть MDI?

Это когда гпу может сама решить сколько вызовов indirect ей нужно.
И не только запустить несколько вызовов пайплайна, но и индексные оффсеты сопоставить на разных вызовах самостоятельно.
Для этого гпу помимо номера инстанса - SV_InstanceID знает и номер текущей отрисовки.

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

Метод Graphics.RenderMeshIndirect позволяет рисовать MDI там где это поддерживается и делает серию обычных Indirect вызовов там, где MDI не поддерживается.
Однако, как показали тесты, семантика SV_DrawID поддерживается не везде =(

Автор: @shiko_q
Источник: https://news.1rj.ru/str/unity_cg/48214

#rendering #graphics
🔥28🗿41👍1🤩1