Вот такого приблизительно и хотелось
Вот есть тот класс задач, которые слишком просты, чтобы гордиться их выполнением, но одновременно слишком сложные, чтобы это было сделать за пять секунд. И недавно я напоролся на такую задачу.
В сущности мне потребовалась анимация, где условная "земля" покрывается трещинами и потихоньку плавится, образуя условную "лаву" набором мелких картинок 100х100. Ну и, казалось бы, такого должно быть полно, бери да пользуйся готовыми шейдаками/генераторами. Но почему-то готовых решений не нашлось, по крайней мере, на условном гитхабе. То есть немного по-другому было, но того, что хотелось — нет.
Пришлось расчехлить Python и сделать самому. В сущности изначальная идея проста: берём рандомную диаграмму Вороного, конвертируем её рёбра в граф (единственный хак - в питоне немного из scipy геморновато доставать рёбра, но решается добавлением дополнительных точек за пределами диапазона отрисовки), дальше выбираем k рандомных точек ближе к центру и начинаем наращивать условную "температуру". Здесь, конечно, она взята в кавычках, потому что к реальной она не имеет отношения — она скорее описывает интенсивность излучения, которое распространяется на соседние пиксели.
Как влияет условный параметр "температуры"? Ну условно мы считаем расстояние до точки, и если оно меньше максимального значения — то считаем его по несложной формуле линейного убывания (у меня там тупо линейное, но, как мне кажется, можно и другое). В случае дуги всё более геморройно - там надо считать длину до дуги, а потом максимальная длина зависит от условной позиции проекции точки на дугу (чтобы мы условно получали треугольные трещины). В принципе, всё это есть в коде, разобраться не особо сложно. Ну и у самой "температуры" есть контрольные точки, к которым она растёт — 1.0 превращается в красный пиксель, 2.0 — в жёлтый, 3.0 (максимальная) — белый с жёлтым оттенком.
Распространение параметра по графу тоже довольно тривиальная ерунда -—условно, если "температура" вершины больше 1, то делаем у соседней вершины её же за вычетом сопротивления, которое зависит от длины дуги (с учётом максимума).
Сначала я думал, параметр "интенсивности-температуры" хранить в дугах, но оказалось, что это генерит довольно резкие углы и неудобно, а в случае вершин - это даёт возможность управлять как радиусом условного "нагрева" вокруг неё, так и распространением по дуге. В графе, конечно, потом потребовалось немного разбить рёбра, добавив нелинейности, чтобы было более красиво и реалистично, но это мелочь.
Самым замороченным оказался перформанс. Я пошёл по нетривиальному пути, сделав алгоритм, по сути, скорее для GPU — условная логика считается попиксельно (ну я ещё и мультисемплинг подпилил по дороге, чтобы результаты были более гладкие), что замедлялочка, конечно, и её даже мультитрединг не решил (ну отчасти в этом виноват запуск на проце). У меня ещё и по спекам проц оказался здесь не очень, всего 6 аппаратных тредов, спасибо Intel. Отчасти ситуацию спасло пространственное хеширование на регулярной сетке - условно оно отрезало те вершины и рёбра, которые не могли повлиять на пиксели в маленьком регионе. Но, на последних этапах это и стало замедлением - хеш строится однопоточно, что плохое решение.
В целом, результатом доволен, но здесь куча мест для улучшений:
- Лучше бы это всё считать на CUDA, всё-таки 6 тредов хорошо, а условные 1024 тредов - это уже на порядок будет быстрее, даже с учётом варпов и прочего.
- Распараллелить построение пространственного хеша и сделать его инкрементальным - всё же, в силу логики увеличения условной "температуры" в нодах, регионы влияния от дуг и вершин будут только расширяться.
- Вынести настройки цветовой схемы и параллелизма - это пока захардкожено, но это достаточно тривиально.
Делать я это, естественно, не буду. Свою задачу этот скрипт выполнил (правда, 60 кадров генерировались ~90 минут, что не круто), а дальше возиться с этим мне нет смысла. Intel отдельный привет - 6 аппаратных тредов в консьюмерских машинах это, что-то прямиком из 2010.
P.S. Я, конечно, немного тупанул - надо было полазить по форумам/чатам любителей процедурной генерации, но, увы, догадался поздновато. Но там частенько такая свалка, что вряд ли что-то легко нашлось бы.
Комментариев нет:
Отправить комментарий