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
https://www.youtube.com/watch?v=RtR4E0z5Sys
При этом музыканты - это все люди из нашей компании.
А вы делали что-нибудь подобное в своих студиях или проектах?
Делитесь ссылками в комментах!
#clip #video #soundtrack #mushroomwars2
YouTube
Main Theme - Rock Edition by the Devs Band | Mushroom Wars 2
Watch the music clip of the main theme of Mushroom Wars 2 recorded by the developers rock band and real Rudo himself!
Download Mushroom Wars 2: https://mushroomwars2.onelink.me/nx8n/a1716zke
Discord https://discord.gg/mw
Facebook https://www.facebook.co…
Download Mushroom Wars 2: https://mushroomwars2.onelink.me/nx8n/a1716zke
Discord https://discord.gg/mw
Facebook https://www.facebook.co…
🔥27❤2🥰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
На самом деле выходит очень даже неплохо и я обязательно поделюсь результатом, когда проект выйдет в релиз (будет софт).
#release #newproject #news
👍51🔥10🫡5❤2👾2
Texture2DArray
Недавно столкнулся с проблемой, что у нас в проекте перестали влезать все юниты в один атлас, а нам прям надо, чтобы все юниты рисовались в один проход. Тут я вспомнил, что была такая древняя штука как Texture2DArray. Принцип простой: по сути у вас вместо 2д текстуры, она становится 3д, в шейдере нужны минимальные изменения для поддержки этого.
На практике же всплыло 2 проблемы:
1. Слои должны быть одного размера, т.е. нельзя сделать один слой 2к, а другой - 1к;
2. Эта штука не работает на андроиде.
Если первую проблему решить довольно просто, переписав пакер, то вот со второй проблемой никакого решения собственно и нет.
Пришлось уходить от массивов в сторону кучи сэмплеров, благо нам нужно по требованиям рисовать не так много атласов.
#shaders #texture2darray #android
Недавно столкнулся с проблемой, что у нас в проекте перестали влезать все юниты в один атлас, а нам прям надо, чтобы все юниты рисовались в один проход. Тут я вспомнил, что была такая древняя штука как Texture2DArray. Принцип простой: по сути у вас вместо 2д текстуры, она становится 3д, в шейдере нужны минимальные изменения для поддержки этого.
На практике же всплыло 2 проблемы:
1. Слои должны быть одного размера, т.е. нельзя сделать один слой 2к, а другой - 1к;
2. Эта штука не работает на андроиде.
Если первую проблему решить довольно просто, переписав пакер, то вот со второй проблемой никакого решения собственно и нет.
Пришлось уходить от массивов в сторону кучи сэмплеров, благо нам нужно по требованиям рисовать не так много атласов.
#shaders #texture2darray #android
🔥8👍5🤯2
Есть такой мемчик, где люди делятся на 2 типа и вот это все. Ну там где у человека выключено отображение ворнингов и там где включено.
Я отношусь к тем, у кого они включены и вообще не люблю когда в логах мусор.
Так вот, в шарпе есть такая штука:
Она позволяет включать и выключать либо все ворнинги, либо конкретные, если указано какие конкретно нужно отключить.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#pragma-warning
Вообще я предпочитаю исправлять предупреждения, а не использовать эти директивы, но тем не менее иногда без этого никуда.
Поддерживайте ваш код в чистоте и без лишних логов и предупреждений.
#logs #pragma #warnings
Я отношусь к тем, у кого они включены и вообще не люблю когда в логах мусор.
Так вот, в шарпе есть такая штука:
#pragma warning disable
#pragma warning restoreОна позволяет включать и выключать либо все ворнинги, либо конкретные, если указано какие конкретно нужно отключить.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#pragma-warning
Вообще я предпочитаю исправлять предупреждения, а не использовать эти директивы, но тем не менее иногда без этого никуда.
Поддерживайте ваш код в чистоте и без лишних логов и предупреждений.
#logs #pragma #warnings
Docs
Preprocessor directives - C# reference
Learn the different C# preprocessor directives that control conditional compilation, warnings, nullable analysis, and more
🔥15👍11😐3🤡1
Array.EmptyИспользуйте вместо new T[0]; статичный массив, который не нужно создавать каждый раз.
#lifehack #optimization #basics
👍24😐8🔥3🗿2
ВОПРОСЫ
Тут можно задать вопрос или предложить тему для поста.
Старайтесь не разводить подтемы, чтобы это было удобнее читать и можно было найти.
Я закреплю это сообщение.
#questions
Тут можно задать вопрос или предложить тему для поста.
Старайтесь не разводить подтемы, чтобы это было удобнее читать и можно было найти.
Я закреплю это сообщение.
#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
Вообще я уже писал немного про это раньше, но решил расписать более подробно про каждый сэмплер, чтобы было понятно где искать проблему.
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🔥14❤1😐1
Fluent-interface
Вы, наверное, слышали и встречали такую штуку, а некоторые даже писали.
По своему определению текучие интерфейсы представляют из себя набор методов, где каждый метод добавляет или удаляет какое-то свойство, то есть меняет инстанс.
В принципе я с этим не совсем согласен. Я считаю, что такие методы должны ставить флаги (или просто записывать входные параметры), то есть не должны выполнять работу прямо в месте вызова.
Как?
Ну это довольно просто:
Меняем на
Где T может быть текущим типом, может быть интерфейсом (как в оригинале было и задумано, но структуры все портят).
Где?
Я использую такое в API своих ME.ECS/BECS для сборки фильтров и запросов.
Вне ecs я передаю настройки в виде структуры, которую я собираю как раз через такой подход. Ну и твинер у нас написан с таким же походом.
Зачем?
Лаконичность кода и легкость восприятия.
Пишите в комментах где вы используете fluent-interface подход.
#architecture #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:
Т.е. мы никогда не вызываем этот метод, но при сборке эти методы будут добавлены.
Вообще это касается всех вызовов через reflection и когда в проекте не указывается вызов.
#aot #il2cpp #error
Совсем недавно ко мне обратился коллега с просьбой помочь с ошибкой, когда 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. Изменение стрингов без переаллокации
И много всякого другого.
@alexmtq создал канал про оптимизации и unsafe приколдэсы на шарпе и в дотнете.
Сейчас пилю либу для унификации ансефа по всем рантаймам. Будет работать как в Mono/IL2CPP, так и в настоящем дотнете, т.е когда юнитеки завезут .NET Core всё продолжит работать.
Основные фичи:
1. вызов методов без .Invoke (т.е без аллокаций), вызов нативных методов без обёртки через нэйтив.
2, Изменение длины и типа массивов — это полезно для бинарной сериализации, рентерпретации данных без дополнительных аллокаций итд
3. Изменение типа размера листов + thread-safe способ для добавления элементов, в том числе через Burst, без дополнительной аллокации NativeList<T>
4. Изменение стрингов без переаллокации
И много всякого другого.
Telegram
MadSharp: Unsafe
The channel is all about unobvious C#/Unity hacks and optimizations.
Blog: meetemq.com
Blog: meetemq.com
👍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 не поддерживается.
Однако, как показали тесты, семантика
Автор: @shiko_q
Источник: https://news.1rj.ru/str/unity_cg/48214
#rendering #graphics
Начну чуть издалека.
Что есть дроуколл?
Это запуск 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🗿4❤1👍1🤩1
Давно у нас не было никаких событий, надо исправляться 🙂
В эту субботу (c 16:00 по мск) пройдет событие на тему ME.BECS, я расскажу как она устроена, отвечу на ваши вопросы.
Регайтесь по ссылке:
https://unsafecsharp.timepad.ru/event/2583150/
#event #ecs
В эту субботу (c 16:00 по мск) пройдет событие на тему ME.BECS, я расскажу как она устроена, отвечу на ваши вопросы.
Регайтесь по ссылке:
https://unsafecsharp.timepad.ru/event/2583150/
#event #ecs
🔥23👍2
Параметры метода (params)
Есть такая штука, которая позволяет вызывать метод, когда мы не знаем сколько параметров хотим туда передать:
Но есть некоторые особенности, которые нужно понимать:
1. По-умолчанию такой вызов создает новый массив (т.е. триггерит GC, что плохо):
2. Если мы передадим точный тип массива, то это не будет создавать новый массив:
3. Любой вызов будет создавать новый массив:
Вывод: избегайте методов с params, особенно если это хот часть.
#gc #performance #params #basics
Есть такая штука, которая позволяет вызывать метод, когда мы не знаем сколько параметров хотим туда передать:
void Method(params object[] arr)
Но есть некоторые особенности, которые нужно понимать:
1. По-умолчанию такой вызов создает новый массив (т.е. триггерит GC, что плохо):
void Method1(params object[] arr)
void Method2(object[] arr)
var arr = new int[10];
Method1(arr); // будет создан массив object[1] и к первому элементу присвоен массив arr
Method2(arr); // будет ошибка компиляции, т.к. object[] не соотвествует типу int[]
2. Если мы передадим точный тип массива, то это не будет создавать новый массив:
void Method1(params int[] arr)
void Method2(int[] arr)
var arr = new int[10];
Method1(arr);
Method2(arr);
// Эти 2 вызова идентичны
3. Любой вызов будет создавать новый массив:
void Method(params int[] arr)
Method(1, 2, 3)
Method(1)
Вывод: избегайте методов с params, особенно если это хот часть.
#gc #performance #params #basics
👍17🤡4🔥1
Напоминаю, что сегодня будем разбирать ME.BECS. Кто еще не зарегался - велкам:
https://news.1rj.ru/str/unsafecsharp/187
#event
https://news.1rj.ru/str/unsafecsharp/187
#event
Telegram
Unity: Всё, что вы не знали о разработке
Давно у нас не было никаких событий, надо исправляться 🙂
В эту субботу (c 16:00 по мск) пройдет событие на тему ME.BECS, я расскажу как она устроена, отвечу на ваши вопросы.
Регайтесь по ссылке:
https://unsafecsharp.timepad.ru/event/2583150/
#event #ecs
В эту субботу (c 16:00 по мск) пройдет событие на тему ME.BECS, я расскажу как она устроена, отвечу на ваши вопросы.
Регайтесь по ссылке:
https://unsafecsharp.timepad.ru/event/2583150/
#event #ecs
🔥12😐1🍓1