<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Sovka Ivanov</title><author><name>Sovka Ivanov</name></author><id>https://teletype.in/atom/mrhuempolbu</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/mrhuempolbu?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@mrhuempolbu?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mrhuempolbu"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/mrhuempolbu?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-10-03T20:26:21.136Z</updated><entry><id>mrhuempolbu:MkB2O0Hiteb</id><link rel="alternate" type="text/html" href="https://teletype.in/@mrhuempolbu/MkB2O0Hiteb?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mrhuempolbu"></link><title>Баланс билдов.</title><published>2025-02-23T08:10:24.560Z</published><updated>2025-06-18T09:58:11.173Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/16/d6/16d6aa5d-06ce-4171-a980-660ffea9d277.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/54/d2/54d25a48-1456-4422-bca8-4a1447c0ae26.png&quot;&gt;В какой-то игрульке у нас были персонажи со статами. На входе у игрока есть всего 4 параметра, по которым ему нужно каким-то образом распределить ачьки: сила ловкость и хуёвкость. На выходе же было больше десяти разных характеристик, которые аффкетятся этим распределением — там всякая меткость, скорость, размер бицухи и прочее. Идея была в том, что бы при радикальном распределении всех ачьков в один параметр характеристики персонажа получались сосунковыми, а при равномерном размазывании поинтов билд персонажа получался хорошим и крепким. Опционально было б круто ещё сделать какую-нибудь секретную пропорцию прокачки, при которой билд получается имбовым, но которую можно нащупать только методом градиентного спуска по пробам и ошибкам...</summary><content type="html">
  &lt;h2 id=&quot;IguZ&quot;&gt;Техническая часть.&lt;/h2&gt;
  &lt;p id=&quot;Lhvq&quot;&gt;В какой-то игрульке у нас были персонажи со статами. На входе у игрока есть всего 4 параметра, по которым ему нужно каким-то образом распределить ачьки: сила ловкость и хуёвкость. На выходе же было больше десяти разных характеристик, которые аффектятся этим распределением — там всякая меткость, скорость, размер бицухи и прочее. Идея была в том, что бы при радикальном распределении всех очков в один параметр характеристики персонажа получались сосунковыми, а при равномерном размазывании поинтов билд персонажа получался хорошим и крепким. Опционально было б круто ещё сделать какую-нибудь секретную пропорцию прокачки, при которой билд получается имбовым, но которую можно нащупать только методом градиентного спуска по пробам и ошибкам. И последнее важное требование: опорные распределения должен задать геймдизайнер. Пример внизу, зелёное заполняет геймдиз на своё усмотрение, белое должен расчитывать мой инструмент.&lt;/p&gt;
  &lt;figure id=&quot;YzFl&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/54/d2/54d25a48-1456-4422-bca8-4a1447c0ae26.png&quot; width=&quot;851&quot; /&gt;
    &lt;figcaption&gt;Ярко зелёным опорные распределения, мутно зелёным опорные билды при этих распределениях. &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;lpch&quot;&gt;Сначала мы чего-то мыкались да пыкались, пробовали да тестили, и всё получалось неустойчиво со всякими сраными побочками. Характеристики уходили в отрицательные значения, небольшое изменение входа приводило к большому изменению выхода и т.д. Из неудачных попыток я помню только линейную регрессию, остальные нерабочие варианты благополучно забыл.  В некоторый момент мы с пацанами додумались сделать визуальную модельку такой системы. Увидев это визуально, я воскликнул: «&lt;em&gt;Ебать меня ржавым якорем! Да это же барицентрическая залупа!&lt;/em&gt;» И в тот же день задачка была успешно закрыта, реализация заняла несколько часов. Матчасть и вовсе несколько минут, львиная возня произошла с API гугл-табличек. &lt;/p&gt;
  &lt;figure id=&quot;61yO&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cf/5d/cf5d8f3b-bc00-4562-b1ab-89fda100f90e.png&quot; width=&quot;1271&quot; /&gt;
    &lt;figcaption&gt;Чёрным опорные билды, красным искомый билд.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;M0WO&quot;&gt;Игорь распределил свои поинты, игре нужно найти три ближайших опорных распределения. Получился локальный барицентрический базис. Далее в этом базисе нужно узнать координаты игорьковского билда — это будут барицентрические веса. И далее эти веса умножить на соответствующие им статы и сложить. Если ни хера не понятно, то вот так понятно: &lt;/p&gt;
  &lt;ol id=&quot;fZXQ&quot;&gt;
    &lt;li id=&quot;obSE&quot;&gt;Найти ближайшие опоры.&lt;/li&gt;
    &lt;li id=&quot;JZR4&quot;&gt;Проинтерполироваться между ними.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;eDXx&quot;&gt;Корокто про возню с API гугл-табличек:&lt;/p&gt;
  &lt;figure id=&quot;iqZb&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/61/f7/61f7b1b9-6ae1-458d-ba33-a9ee4b0bf631.png&quot; width=&quot;468&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;vtVd&quot;&gt;Гуманитарная часть.&lt;/h2&gt;
  &lt;p id=&quot;O6vB&quot;&gt;Это был первый раз, когда я делал математичное &lt;strong&gt;не CG&lt;/strong&gt;. В будущем оказалось, что не последний, ещё пару раз нужно было выдумывать какие-то кастомные геймдизные инструменты, и в основном это было интересно. На следующих геймдизных задачках я заметил одну фундаментальную разницу между прогерством и дизайнерством: инстант результат и отложенный результат. В разработке результат работы можно оценить сразу же после нажатия кнопочки плэй; в дизайне же результат видно через три дня, тридцать дней, девяносто дней, в общем через много нажатий кнопочки плэй. И как следствие, дебаг разработки суть одно прямолинейное рассуждение, дебаг дизайна — какой-то ебучий бэк пропагейшен. &lt;/p&gt;
  &lt;p id=&quot;GxVH&quot;&gt;От этой системы прокачки отказались в пользу я хз чего, я даже не знал, для какой это игры задумывалось. Да и мне оно было собственно до пизды.&lt;/p&gt;

</content></entry><entry><id>mrhuempolbu:LsJ4vEIu87z</id><link rel="alternate" type="text/html" href="https://teletype.in/@mrhuempolbu/LsJ4vEIu87z?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mrhuempolbu"></link><title>Расчлен на Unity.</title><published>2025-02-21T13:26:13.463Z</published><updated>2025-06-18T10:08:18.592Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/0f/e0/0fe02b28-556e-4f59-8b8c-5642faf8c6a8.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/cb/7b/cb7b4fde-d5da-44fa-91eb-7835ad6a5dbb.png&quot;&gt;Код не покажу, потому что это НДА и просто душно. Алгоритм расскажу, потому что это можно и круто. Всё это происходило давно, и все полезные на тот момент ссылки да ресурсы сейчас утеряны и/или неактуальны. Да и хуй с ними.</summary><content type="html">
  &lt;h2 id=&quot;qIcM&quot;&gt;Техническая часть.&lt;/h2&gt;
  &lt;p id=&quot;aLLv&quot;&gt;&lt;em&gt;Код не покажу, потому что это НДА и просто душно. Алгоритм расскажу, потому что это можно и круто. Всё это происходило давно, и все полезные на тот момент ссылки да ресурсы сейчас утеряны и/или неактуальны. Да и хуй с ними.&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;figure id=&quot;i3KG&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cb/7b/cb7b4fde-d5da-44fa-91eb-7835ad6a5dbb.png&quot; width=&quot;829&quot; /&gt;
    &lt;figcaption&gt;Для заголовка.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;QBQR&quot;&gt;Однажды мы делали пострелушки киборгов. Одной из угарных фич была расчленёнка и сочленёнка обратно. То есть какому-то терпиле (в т.ч. из своей команды) можно отстрелить нахуй голову, затем видимо войдя в кураж оторвать голову себе тоже, и водрузить на своего фрешдекапитейтед персонажа свежий трофей. &lt;strong&gt;БЛЯТЬ, ДА Я БЫЛ РОЖДЁН ДЛЯ ЭТОЙ ЗАДАЧИ. &lt;/strong&gt;Беглый гугл показал, что расчлен на юнити делается легко. Там нужно-то всего лишь заготовки моделек без конечностей, и заготовки конечностей. И во время расчлена, просто нормальную модель заменять на безрукую например, а рядом спавнить оторванную руку. Но вот для обратного сочлена с такой системой требуются заготовки всех перестановок всех конечностей между всеми персонажами, что  слегка неприемлемо. И никаких других способов расчленять гуманоидов я в интернетах не нашёл, как и никаких вообще способов сочленять. Я попробовал просто детачить кость от скелета, но юнити мне сказал «&lt;em&gt;runtime error»&lt;/em&gt; или что-то в этом духе, оказывается так делать нельзя. После этого &lt;s&gt;в маршрутке начался &lt;/s&gt;пришлось закопаться в доку на пару дней и разбираться, как это всё говно там работает. И вот как:&lt;/p&gt;
  &lt;ol id=&quot;3EhV&quot;&gt;
    &lt;li id=&quot;BLRz&quot;&gt;Есть иерархия костей, типа скелет. Хотя не типа ни хера, это и есть скелет. Это конкретные геймОбжекты в сцене с позишеном и ротейшеном. У них там есть параметр, какой меш на них забинден, этот параметр кайф, он мне пригодился.&lt;/li&gt;
    &lt;li id=&quot;UUEZ&quot;&gt;Есть аватар. Это уже абстракция, а не конкретный объект. Можно его рассматривать как конфиг, в котором записаны имена и должности костей. Его роль — обоссанная прокладка между скелетом и аниматором. Аватар может быть произвольного или гуманоидного типа, в случае с гуманоидом у него должности костей расписаны заранее: левая рука, средняя нога и т.д. Это мне однажды вставило небольшую палочку в колёсико.&lt;/li&gt;
    &lt;li id=&quot;P0l3&quot;&gt;Есть аниматор. Это компонент на руте скелета, он собирает разную инфу со всей игры: какие кнопочки сейчас нажаты, кто персонаж по жизни и т.п., инфу отправляет в контроллер, анимации отправляет в аватар. &lt;/li&gt;
    &lt;li id=&quot;bC3V&quot;&gt;Есть контроллер анимаций, это обычный стейт машин, во всех движках одинаковый. Аниматор выдаёт ему разные параметры и спрашивает, что в такой ситуации делать -&amp;gt; контроллер ему отвечает, что в такой ситуации нужно делать приседания -&amp;gt; аниматор отправляет присед в аватара -&amp;gt; аватар сажает кости.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;dzPM&quot;&gt;Отсюда я выяснил, что детачить кость просто так нельзя, потому что разрабы не готовили аватар к ситуациям, когда у скелета могут спиздить кости. Но вот конструктить на лету новый аватар с новым конфигом костей, и потом ставить его в аниматора можно. Я так и сделал. И выяснил, что гуманоидный аватар придирчив к наличию всех конечностей, на каждую руку и ногу должны быть указаны кости. Ноу проблем, я могу сделать кости, у которых параметр забинденного меша будет пустым. А если и кости будут придирчивы к наличию меша, могу сделать пустой меш, хуль тут сложного. Но к счастью кости оказались не придирчивыми. И вот, после того, как новый аватар с пустой конечностью засунут в аниматора, старый аватар автоматически уничтожается сборщиком мусора, и в сцене остаются кости оторванной конечности, которые не указаны ни в одном аватаре, и следовательно их можно доставать из иерархии скелета и отправлять в свободный регдолл. И расчлен работает с кайфом. Вот первый удачный тест.&lt;/p&gt;
  &lt;figure id=&quot;F1uT&quot; class=&quot;m_column&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/a2ZRTwjU_qM?autoplay=0&amp;loop=0&amp;mute=0&quot;&gt;&lt;/iframe&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XIfo&quot;&gt;Далее был неожиданный и приятный момент: сочлен задействует все те же операции, просто в обратном порядке, так что его разработка прошла уже на изичах, с красивыми виражами вокруг всех ранее отпизженных моей головой граблей. На всякий случай полный порядок для сочленения: кости с оторванной конечностью засунуть в иерархию скелета -&amp;gt; собрать новый аватар с учётом этой новой конечности -&amp;gt; поставить аватар в аниматора. Вот последний удачный тест:&lt;/p&gt;
  &lt;figure id=&quot;veow&quot; class=&quot;m_column&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/SRHllxZEMN8?autoplay=0&amp;loop=0&amp;mute=0&quot;&gt;&lt;/iframe&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;2bCS&quot;&gt;Гуманитарная часть.&lt;/h2&gt;
  &lt;p id=&quot;gNHe&quot;&gt;В техчасти всё описано как будто бы раз два и готово. Но на деле это оказался почти месяц разработки. Юнити вставлял очень много опущенных палок в колёса, и единственный, кто мне как-то помогал с этими палками разбираться — документация юнити. Как и в случае с декалями, никаких подобных разработок именно на юнити я в интернетах не нашёл, поэтому во всём пришлось разобраться самому методом проб и ошибок. &lt;br /&gt;Игрульку выпустили в открытую бету, собрали фидбек, и свернули разработку. И тут мне было немножечко обидно, потому что я во всякий драйв и трэш люблю играть, и эту игру я бы хотел помацать в финальной версии со всеми её кровавыми угарами.&lt;br /&gt;Ещё мне в этом проекте доверили сделать немного рига на киборгов, чтоб они от попаданий дёргались физкорректно, чтоб отдача от выстрелов была и ещё чот там такое. Ниже пара мемов с этого этапа работы. Вообще в процессе разработки было много дикого ора, угара, смехуёчков и веселья. И пара кранчей была, которая полностью того стоила, ящетаю.&lt;/p&gt;
  &lt;figure id=&quot;fVb3&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f8/43/f843e94e-29b3-4900-ae13-e2d766b8e0a8.jpeg&quot; width=&quot;482&quot; /&gt;
    &lt;figcaption&gt;Это жожо референс?&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;gNgn&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/de/d7/ded7917d-51fa-472a-aacf-6859c61e6d3e.jpeg&quot; width=&quot;526&quot; /&gt;
  &lt;/figure&gt;

</content></entry><entry><id>mrhuempolbu:9TjV7jmrlht</id><link rel="alternate" type="text/html" href="https://teletype.in/@mrhuempolbu/9TjV7jmrlht?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mrhuempolbu"></link><title>Запечёный GI на webGL.</title><published>2025-02-21T07:34:05.892Z</published><updated>2025-02-21T07:34:05.892Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/2a/da/2adaee11-0a2e-42fb-b20c-9106bfef8b42.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/f9/4a/f94a9046-9e94-4cdb-99d2-92f7e3e8af22.jpeg&quot;&gt;Код не покажу, потому что это НДА и просто душно. Алгоритм расскажу, потому что это можно и круто. Всё это происходило давно, и все полезные на тот момент ссылки да ресурсы сейчас утеряны и/или неактуальны. Да и хуй с ними.</summary><content type="html">
  &lt;h2 id=&quot;qIcM&quot;&gt;Техническая часть.&lt;/h2&gt;
  &lt;p id=&quot;aLLv&quot;&gt;&lt;em&gt;Код не покажу, потому что это НДА и просто душно. Алгоритм расскажу, потому что это можно и круто. Всё это происходило давно, и все полезные на тот момент ссылки да ресурсы сейчас утеряны и/или неактуальны. Да и хуй с ними.&lt;/em&gt;&lt;/p&gt;
  &lt;figure id=&quot;jpNC&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f9/4a/f94a9046-9e94-4cdb-99d2-92f7e3e8af22.jpeg&quot; width=&quot;1280&quot; /&gt;
    &lt;figcaption&gt;Ноль источников света.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;5S8G&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/31/48/3148a2a3-d5c4-4bd9-b273-997f2ed31ec1.jpeg&quot; width=&quot;1280&quot; /&gt;
    &lt;figcaption&gt;ДжиАй онли. &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Srq5&quot;&gt;Делали какую-то пострелушку на браузерном движке Playcanvas. По какой-то причине нам захотелось добавить туда global illumination, который предварительно красиво запечь где-нибудь там в гудини например. Чтоб персонаж бегал по левелу, и угарно освещался этим левелом. Но лайтпроб-то в плейканвасе нету. Значит придётся их своими руками сделать. На мне повисла работа по движку, на другом серьёзном пацане работа по гудини. Идея запекания проста: разбить пространство на грид точек, в каждой точке посчитать освещённость (цвет, интенсивность опционально), все эти значения упаковать в жсон и отдать мне. Идея лайтпроб тоже проста: засунуть этот жсон в шейдер, и шейдером разобраться с какого раена конкретная точка на геометрии, которую сейчас надо осветить, кто её ближайшие соседи из запечённого грида, и  проинтерполироваться между этими соседями. Реализация оказалась тоже проста — всё как задумали, так и сделали. По части запекания в гудиче я хз какие проблемы возникали, это были не мои проблемы. У меня же возникла беда с суванием жсона в шейдер, ибо webGL того времени не поддерживал никаких буферов, и никаким удобным образом массив кастомных данных в GPU не передать. Но есть неудобный способ, который я уже применял в декалях — закодировать всю эту парашу в текстуру, и отправлять в видеокарту текстуру. Благо наши так называемые &lt;em&gt;кастомные&lt;/em&gt; данные — это RGB, так что и кодировать даже ничего не пришлось, взял цвет точки, положил в цвет текселя, хуль тут сложного. Ну и вот, теперь у меня есть текстура, в каждом пикселе которой находится значение освещённости в какой-нибудь точке сцены. Эту текстуру я могу сувать в шейдер. Шейдер написал без приключений — там просто определение соседей да интерполяция между ними, ничего интересного. А потом снова нюанс: этот фейк-джиай должен быть встроен во все материалы сцены. Чтобы художники там понастраивали материальчики, игру включили, а мой GI опа и работает сам собой. И такую возможность встраивания своего кода в код материала плэйканвас предоставляет. Молодец какой. Там это называется shader chunks. Суть в том, что шейдеры компилятся при запуске игры, а не в едиторе. В едиторе же они хранятся текстом, просто открытым голым кодом валяются, а значит промеж этого заводского кода можно сувать свой кастомный код. И при запуске компилиться будет уже заводской шейдер со встроенными кусками моего. Я свой шейдер и положил во все материалы в чанк люминанса. А потом чтобы художники могли новые материалы добавлять, и меня не дёргать мол включи ну включи джиай, я бахнул скрипт, который при запуске ещё до компиляции шейдеров все материалы собирает, и суёт в них мой шейдер.&lt;/p&gt;
  &lt;p id=&quot;yFlX&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;ghxq&quot;&gt;Гуманитарная часть.&lt;/h2&gt;
  &lt;p id=&quot;mDcB&quot;&gt;Давным-давно я щупал движок юниджайн, кажется это был ещё 2014. Там я увидел лайтпробы и охуел как вкопанный. Это казалось обоссаным чудом, что глобал иллюминейшен возможен в риалтайме хоть в каком-то виде. Я тогда думал, что это какие-то надмозги придумали и даже не пытался там что-то изучить или поприкидывать, как это могли сделать; просто подумал «не для моих мозгов», пустил дегенеративную слюнку и забил хуйца. И вот спустя шесть лет мне поставили задачку бахнуть этот иллюминейшен в браузере. И мне не понадобилось даже ничего гуглить, идея как это сделать пришла сразу же, я сразу эту идею реализовал, и всё прошло гладко, легко и быстро. На протяжении всего дня разработки я не воспользовался гуглом ни разу. Задачка казалась пугающей издалека, но вблизи на практике выяснилось, что а разговоров-то было.&lt;/p&gt;

</content></entry><entry><id>mrhuempolbu:sWUvt_vDQnQ</id><link rel="alternate" type="text/html" href="https://teletype.in/@mrhuempolbu/sWUvt_vDQnQ?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=mrhuempolbu"></link><title>Декали на webGL.</title><published>2025-02-20T08:30:55.751Z</published><updated>2025-02-20T13:50:41.224Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/db/c3/dbc35ef0-6c22-4f5a-aa0b-f90d8bfec043.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/7d/67/7d67d7f8-e1d4-4597-a0cb-3c82bd650c94.png&quot;&gt;Код не покажу, потому что это НДА и просто душно. Алгоритм расскажу, потому что это можно и круто. Всё это происходило давно, и все полезные на тот момент ссылки да ресурсы сейчас утеряны и/или неактуальны. Да и хуй с ними.</summary><content type="html">
  &lt;h2 id=&quot;qIcM&quot;&gt;Техническая часть.&lt;/h2&gt;
  &lt;p id=&quot;aLLv&quot;&gt;&lt;em&gt;Код не покажу, потому что это НДА и просто душно. Алгоритм расскажу, потому что это можно и круто. Всё это происходило давно, и все полезные на тот момент ссылки да ресурсы сейчас утеряны и/или неактуальны. Да и хуй с ними.&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;IfJy&quot;&gt;Что такое декали, если по какой-то причине твоя карьера прошла мимо них:&lt;/p&gt;
  &lt;figure id=&quot;XXaE&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7d/67/7d67d7f8-e1d4-4597-a0cb-3c82bd650c94.png&quot; width=&quot;1801&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Pvvu&quot;&gt;Мне нужно было их бахнуть на браузерном игровом движке Playcanvas. Требований было немного, вот они все трое:&lt;/p&gt;
  &lt;ul id=&quot;soqx&quot;&gt;
    &lt;li id=&quot;Tr2m&quot;&gt;Декали должны быть со своим материалом, своими параметрами спекуляра с говном.&lt;/li&gt;
    &lt;li id=&quot;Jyal&quot;&gt;Они должны спавниться в рантайме, то есть охуенно быстро.&lt;/li&gt;
    &lt;li id=&quot;xTpd&quot;&gt;Их может наспавниться очень много, так что количество декалек должно очень слабо влиять на перформанс.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;fpD2&quot;&gt;&lt;br /&gt;И первым применением по плану должны были стать брызги крови на стенах, на полу, на любой геометрии, РАЗМАЗАТЬ ЭТО ДЕРЬМО ПО ВСЕЙ СЦЕНЕ. И думая о кровище, я от себя добавил ещё немного требований:&lt;/p&gt;
  &lt;ul id=&quot;LJEV&quot;&gt;
    &lt;li id=&quot;WEdL&quot;&gt;Расстояние от источника брызг до поверхности должно влиять на дисперсию.&lt;/li&gt;
    &lt;li id=&quot;foDD&quot;&gt;Форма брызгульки должна зависеть от угла между направлением брызг и поверхностью.&lt;/li&gt;
    &lt;li id=&quot;D8cQ&quot;&gt;Каждая брызга уникальна по форме, никаких подготовленных текстур, чисто генератив.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;LTNM&quot;&gt;Позже оказалось, что первые два требования — это одно и то же требование в двух разных интерпретациях, это круто.&lt;/p&gt;
  &lt;p id=&quot;O5BD&quot;&gt;Все перестрелки между игорьками происходят на стороне CPU, то есть высчитывать направление и позишен декали придётся именно там. А рендерить придётся на GPU.  Другой поганый момент — на GPU мне не сделать какую-то угарную структуру данных, в которую можно было бы на расслабоне складывать и хранить прилетающие из CPU декальки, которые при рендере доставать и юзать не снимая свитер. Значит удобно складывать и хранить эти декали придётся тоже на стороне CPU. Учитывая требования выше, мне нужна структура данных, у которой максимально быстрая вставка нового элемента, адекватно быстрый поиск элемента и максимально сильное похуй всё остальное. Спецфичи, которые могут помочь — у декалей три координаты, значит моя структурка может быть трёхмерной. Сразу же в голову пришло ЕБЕЩЕЕ ОКТОДЕРЕВО, оно ведь будто бы рождено для этой задачи, мэтчинг по требованиям сто из ста. И я его сделал. Вот как это говно у меня работало (ячейки октодерева во всём этом длинночтене я буду называть вокселями).&lt;/p&gt;
  &lt;p id=&quot;jEZw&quot;&gt;&lt;strong&gt;1. ИНИШИАЛ СОСТОЯНИЕ.&lt;/strong&gt;&lt;br /&gt;Существует структурка декали, в ней лежит матрица и какая-то кастомная инфа, например таймстамп или цвет или что угодно.&lt;br /&gt;Существует тупа массив декалей. При ините естеесн пустой. &lt;br /&gt;Существует структурка вокселя, в ней лежат восемь интеджеров (ссылки на декали в предыдущем массиве либо на другие воксели в этом же массиве); чекбокс subdivided; какая-то техническая инфа, которая я уже и не помню для нахуя.&lt;br /&gt;Существует тупа массив вокселей. Оба массива нужны отдельно для отправки всех этих данных на GPU, потому что октодерево туда не отправить.&lt;br /&gt;И собсна само октодерево: в инишиал состояни это просто один большой воксель размером с весь левел.&lt;/p&gt;
  &lt;p id=&quot;KyKS&quot;&gt;&lt;strong&gt;2. СПАВН.&lt;/strong&gt;&lt;br /&gt;Спавнится первая декаль, вторая и вплоть до восьмой — массив декалей пополняется, в большом вокселе восемь сцылок заполняются. И тут спавнится предательская девятая декаль. В массив она конечно на изи попадает, но в вокселе для неё места нету, все ссылки заняты. И этот кедр просто делится на восемь вокселей поменьше. Они попадают в массив вокселей. Те восемь декалей, которые в большом папе, распихиваются по его дочкам, папа-воксель ставит себе чекбокс subdivided, и ссылки на декали заменяет ссылками на дочек.&lt;/p&gt;
  &lt;figure id=&quot;YYBD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/67/55/6755490d-90e9-4e19-a162-fc9e386d554a.png&quot; width=&quot;1705&quot; /&gt;
    &lt;figcaption&gt;Ни хуя не понятно, но очень интересно. Слева до деления вокселя, справа после.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;X4BC&quot;&gt;&lt;strong&gt;3. ПОИСК.&lt;br /&gt;&lt;/strong&gt;Позишен свежей декальки поступает в первый большой папа-воксель. Если этот воксель уже разбит, то он оценивает, с какого раена свежая декаль, и кому из дочек её отправить, и отправляет. Доча-воксель, принявшая эту декаль, поступает с ней точно так же. И так до тех пор, пока декаль не дойдёт до вокселя, который ещё не разбит на дочек, и в котором есть для неё место.&lt;/p&gt;
  &lt;p id=&quot;H0hh&quot;&gt;&lt;strong&gt;4. ПРОФИТ.&lt;br /&gt;&lt;/strong&gt;Казалось бы ни хера себе тут работы, компуктер перегреется. Хотя если ты шаришь за &lt;em&gt;O(n)&lt;/em&gt;, то тебе не казалось бы. Тем не менее. На тестах декали вставляются не то что с лагом, а с ускорением нахуй. Фпс вверх подскакивает, когда декаль спавнится. Шучу конечно, фпс просто не дёргается, никакого лага нету, всё работает максимально с кайфом. Октодерево аппрувед.&lt;/p&gt;
  &lt;blockquote id=&quot;Nkvr&quot;&gt;Маленькай момент с максимальной глубиной дерева, доколе оно может делиться. Тут изи посчитать, на карте максимально может бегать &lt;em&gt;x&lt;/em&gt; челиков, в каждого можо сделать максимум &lt;em&gt;y&lt;/em&gt; попаданий до разлома кабины. Пусть карта отмывается от крови раз в &lt;em&gt;z&lt;/em&gt; каток. Итого максимально может заспавниться &lt;em&gt;x*y*z&lt;/em&gt; декалей. Первые два множителя это данность, константа, факт, принимаем это. Третий множитель на тестах регулируем так, чтобы и крови копилось нормально, и переполнений дерева не возникало. Но вообще для деления дерева до глубины всего лишь пять уже требуется восемь в пятой степени успешных ранений игорьков — это 32 тысячи выстрелов, тридцать две тысячи нажатий ЛКМ при условии что все ниибаца меткие. Поэтому эта тяга с дроблением дерева в бесконечность меня не кошмарила. Алсо в воксели можно записывать их поколение, и просто его ограничить, но я кажется забил хер либо забыл.&lt;/blockquote&gt;
  &lt;p id=&quot;WleO&quot;&gt;Теперь нужно передать массив декалек на GPU и начатьь уже рендорить. Не так быстро, молодой человек. В webGL на тот момент не было никаких буферов, webGPU не существовал даже в открытой бете, прямого пути переправить сраный массив данных из проца в видяху на вебе просто нету. Но есть косой путь — текстуры. Значит надо просто задекодить объекты декалек в наборы пикселей, а на стороне шейдера раздекодить обратно, хуль тут сложного. Тут я особо ничего не делал, собрал пару кодов со стакОверфлоу, они по какой-то причине не работали, починил, бахнул пивасика, посмотрел серик, в то время «дом дракона» только начинался. В общем трансфер данных налажен, остался рендер. И раз уж все брызги крови будут одним и тем же материалом — почему бы их все не рендерить за один дроколл. Просто взять шейдер крови, накинуть сразу на всю геометрию в сцене, а декали использовать как маску для этого шейдера. И как раз количество декалей не будет влиять не перфоманс вообще, и все требования получаются выполнены. Так и сделал, весь левел со старта облит кровью, просто с альфой. Когда кто-то cum blood — декаль затирает маску, и в этом месте материал крови становится непрозрачный.&lt;/p&gt;
  &lt;p id=&quot;8ncy&quot;&gt;Теперь про шейдер. В шейдере по умолчанию всегда можно добыть глобальный позишен обрабатываемого пикселя, так уж оно устроено. Так же там есть массив вокселей, который прилетел с проца, и нулевой в этои массиве — папа всех вокселей. Зная всё это, шейдер спрашивает у папы, есть ли у того доченьки. Если есть, шейдер по позишену сам определяет к кому из дочек обратиться, и обращается. И так до тех пор, пока не найдёт ту, что не разделена. И шейдер пройдётся по всем декалям в ней, и каждой из них подотрёт свою альфу. Здесь выяснился вот такой момент:&lt;/p&gt;
  &lt;figure id=&quot;ePLk&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1e/39/1e39c4f8-1575-479f-8c8b-9fc06de72a9a.png&quot; width=&quot;1143&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;wNDu&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e1/35/e13506b4-5544-4c00-892b-2bc14140f37d.png&quot; width=&quot;663&quot; /&gt;
    &lt;figcaption&gt;Чёрным воксели, красным декаль, зелёным рендер декали.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Av3g&quot;&gt;Центр декали в левом вокселе, там шейдер её находит и рендерит. В правом вокселе шейдер её не находит и не рендерит. Значит вставка декалей в воксели должна происходить по другому принципу. Не в тот воксель, внутри которого находится её центр, а во все воксели, с которыми она интерсектится. Внёс эту правку, на перфоманс не повлияло, всё хорошо. Теперь шейдер всегда понимает в каком пикселе сколько декалей находится.&lt;/p&gt;
  &lt;p id=&quot;xaML&quot;&gt;Ещё нужен мапинг декали на поверхность. Тут инфы в интернете полно, отдельно разжёвывать не буду, взял да замапил. Но в этот дефолтный мапинг я добавил небольшой нюанс — перспективу брызгульки. То есть баундБокс декали расширяется по оси &lt;strong&gt;Z&lt;/strong&gt;, и похож на фрустум камеры. Это как раз для дисперсии с расстоянием. И неожиданно это же делает брызги красивыми, когда они проходят вдоль стены например. То есть два моих выдуманных требования я убил одним зайцем. &lt;/p&gt;
  &lt;figure id=&quot;2u3t&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a3/bf/a3bf5c90-ceb7-41b0-9a5f-7a9e8b21e1b1.png&quot; width=&quot;2332&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XHAT&quot;&gt;Ну и последнее — брызговая маска. Тупо нойз. Обычный сука дженерик нойз, без перлина и без каких-либо выебонов вообще. Яркость нойза уменьшается с расстоянием от центра декали, таким образом капелек к краям становится всё меньше. И с художественной частью кровищи, то есть с обычной и заурядной частью шейдера, я работать особо не стал, тут есть люди, которые сделают это быстрее и красивее меня. А мне требовалось обобщить полученное решение, чтобы брызги крови были в один клик заменяемы на что угодно — лужи, пыль, следы и т.д. Тут уже ничего интересного, это полурутинная работа.&lt;/p&gt;
  &lt;figure id=&quot;yJhO&quot; class=&quot;m_column&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/hDOxHVqArec?autoplay=0&amp;loop=0&amp;mute=0&quot;&gt;&lt;/iframe&gt;
    &lt;figcaption&gt;декали в браузере 60 фпс жесть смотреть.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;p9KS&quot;&gt;Гуманитарная часть.&lt;/h2&gt;
  &lt;p id=&quot;e4Y4&quot;&gt;На момент, когда мне эту задачку поставили, я не знал о внутренности декалей ровно ничего. Знал только, что такая технология существует, юзал декальки когда-то давно в анриле. Полез гуглить как там в плейканвасе с декалями вопрос обстоит. Не нашёл ничего вообще, про это были вопросы на форуме, вопросы без ответов, вопросы с ответвами от разрабов, дескать функционала такого у нас нету и не предвидится, сасайте палка. После я полез гуглить как сделать декали на openGL, нашёл полезную инфу про мапинг декалей, какой-то видос с не очень полезной, но крутой инфой от графоноинженера какой-то трипл-инди хуйни. Но не нашёл ничего, что могло бы мне помочь. Зато начерпавшись вот этой всей рандомной хуерги со всего интернета по запросу «&lt;em&gt;decals openGL&lt;/em&gt;», решение по-тихонечку начало формироваться как будто бы само собой. Я просто сижу, в носу ковыряю, ничего не делаю, а идея приходит. Ну не кайф ли. Кайф. Потом правда приходится эту идею реализовавыть, что в общем-то тоже кайф. А иногда в процессе реализации осознаётся, что идея не рабочая, и нужно ещё поковырять в носу, что снова кайф. Хоспаде, да какой этап разработки не возьми — всё кайф. &lt;br /&gt;Игра, для которой это всё делалось в итоге переехала на юнити, и эти декали канули в хер. Никаких эмоций у меня по этому поводу не возникало, я свой балдёж высосал из разработки до дна.&lt;/p&gt;

</content></entry></feed>