Хочу поделиться с вами своим небольшим начинанием на арене Android-разработки и немного рассказать о интересных моментах реализации.

Долго думал и решил начать свой путь с персонализации и живых обоев. Согласен, что эта область достаточно ограничена по сравнению, скажем, с играми, но в тоже время она оставляет авторам возможность продемонстрировать пользователю некоторую идею. Мне хотелось сделать, прежде всего, что-то интересное с точки зрения программирования, ну и не совсем обычное.

Получилось следующее:



Немного о реализация


Симуляция, рендеринг и часть интерфейса написанны на C++.

Симуляция основана на системе частиц и динамике, описанной в статье Particle-based Viscoelastic Fluid Simulation. Алгоритм немного упрощен и реализован для двуxмерного случая. Исходя из того, что вся система строится на взаимодействие частицы со своим окружением, наиболее важной частью является механизм поиска этого окружения. Рассмотрим этот поиск немного детальнее.

Итак, на входе мы имеем массив частиц, каким-либо образом распределенных в пространстве. Наша цель — для каждой частицы перебрать все соседние с ней, находящиеся на некотором фиксированном растоянии R.

Чтобы избежать полного перебора, мы разобьем пространство на ячейки одинакового размера. Это позволит искать потенциальных соседей не среди всех частиц, а только среди тех, которые принадлежат смежным ячейкам. Размер ячейки выбирается кратным расстоянию R.

image

Далее, мы сортируем наш массив по ячейкам с помошью Сортировки подсчетом (Counting sort) . Помимо скорости, сортировка подсчетом дает, необходимый нам, набор частичных сумм (для каждой ячейки мы будем знать количество частиц расположенных в предыдущих).

image

Теперь, чтобы перебрать всех потенциальных соседей, нам необходимо последовательно прочитать нужные интервалы(количество зависит от изначального выбора размера ячейки) в массиве. Смещения до нужных элементов вычисляются тривиально на основании частичных сумм полученных в процессе сортировки. В нашем примере это полуинтервалы: [0, 3), [4, 9), [11, 14), для размера ячейки, совпадающего с расстоянием R.

После сортировки, следуя динамике из упомянутой выше статьи, обновляются позиции всех частиц. Обновленные данные отсылаются на рендеринг. Что касается количества частиц, учавствующих в симуляции, то здесь их немного, всего 1000 на максимальном уровне качестве.

Рендеринг

Основан на OpenGL ES 2.0. Состоит из 9 проходов (блюр 2х проходный вертикальный/горизонтальный).

  1. В отдельную текстуру (меньшую по размеру чем разрешение экрана, размер определяется настройками качества) спрайтами рисуем все частицы:
    Результат
    image
  2. Размытие с большим коэффициентом:
    Результат
    image
  3. Обрезаем ненужное (на основе интенсивности) и формируем поверхность:
    Результат
    image
  4. Размытие с небольшим коэффициентом;
  5. Размытие с небольшим коэффициентом. За один проход не удалось достичь нужного эффекта без появления артефактов:
    Результат
    image
  6. Последним проходом отрисовываем поверхность вместе с фоном. Также, на основе интенсивности расчитываются нормали.
    • Рефракция:
      Результат
      image
    • Внутрение и внешние тени:
      Результат
      image
    • Смешивание:
      Результат
      image
    • Освещение:
      Результат
      image
В самом конце отрисовывается нативный интерфейс.

Интерфейс

Наличие нативного интерфейса было продиктованно необходимостью. Дело в том, что живые обои могут отображаться в двух режимах

  • Home or/and Lock Screen;
  • Preview;

С первым режимом все хорошо, а вот в режиме preview активность ведет себя не стандартным образом. В этом режиме, при перекрытие, цикл обновления и отрисовки живых обоев останавливается. Причем неважно чем мы перекрываем (я не смог найти разумное объяснение такому поведению). Как следствие, использование для настройки полупрозрачных android-диалогов, не позволит нам сохранить нужную интерактивность.

Буду рад Вашим комментариям и отзывам. Спасибо!

Комментарии (3)