This media is not supported in your browser
VIEW IN TELEGRAM
Обещанное видео) Конечно тут кубики, с разными цветами, обозначающие уровень детализации 🤷
С LOD оказалось все чуть сложнее, чем я думала. Но все же победа вот-вот будет за мной! Осталось откинуть те кубики, которые слишком далеко от камеры👏
С LOD оказалось все чуть сложнее, чем я думала. Но все же победа вот-вот будет за мной! Осталось откинуть те кубики, которые слишком далеко от камеры
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍3
This media is not supported in your browser
VIEW IN TELEGRAM
А вот теперь есть и поддержка "пустых" лодов, которые не рендерят ничего 💃
Стоит заметить, что LOD выбирается не просто по дистанции до камеры, а по эвристике, определяющей, сколько объект занимает в процентном соотношении места на экране! Это позволяет более точно выбирать LOD и рисовать только то, что реально видно и имеет шанс быть замеченным (поэтому маленькие объекты даже в близи могут быть еще скрыты, тогда как большие - уже рисоваться).
Следующий шаг - добавление cross fade, чтобы лоды плавно смешивались.
Стоит заметить, что LOD выбирается не просто по дистанции до камеры, а по эвристике, определяющей, сколько объект занимает в процентном соотношении места на экране! Это позволяет более точно выбирать LOD и рисовать только то, что реально видно и имеет шанс быть замеченным (поэтому маленькие объекты даже в близи могут быть еще скрыты, тогда как большие - уже рисоваться).
Следующий шаг - добавление cross fade, чтобы лоды плавно смешивались.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19❤3
Хочу немного рассказать, как я выбираю LOD. Это не очень сложно на самом деле, как бы не звучало в моем предыдущем посте 🤭
Самый простой способ выбирать LOD - зная позицию камеры и для каждого инстанса матрицу трансформации, можно взять дистанцию между ними. Потом сравнить дистанцию с теми значениями диапазонов, которые мы указали в редакторе. Получается линейная выборка, которая никак не учитывает размер объекта.
А размер объекта на самом деле очень важен. Цель LOD - уменьшить не только кол-во треугольников, но и кол-во инстансов. Маленькие объекты вдалеке человеку чаще не заметны, тогда зачем их рисовать?
Диапазоны расстояний в итоге заменяются на процентное соотношение относительно экрана. То есть при настройке LOD мы указываем уже не дистанцию, а процентное соотношение. Например, 100% - виден когда занимает весь экран, 60% - виден, когда занимает примерно 60% площади экрана, 15% - когда объект занимает совсем небольшую площадь экрана, то есть он или маленький или находится далеко от нас.
В BRG у нас на руках есть матрица трансформации (с поворотом и скейлом в том числе) для каждого инстанса, а также размер меша per LOD в world space. То есть вычислить фактический размер в world space - уже не проблема, для удобства берем самое большее значение по одной из осей.
Зная размер меша и зная процентное соотношение, можно вычислить для него диапазон уже дистанций:
Но дистанция от объекта до камеры тоже не просто
Самый простой способ выбирать LOD - зная позицию камеры и для каждого инстанса матрицу трансформации, можно взять дистанцию между ними. Потом сравнить дистанцию с теми значениями диапазонов, которые мы указали в редакторе. Получается линейная выборка, которая никак не учитывает размер объекта.
А размер объекта на самом деле очень важен. Цель LOD - уменьшить не только кол-во треугольников, но и кол-во инстансов. Маленькие объекты вдалеке человеку чаще не заметны, тогда зачем их рисовать?
Диапазоны расстояний в итоге заменяются на процентное соотношение относительно экрана. То есть при настройке LOD мы указываем уже не дистанцию, а процентное соотношение. Например, 100% - виден когда занимает весь экран, 60% - виден, когда занимает примерно 60% площади экрана, 15% - когда объект занимает совсем небольшую площадь экрана, то есть он или маленький или находится далеко от нас.
В BRG у нас на руках есть матрица трансформации (с поворотом и скейлом в том числе) для каждого инстанса, а также размер меша per LOD в world space. То есть вычислить фактический размер в world space - уже не проблема, для удобства берем самое большее значение по одной из осей.
Зная размер меша и зная процентное соотношение, можно вычислить для него диапазон уже дистанций:
worldSpaceSize / screenRelativeTransitionHeight[i]. С этими дистанциями уже можно сравнивать дистанцию от объекта до камеры.Но дистанция от объекта до камеры тоже не просто
math.distance, так как для перспективной камеры у нас есть искажение, а для ортогональной его нет. Также необходимо еще учитывать LOD Global Bias из QualitySettings,Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤3🔥2🦄1
Вот и LOD Cross Fade получился! 🙌
Есть о чем рассказать, есть интересные моменты😧 Завтра соберу все мысли и опишу в виде поста 💃
Хотя может даже в виде статьи?🚪
Есть о чем рассказать, есть интересные моменты
Хотя может даже в виде статьи?
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11🔥9
https://telegra.ph/Level-of-Detail-v-Unity-BRG-04-10
Написала статью про LOD в BRG🚪 Весь код можно найти в моем репозитории по BRG (MIT-лицензия) 😶 Документацию там тоже скоро обновлю.
Написала статью про LOD в BRG
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegraph
Level of Detail в Unity BRG
Что такое BRG Для того, чтобы описать что же такое Batch Renderer Group (BRG) нужна отдельная статья, поэтому тут я только кратко расскажу про основные его принципы и больше расскажу про интеграцию поддержки Level of Detail (LOD).
🔥28❤6👏3😍3❤🔥1
Media is too big
VIEW IN TELEGRAM
Видео с камушками! 🤩 (и с LOD вместе с CrossFade). 🙌
Как по мне, выглядит неплохо, очень нравится, что камушки плавненько появляются и исчезают, ради этого я и добавила поддержку LOD (а не ради оптимизации, как вы могли подумать☺️ )
Чтобы не делать много постов, скриншот из Frame Debugger приложу в комментариях🚪
Как по мне, выглядит неплохо, очень нравится, что камушки плавненько появляются и исчезают, ради этого я и добавила поддержку LOD (а не ради оптимизации, как вы могли подумать
Чтобы не делать много постов, скриншот из Frame Debugger приложу в комментариях
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17❤12
Media is too big
VIEW IN TELEGRAM
Протестировала на траве! 🥔
К сожалению не нашла в HDRP ассетах от Unity лоды для травы, они ее просто скрывают плавно по дистанции (ага, и десятки и сотни млн треугольников в итоге в кадре, хоть и не видно их). Пришлось также взять просто Lit шейдер, чтобы не писать сейчас поддержку для Cross Fade для их шейдера. В итоге трава не шевелится :(
Но ничего, то, что мы не видим, то не рисуется, а это главное!🙌 Хотя при этом трава сгенерирована и находится в памяти.
P.S.: Я думала, думала, и решила немного уточнить момент с графикой. Это не стиль будущей игры, и она не будет в реализме, поэтому я не работаю сейчас над визуальной составляющей (некоторые подвижки в эту сторону скоро начнутся). Это пока что просто технические решения и некоторые стресс тесты для них (и для меня😄 ).
К сожалению не нашла в HDRP ассетах от Unity лоды для травы, они ее просто скрывают плавно по дистанции (ага, и десятки и сотни млн треугольников в итоге в кадре, хоть и не видно их). Пришлось также взять просто Lit шейдер, чтобы не писать сейчас поддержку для Cross Fade для их шейдера. В итоге трава не шевелится :(
Но ничего, то, что мы не видим, то не рисуется, а это главное!
P.S.: Я думала, думала, и решила немного уточнить момент с графикой. Это не стиль будущей игры, и она не будет в реализме, поэтому я не работаю сейчас над визуальной составляющей (некоторые подвижки в эту сторону скоро начнутся). Это пока что просто технические решения и некоторые стресс тесты для них (и для меня
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14❤3👍2
https://telegra.ph/Shading-landshafta-04-13
Решила сегодня попробовать формат не просто поста, а поста-статьи, так как в телеграмме не получится написать такой длинный пост😢 Но это не статья как в прошлый раз! Просто чуть длинненький пост)
Зато там получилось выложить побольше информации и побольше скриншотов🙌
Решила сегодня попробовать формат не просто поста, а поста-статьи, так как в телеграмме не получится написать такой длинный пост
Зато там получилось выложить побольше информации и побольше скриншотов
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegraph
Shading ландшафта
Как же я рисую ландшафт?
🔥16❤4👍3
Небольшой опрос по формату постов в канале)
И спасибо за то, что читаете и даже комментируете ^^
И спасибо за то, что читаете и даже комментируете ^^
Final Results
10%
Маленькие посты, но чаще.
10%
Большие посты через телеграф, но реже.
80%
Вперемешку - иногда маленькие, иногда большие, и иногда полноценные статьи.
🔥2
Всем спасибо за голосование! 🥰
10% проголосовало за маленькие частые посты, 10% за большие, но редкие, и 80% за смешанный тип. Тогда буду стараться поразнообразней публиковать посты)
10% проголосовало за маленькие частые посты, 10% за большие, но редкие, и 80% за смешанный тип. Тогда буду стараться поразнообразней публиковать посты)
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉5👍3❤1🥰1
Биомы
А сейчас я хотела бы подняться на уровень выше в генерации. Биомы!
Что такое биом? Это какой-то набор флоры и фауны, определенный вид ландшафта с уникальными материалами, а еще с уникальными монстрами, условиями игры и многого другого. Например биом гор, полей, леса, океана и т.п.
Но что такое биом в рамках генерации? Как ни странно, это просто набор вокселей и правила их генерации! Потому что только воксели определяют весь окружающий мир.
При генерации каждого вокселя я для него определяю и биом. Это происходит все также по графу шума (на скриншоте), правда уже в 2D.
Для каждого биома я в дальнейшем генерирую полноценный воксель - SDF значение, его градиент. А потом по blend значению смешиваю и получаю уже окончательный результат. Мне это позволяет смешивать биомы: создавать плавный переход от одного к другому. Например горы плавно переходят в поля.
Материалы я также выбираю с двух биомов, и выбираю те, которые имеют наибольший вес. Но это требует повышенного количества ресурсов, так как в одном чанке может быть сразу несколько биомов, у каждого из которых свои настройки и текстуры.
А сейчас я хотела бы подняться на уровень выше в генерации. Биомы!
Что такое биом? Это какой-то набор флоры и фауны, определенный вид ландшафта с уникальными материалами, а еще с уникальными монстрами, условиями игры и многого другого. Например биом гор, полей, леса, океана и т.п.
Но что такое биом в рамках генерации? Как ни странно, это просто набор вокселей и правила их генерации! Потому что только воксели определяют весь окружающий мир.
При генерации каждого вокселя я для него определяю и биом. Это происходит все также по графу шума (на скриншоте), правда уже в 2D.
var biomeSelectionResult = BiomeFlow.SelectBiome(worldPosition.x, worldPosition.z, InputData.WorldSeed);
BiomeFlow.SelectBiome возвращает индексы двух биомов в указанной точке, которые имеют наибольший вес. Также я возвращаю и blend значение, чтобы потом можно было смешивать результаты.Для каждого биома я в дальнейшем генерирую полноценный воксель - SDF значение, его градиент. А потом по blend значению смешиваю и получаю уже окончательный результат. Мне это позволяет смешивать биомы: создавать плавный переход от одного к другому. Например горы плавно переходят в поля.
Материалы я также выбираю с двух биомов, и выбираю те, которые имеют наибольший вес. Но это требует повышенного количества ресурсов, так как в одном чанке может быть сразу несколько биомов, у каждого из которых свои настройки и текстуры.
🔥12❤4🥰1
Burst и делегаты
Иногда в задачах никак не обойтись без делегатов, но что делать, если код на Jobs + Burst? Delegate - это managed тип, под Burst не вызовешь, а от преимуществ отказываться не хочется.
В C# есть unmanaged делегаты, которые также поддерживаются и Burst если правильно приготовить🧂
Все, что нужно сделать, так это:
Шаг 1. Определить самый обыкновенный
Шаг 2. Определить метод/методы, которые хотим вызывать с помощью делегата и пометить атрибутом с ним
Шаг 3. Пометить вызываемые методы из п.2 и типы, которые их содержат атрибутом
Шаг 4. Скомпилить каждый делегат через
Или по старинке вот так:
А что по производительности?
Например, у меня так реализованы операции над ландшафтом.🚪 Я использую указатели на функции, чтобы все типы операций (копание/возведение, по сфере, по кубу и т.п.) можно было описать абстрактной структурой
Все эти операции складываются в массив, по которому пробегаюсь при вычислении SDF вокселя.🥔
Иногда в задачах никак не обойтись без делегатов, но что делать, если код на Jobs + Burst? Delegate - это managed тип, под Burst не вызовешь, а от преимуществ отказываться не хочется.
В C# есть unmanaged делегаты, которые также поддерживаются и Burst если правильно приготовить
Все, что нужно сделать, так это:
Шаг 1. Определить самый обыкновенный
delegate и пометить его как CallingConvention.Cdecl если собираем IL2CPP:[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OperationPerformDelegate(ref OperationExecutor.Parameters parameters);
Шаг 2. Определить метод/методы, которые хотим вызывать с помощью делегата и пометить атрибутом с ним
[MonoPInvokeCallback(typeof(OperationPerformDelegate))]:[BurstCompile]
[MonoPInvokeCallback(typeof(OperationPerformDelegate))]
private static void InvokeExecute(ref OperationExecutor.Parameters parameters)
{
OperationExecutor.Execute<CapsuleOperation, CapsuleOperation>(ref parameters);
}
Шаг 3. Пометить вызываемые методы из п.2 и типы, которые их содержат атрибутом
[BurstCompile].Шаг 4. Скомпилить каждый делегат через
BurstCompiler.CompileFunctionPointer:private static readonly FunctionPointer<OperationPerformDelegate> m_InvokeExecuteFunctionPointer =
BurstCompiler.CompileFunctionPointer<OperationPerformDelegate>(InvokeExecute);
FunctionPointer можно передать любым удобным образом в Job и вызывать или с помощью обычного Invoke:m_ExecutePtr.Invoke.Invoke(ref parameters);
Или по старинке вот так:
((delegate * unmanaged[Cdecl] <ref OperationExecutor.Parameters, void>)m_ExecutePtr.Value)(ref parameters);
А что по производительности?
FunctionPointer существенно медленнее, чем прямой вызов, поэтому использовать лучше в тех моментах, где совсем не обойтись. Вот тут можно посмотреть сравнение.Например, у меня так реализованы операции над ландшафтом.
NativeOperation, которая содержит только упакованные данные операции + указатель на метод, который по этим данным может произвести вычисления.public struct NativeOperation : IDisposable
{
private readonly FunctionPointer<OperationPerformDelegate> m_ExecutePtr;
[NativeDisableUnsafePtrRestriction]
internal unsafe void* m_Data;
public readonly int3 Min;
public readonly int3 Max;
}
Все эти операции складываются в массив, по которому пробегаюсь при вычислении SDF вокселя.
Please open Telegram to view this post
VIEW IN TELEGRAM
Docs
Function pointers - C# feature specifications
This feature specification describes function pointers, which are unmanaged delegates. They are typically used to avoid the allocations necessary to instantiate a delegate object.
🔥12❤4👍2🤝1🤗1
Media is too big
VIEW IN TELEGRAM
Добавляю генерацию объектов, с которыми игрок может взаимодействовать тем или иным образом (например, физика). Это все большие камни, деревья, постройки и т.п.
Также учитываю и тот момент, что ландшафт может меняться☺️ Пока что реализовала самый простой вариант, когда при изменении ландшафта мы просто опускаем объект вниз (понадобится для кустов и подобных небольших объектов). Но в планах конечно в такие моменты включать физику, и пусть булыжник упадет кому-нибудь на голову 😕 🤭
Так как это объекты с коллайдером, то они симулируются и на серверной стороне, а не только на клиентской😶
Также учитываю и тот момент, что ландшафт может меняться
Так как это объекты с коллайдером, то они симулируются и на серверной стороне, а не только на клиентской
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Media is too big
VIEW IN TELEGRAM
Вот еще одно небольшое видео, на котором видно, что объект с коллайдером 🤩
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Media is too big
VIEW IN TELEGRAM
Тест с большими камушками 🤩
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11
Media is too big
VIEW IN TELEGRAM
Деревья!😧 🙌
Стало намного интереснее) Причем деревья, которые поблизости, являются "призраками" и синхронизируются с копией на сервере. А вот деревья вдалеке - существуют только на клиенте) При приближении они конечно же заменяются на призраки🥔
В комментариях еще скрин🫥
Стало намного интереснее) Причем деревья, которые поблизости, являются "призраками" и синхронизируются с копией на сервере. А вот деревья вдалеке - существуют только на клиенте) При приближении они конечно же заменяются на призраки
В комментариях еще скрин
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍1
Сегодня расскажу про то, что крайне редко кастомизируется - аллокаторы в DOTS! ☺️
Все, кто использует нативные коллекции из Unity.Collections, знакомы с аллокаторами, которые Unity предоставляет по умолчанию. Это Persistent - для объектов с долгим времени жизни, Temp - для однокадровых объектов, TempJob - для объектов, передаваемых в Job. Но мало кто знает, что можно написать свой аллокатор и использовать также, как и дефолтные! (Правда с некоторыми оговорками😔 )
На самом деле Unity предоставляет все необходимое API, чтобы можно было реализовать свой аллокатор и использовать в нативных коллекциях. Все, что нужно сделать, так это реализовать интерфейс
Где
Самое интересное - метод🤭 ) выяснять некоторые детали.
В качестве входного параметра нам приходит
Правила тут такие:
- если
- если
- в ином случае, мы должны освободить память.
А вот что возвращает метод?🤔 Указан возвращаемый тип как
- код
- код
После того, как написали свой аллокатор, его можно использовать, но как? Каждый аллокатор должен возвращать свой🔍
Но в случае с кастомным аллокатором есть некоторые ограничения:
1. Нельзя использовать
2.😒 Чтобы создать NativeArray<> надо использовать
Но это сильно ограничивает, в Job уже не получится задиспоузить массив, созданный таким образом😢
3. Нет поддержки многопоточности! То есть нельзя создать инстанс аллокатора в главном потоке, а потом использовать в других потоках. Причина в том, что на каждый аллокатор также создаются свои safety checks - проверки "от дурака". И🤦
Зачем вообще использовать свой аллокатор? В большинстве задач это не требуется, но иногда, все же может быть лучше свое решение, чем то, что предоставляет Unity. Я использую кастомный аллокатор на базе smmalloc по той причине, что мне в какой-то момент понадобились аллокации, которые быстры как и TempJob/Temp, но и живут больше 4 и 1 кадра соответственно.
Все, кто использует нативные коллекции из Unity.Collections, знакомы с аллокаторами, которые Unity предоставляет по умолчанию. Это Persistent - для объектов с долгим времени жизни, Temp - для однокадровых объектов, TempJob - для объектов, передаваемых в Job. Но мало кто знает, что можно написать свой аллокатор и использовать также, как и дефолтные! (Правда с некоторыми оговорками
На самом деле Unity предоставляет все необходимое API, чтобы можно было реализовать свой аллокатор и использовать в нативных коллекциях. Все, что нужно сделать, так это реализовать интерфейс
AllocatorManager.IAllocator:public struct TestAllocator : AllocatorManager.IAllocator
{
public AllocatorManager.TryFunction Function { get; }
public AllocatorManager.AllocatorHandle Handle { get; set; }
public Allocator ToAllocator { get; }
public bool IsCustomAllocator { get; }
public int Try(ref AllocatorManager.Block block) { }
public void Dispose() { }
}
Где
AllocatorManager.TryFunction Function { get; } - делегат функции int Try(ref AllocatorManager.Block block) { }, которую AllocatorManager вызывает при попытке аллоцировать/реаллоцировать/освободить память.Самое интересное - метод
Try, тут мне пришлось опытным путем (ну как всегда в Unity В качестве входного параметра нам приходит
ref AllocatorManager.Block block, который содержит некоторые детали запроса. А именно сколько элементов и с каким размером и выравниванием надо аллоцировать. Также тут хранится и указатель на память, этот указатель нам и надо заполнить. Правила тут такие:
- если
block.Range.Pointer равен IntPtr.Zero, то мы должны аллоцировать память;- если
block.Range.Pointer не равен IntPtr.Zero и block.Range.Items больше 0, то есть уже раньше аллоцировали этот блок памяти и он валиден, то мы его должны реаллоцировать;- в ином случае, мы должны освободить память.
А вот что возвращает метод?
int, надо же что-то вернуть. А возвращается тут код ошибки. Из того, что я выяснила:- код
0 - все успешно;- код
-1 - операция прошла неуспешно.После того, как написали свой аллокатор, его можно использовать, но как? Каждый аллокатор должен возвращать свой
AllocatorHandle - это всего лишь указатель на запись во внутренней таблице аллокаторов, по которой Unity ищет указатель на функцию аллокатора. Кстати, Allocator.Persistent/Temp/TempJob - также неявно конвертируются в AllocatorHandle. Но в случае с кастомным аллокатором есть некоторые ограничения:
1. Нельзя использовать
UnsafeUtility.Malloc/Free, вместо этого необходимо использовать AllocatorManager.Allocator/Free.(T*)AllocatorManager.Allocate(handle, itemSizeInBytes, alignmentInBytes, length);
AllocatorManager.Free(handle, pointer, length);
2.
NativeArray<> не поддерживает кастомный аллокатор! Причина в том, что он написан для использования только enum Allocator CollectionHelper.CollectionHelper.CreateNativeArray<T, TestAllocator>(length, ref allocator, options);
CollectionHelper.Dispose(array);
Но это сильно ограничивает, в Job уже не получится задиспоузить массив, созданный таким образом
3. Нет поддержки многопоточности! То есть нельзя создать инстанс аллокатора в главном потоке, а потом использовать в других потоках. Причина в том, что на каждый аллокатор также создаются свои safety checks - проверки "от дурака". И
SafetyHandle внутри AllocatorManager хранятся в UnsafeList, который не является потокобезопасным. Опять же недоработка от Unity.Зачем вообще использовать свой аллокатор? В большинстве задач это не требуется, но иногда, все же может быть лучше свое решение, чем то, что предоставляет Unity. Я использую кастомный аллокатор на базе smmalloc по той причине, что мне в какой-то момент понадобились аллокации, которые быстры как и TempJob/Temp, но и живут больше 4 и 1 кадра соответственно.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤6🤯2❤🔥1👍1
Разбираюсь сейчас со спайками, и немного углубляюсь в unsafe мир ☺️
Вот что интересного выяснила: память желательно выравнивать! Вот да, недостаточно просто выделить кусок памяти, желательно выровнять его по размеру кэшлайна. Разница - огромная!😧
Размер кэшлайна в Job System можно узнать через константу
А вот выровнять можно через CollectionHelper:
Где T - ваш тип данных. Достаточно просто, а разница - на скриншоте)
Вот что интересного выяснила: память желательно выравнивать! Вот да, недостаточно просто выделить кусок памяти, желательно выровнять его по размеру кэшлайна. Разница - огромная!
Размер кэшлайна в Job System можно узнать через константу
JobsUtility.CacheLineSize (64 байта).А вот выровнять можно через CollectionHelper:
// Считаем сколько памяти (в байтах) нам нужно, заодно выравниваем по кэшлайну, чтобы было кратко CacheLineSize
var someDataSize = CollectionHelper.Align(UnsafeUtility.SizeOf<T> * length, JobsUtility.CacheLineSize);
// Выделяем (аллоцируем) память по посчитанному размеру и указываем, что выравниваем по CacheLineSize
var someData = (byte*)AllocatorManager.Allocate(allocatorHandle, someDataSize, JobsUtility.CacheLineSize);
Где T - ваш тип данных. Достаточно просто, а разница - на скриншоте)
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20❤🔥2❤2👌2🦄2
Мехмат ЮФУ (Южный Федеральный Университет) не так давно взял у меня интервью, и вот оно вышло 🥔
https://t.me/igromech/85
https://t.me/igromech/85
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
ИгроМех
Иногда канал в телеграме выглядит так классно, что нельзя пройти мимо. Вот и наш @xivol настолько заинтересовался, что взял интервью у Елизаветы, которая ведет канал @infinity_world_developer_diary
По ссылке вы найдете обстоятельный разговор о процедурной…
По ссылке вы найдете обстоятельный разговор о процедурной…
🔥17👍7❤4🥰2
Что-то давно я не писала, ох уж эти выходные 🤭
Продолжаю избавляться от спаек в рантайме, много экспериментов, проверок теорий и различных исправлений. Некоторые моменты приходится вообще переосмыслить, так как оказалось, что я выбрала неправильное направление. Но это нормально, и главное тут не унывать🫥
Вместе с Profiler пользуюсь Profile Analyzer, который очень сильно помогает анализировать конкретные маркеры, и даже сравнивать их между несколькими снапшотами. Так что, очень советую этот инструмент взять на заметку, если еще не взяли🥔
Только учтите, что время там показывается на кадр) То есть, например, медиана - за кадр + кол-во кадров, в которых этот маркер есть. Я так долго думала, почему запись в память (пусть и random access) занимает 1.4 мс😄 А это 200к операций в кадр оказалось) Глупо получилось конечно 🤪
Что же касается своих маркеров, то все очень просто.
Шаг 1. Создаете сам маркер, желательно статик:
Шаг 2. Используете маркер
Шаг 3. Находим наш маркер в анализаторе по названию, который указали в конструкторе маркера.
Продолжаю избавляться от спаек в рантайме, много экспериментов, проверок теорий и различных исправлений. Некоторые моменты приходится вообще переосмыслить, так как оказалось, что я выбрала неправильное направление. Но это нормально, и главное тут не унывать
Вместе с Profiler пользуюсь Profile Analyzer, который очень сильно помогает анализировать конкретные маркеры, и даже сравнивать их между несколькими снапшотами. Так что, очень советую этот инструмент взять на заметку, если еще не взяли
Только учтите, что время там показывается на кадр) То есть, например, медиана - за кадр + кол-во кадров, в которых этот маркер есть. Я так долго думала, почему запись в память (пусть и random access) занимает 1.4 мс
Что же касается своих маркеров, то все очень просто.
Шаг 1. Создаете сам маркер, желательно статик:
private static readonly ProfilerMarker s_SomeProfilerMarker = new("Some Marker");Шаг 2. Используете маркер
// Первый вариант использования
using(s_SomeProfilerMarker.Auto())
{
// тут какой-то код, который мы хотим оценить
}
// Второй вариант использования
s_SomeProfilerMarker.Begin();
// тут какой-то код, который мы хотим оценить
s_SomeProfilerMarker.End();
Шаг 3. Находим наш маркер в анализаторе по названию, который указали в конструкторе маркера.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥5🥰2👍1