Визуализация для музыкального плеера
Информация в статье затронет тему создания визуализации для музыкального плеера. Так сложилось, что программа была написана на as3, т.к. это язык на котором я сейчас программирую. Все началось из увиденной в плеере AIMP визуализации Phthalo's Corona. Я долго думал как она работает и наконец кое-что придумал. Первый прототип был написан на C++.
В итоге у меня получился только прототип движения частиц как в этой визуализации. На этом я и остановился и через пол года снова захотелось поработать со звуком. Через 2 дня была готова вот такая флешка. ССЫЛКА Клик мыши — сменить режим размытия.
Для того, чтобы она корректно работала, нужно открыть какой-нибудь музыкальный плеер(например в ВКонтакте) в браузере, и закрыть все лишние вкладки с аудио данными, потому что при получении спектральных данных, через SoundMixer.computeSpectrum флешка может вылетать из-за, того что другие приложения не позволяют брать у них аудио данные. Если не падает, то можно ничего не закрывать. Как было замечено, у меня в хроме не ловится звук из других вкладок.
Теперь перейдем к обзору того, как это все работает.
ФизикаВ области расположены частицы(в данном случае 650). 600 активных частиц и 50 частиц, которые появляются в случайной точке области и падают вниз, когда такая частица касается пола, она заново респаунится в области. Само собой на все частицы действует гравитация. По мимо гравитации на частицы можно влиять аттрактором и репульсором. Сейчас я объясню, что это за штуки такие волшебные. На самом деле, они никакие не волшебные, просто названия у них такие же заумные, какими любят выражаться всякие «профессора».
Аттрактор — это такая штука, которая притягивает к себе все, что только можно. В данном случае частицы, причем чем дальше частица от аттрактора, тем слабее она притягивается.
Репульсор — тоже самое, что и аттрактор, только он наоборот отталкивает все от себя.
Так вот, на частицы при определенных условиях(основываясь на звуковом спектре) действует аттрактор и репульсор. Из-за этого они так скачут в области.
ОтрисовкаСоздается bitmapdata для частиц, одна для всех(это логично). Это маленький белый кружок, почему белый объясню ниже.
Рисуются частицы так:
Матрица трансформирует частицы так, что они растягиваются при движении. Ничего сложного.
Эффекты ПалитраПри запуске визуализации, создаются палитры из которых идет выборка цвета при отрисовке конечного изображения(стандартная фитча демокодеров :)
Они рандомно выбираются в процессе работы.
Для работы с палитрой, необходимо заготовить 3 массива размером 256 значений. Это будут массивы для красного, зеленого и синего цветов.
Для того чтобы их задействовать, необходимо воспользоваться функцией paletteMap класса BitmapData. Она получает в качестве параметров как-раз таки эти массивы и исходное изображение.
- берется цвет пикселя из исходного изображения, integer;
- этот цвет разбивается на rgb(byte) компоненты;
- по этим компонентам, берется значение из соответствующего массива, это и будут новые rgb значения;
- новые rgb значения собираются обратно в integer.
При применении блур фильтра, все пиксели будут размываться и в итоге, если ничего не рисовать, они станут черными. При применении палитры, черный заменяется на любой цвет, таким образом при размытии цвет будет плавно переходить в нужный нам цвет(в буфере, в который рисуются частицы, фон останется черным).
Палитра строится так, что в верхних индексах (255 — белый цвет) rgb массивов, записывается цвет частиц, а в нижних (0 — черный цвет) цвет фона. Во всех остальных индексах [1..254] записываются цвета градиента от цвета фона до цвета частицы. Конечно никто не мешает добавить больше 2 цветов в палитру и сделать градиент между ними.
Distortion mapВ оригинальной визуализации, сделано очень интересное завихрение следа частиц. Я долго всматривался в него, чтобы понять как оно работает.
В итоге я пришел к выводу, что это гиперболическая спираль.
Уравнение гиперболической спирали(в полярных координатах): r * phi = a, где a — это скорость расхождения спирали
В декартовых координатах: x = a * cos(phi) / phi, y = a * sin(phi) / phi, где a / phi = r
Встал вопрос как теперь это сделать О_О. Во первых, нужно как-то задать формулу для такого дисторшина, во вторых как это сделать на флеше.
Конечно же сначала я попробовал сделать все по старинке, пройдясь по всем пикселям изображения и сдвинуть пиксели в определенных направлениях, к тому же это позволило бы сразу же туда засунуть и размытие. Но на практике оказалось все намного иначе. Цикл по изображению убивал fps. Пришлось искать другое решение.
В голову пришла идея сделать twirl эффект, сразу нашел код через DisplacementMapFilter. Но это было не то, что было в оригинале.
Пришлось вернутся к обзору гиперболической спирали. Вся трудность заключалась в том, что спираль четко задается через угол и радиус в полярных координатах, а мне нужно было добавить еще один параметр — толщину. В итоге после вывода некоторых формул, я написал алгоритм генерации карты смещений.
Карта смещений строится по такому алгоритму: Пробегаясь по всем пикселям изображения, каждый пиксель проверяется на принадлежность спирали(учитывая толщину). Если пиксель принадлежит спирали, то в этой точке необходимо вычислить смещение.
Для нахождения направления смещения можно взять касательную в данной точке. Для упрощения расчетов я решил находить касательную к окружности в данной точке. При таком подходе, погрешность расчетов будет заметна только в хвосте спирали. Т.к. при увеличении радиуса(или угла) y координата стремится к a, т.е. к линии.
f'(x,y) = ArcTan(y/x) — Pi / 2
Теперь просто находим вектор по полученому углу и умножаем его на коэффициент смещения. В итоге получилась такая карта смещений(используется зеленый и синий каналы)
Во втором режиме, накладывается другая карта смещений которая генерируется шумом Перлина.
Вот такое симпатичное изображение получается на выходе:
Можно было бы добавить больше октав при генерации, но шум генерируется каждый апдейт(для этого и используется смещение октав, для эффекта движения).