Вот теперь зум получается хорошим.
Нужен только один workaround в пользовательском коде для
Первый можно просто занулить, для второго взять
За одно переставил зум на колесико мышки. Ограничение зума и скорость будет в
Нужен только один workaround в пользовательском коде для
TextEdit
- задать явно desired_size
и margin
.Первый можно просто занулить, для второго взять
ui.spacing().item_spacing
например.За одно переставил зум на колесико мышки. Ограничение зума и скорость будет в
SnarlStyle
Сегодня я узнал что даже вот так бывает с флотами в IEEE754
Не ожидал что
Ну потому что почему бы не
assert_eq!(a, b);
let c = a - b;
assert_eq!(c, 0.0); // assertion `left == right` failed, left: NaN, right: 0.0
Не ожидал что
inf - inf
это NaN
.Ну потому что почему бы не
0.0
, раз уж они "равны".This media is not supported in your browser
VIEW IN TELEGRAM
Соединять пачку пинов с одним теперь проще!
❤4👍1🔥1
Я полностью перелопатил API у `SnarlViewer`а.
Полностью отказался от концепции записи эффектов.
Теперь методы просто получают
Ноды теперь не обернуты в
Полностью отказался от концепции записи эффектов.
Теперь методы просто получают
&mut Snarl
и делают что хотят с ним.Ноды теперь не обернуты в
RefCell
и в методы вьюера не передаются, только IDшники, по которым можно получить ссылку🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
Добавить выдергивание связки проводов оказалось еще проще.
👍5
This media is not supported in your browser
VIEW IN TELEGRAM
А вот и граф систем в действии.
Контроль за выполнением систем прямо во время игры.
В теории можно запустить несколько игр в редакторе, все шарят граф.
Контроль за выполнением систем прямо во время игры.
В теории можно запустить несколько игр в редакторе, все шарят граф.
🍓4🔥2👍1
Если интересно, а где же система спавнящая кружочки, то ее нет.
Кружочки спавнятся в асинхронных тасках.
Макромагия нужна потому что Rust не может в асинк замыкания нормально.
не компилируется если потребовать такой баунд.
Хотя с
Кружочки спавнятся в асинхронных тасках.
Макромагия нужна потому что Rust не может в асинк замыкания нормально.
|world: &mut World| async { use_world(world).await; }
не компилируется если потребовать такой баунд.
for<'a> F: FnMut(&'a mut World) -> Future + 'a
Хотя с
async fn
такое сработает👍1🤯1
Лопающиеся шары?
Это явно высокоуровневая какая-то логика.
Поэтому она не в системе, а в таске, которая привязана к сущности каждого шарика.
При первом столкновении с другим шариком она попадает в цикл, где увеличивает размер шарика с маленьким шагом каждые 20мс и уничтожает его.
Это явно высокоуровневая какая-то логика.
Поэтому она не в системе, а в таске, которая привязана к сущности каждого шарика.
При первом столкновении с другим шариком она попадает в цикл, где увеличивает размер шарика с маленьким шагом каждые 20мс и уничтожает его.
👍1
Ничего давно не постил. Потихоньку делаю work-graph для работы с GPU в движке и эдиторе.
Сначала я хотел просто отображать графи рендерпассов, без возможности менять его в UI, так как он задается кодом.
Сейчас рядом с рендерграфом почти вырос более обобщенный
В первом черновике входы и выходы типизировались растовыми типами и соотвественно в данных лежал
Сейчас за неимением сильно лучшей альтернативы в нодах лежит
Но граф существует как граф только в редакторе.
В джижке он тут же превращается втыкву очередь.
В самом деле, зачем нам хранить граф как граф, если нас интересует только его обход в dependencies-first или dependencies-last порядке. Можно просто сделать очередь и ходить по ней в двух направлениях.
В конструкторе
Портам, которые соединены с другим(и) назначаются target IDшки, так что бы у соединенных был одинаковый ID, а так же у update пар внутри каждой джобы.
Еще всем входам прописываются их джобы-зависимости. Почему портам а не джобам? Сейчас мы к этому придем.
WorkGraph в движке получается полу-статичный, при изменении набора нод или связей нужно пересобрать движковый WorkGraph. Это совершенно нормально, потому что меняется граф только когда разработчик руками его меняет, то есть очень не часто в разработке, а в проде вообще никогда.
Но все же не совсем статичный.
В граф можно добавить к выходам внешние таргеты, так результат работы графа и экстрактится из него.
Например можно захватить следующую картинку из
Дальше то что идет каждый кадр.
1. Планирование. Берем все внешние таргеты и добавляем в сет
2. Потом идем с конца, пропуская джобы не из
В этот момент так же добавляются в
В конце получаем сет всех джоб, которые нужно запустить, что бы заполнить все внешние таргеты. А еще у каждого таргета, который нужно будет создать, собирается
3. Наконец идем в прямом порядке и запускаем выполнение всех
Кроме таргетов джоба аллоцирует нужное количество
К тому же перед тем как отдать первый
Так же джоба вольна пользоваться
4. В последний
Вот так примерно оно должно будет работать.
Кто досюда дочитал - молодец и умница, возьми угощение на полочке и поставь лайк.
Сначала я хотел просто отображать графи рендерпассов, без возможности менять его в UI, так как он задается кодом.
Сейчас рядом с рендерграфом почти вырос более обобщенный
WorkGraph
, который можно собрать из джобов, которые плагины будут экспортировать. Джобы будут инстанциироваться и соединятся как угодно, в пределах типизации пинов.В первом черновике входы и выходы типизировались растовыми типами и соотвественно в данных лежал
TypeId
, но так как плагины могут в рантайме перезагружаться, то TypeId
может меняться.Сейчас за неимением сильно лучшей альтернативы в нодах лежит
kind: String
. А в дженерик методах, где есть тип T: Target
проверяется T::kind() == pin.kind
. Если у вас есть идеи что будет лучше, милости прошу, оставьте в комментариях.Но граф существует как граф только в редакторе.
В джижке он тут же превращается в
В самом деле, зачем нам хранить граф как граф, если нас интересует только его обход в dependencies-first или dependencies-last порядке. Можно просто сделать очередь и ходить по ней в двух направлениях.
В конструкторе
WorkGraph
на вход подаются джобы и их связи.Портам, которые соединены с другим(и) назначаются target IDшки, так что бы у соединенных был одинаковый ID, а так же у update пар внутри каждой джобы.
Еще всем входам прописываются их джобы-зависимости. Почему портам а не джобам? Сейчас мы к этому придем.
WorkGraph в движке получается полу-статичный, при изменении набора нод или связей нужно пересобрать движковый WorkGraph. Это совершенно нормально, потому что меняется граф только когда разработчик руками его меняет, то есть очень не часто в разработке, а в проде вообще никогда.
Но все же не совсем статичный.
В граф можно добавить к выходам внешние таргеты, так результат работы графа и экстрактится из него.
Например можно захватить следующую картинку из
Swapchain
и установить в качестве таргета у вообще любого выхода подходящего типа. Это даже вполне ок делать каждый кадр, если их количество не зашкаливает.Дальше то что идет каждый кадр.
1. Планирование. Берем все внешние таргеты и добавляем в сет
selected
все джобы ноды от этих выходов.2. Потом идем с конца, пропуская джобы не из
selected
и собираем дескрипшны со всех входов, так мы узнаем например какого разрешение должен быть таргет картинка или размер таргета буфера.В этот момент так же добавляются в
selected
джобы-зависимости каждого входного порта. Да, вот они где используются.В конце получаем сет всех джоб, которые нужно запустить, что бы заполнить все внешние таргеты. А еще у каждого таргета, который нужно будет создать, собирается
Target::Info
для инициализации.3. Наконец идем в прямом порядке и запускаем выполнение всех
selected
джоб. В этот момент создаются все нужные таргеты (берутся из кэша, если предыдущий Target::Info
совпадает).Кроме таргетов джоба аллоцирует нужное количество
CommandEncoder
-ов которые сразу кладутся в очередь, а джобе достается только ссылка. Так джоба не забудет сделать Queue::submit
, потому что она и не должна.К тому же перед тем как отдать первый
CommandBuffer
джобе, туда ловко вставляется синхронизация (в коде еще нет, но такой план).Так же джоба вольна пользоваться
Device
для создания внутренних ресурсов и чего только ей не захочется.4. В последний
CommandEncoder
вписывается синхронизация между джобами и внешним кодом для внешних ресурсов. Туда же добавится CommandEncoder::present
. После чего все они сабмитятся в порядке аллокации.Вот так примерно оно должно будет работать.
Кто досюда дочитал - молодец и умница, возьми угощение на полочке и поставь лайк.
👍4
Попался любопытный проект.
https://github.com/ronnychevalier/cargo-multivers
Наверное, с распоследними векторными оптимизациями какая-нибудь рапира сможет потянуть еще больше тел
https://github.com/ronnychevalier/cargo-multivers
Наверное, с распоследними векторными оптимизациями какая-нибудь рапира сможет потянуть еще больше тел
GitHub
GitHub - ronnychevalier/cargo-multivers: Cargo subcommand to build multiple versions of the same binary, each with a different…
Cargo subcommand to build multiple versions of the same binary, each with a different CPU features set, merged into a single portable optimized binary - ronnychevalier/cargo-multivers
👍2
Абсолютно неожиданно человек взял мой
Да еще и сказал "Overall the experience was fantastic and this crate made the whole thing possible".
Что ж, я получил +10 к уверенности в соих способностях и желанию продолжать делать опенсорс.
egui-snarl
и noise
(не мой crate для генерации текстурок шумов) и сделал красивый GUI.Да еще и сказал "Overall the experience was fantastic and this crate made the whole thing possible".
Что ж, я получил +10 к уверенности в соих способностях и желанию продолжать делать опенсорс.
🔥16
Почти добрался делать UI для редактирования значений в компонентах.
Поэтому для начала пилю виджет с трейтом и дерайв макросом для редактирования значений.
План простой - дерайвим трейт для компонентов.
Добавляем трейт в borrow список компонента.
Кверим все компоненты с этим трейтом. Показываем виджеты.
Поэтому для начала пилю виджет с трейтом и дерайв макросом для редактирования значений.
План простой - дерайвим трейт для компонентов.
Добавляем трейт в borrow список компонента.
Кверим все компоненты с этим трейтом. Показываем виджеты.
🔥4