Покадровая Анимация И Шейдеры В Ios

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

Мы собрали его, измерили, и получилось 4 текстуры по 16 мегабайт каждая.

Детализация графики того стоит, но для одной анимации это многовато :) Нам нужно это всё упаковать.

Мы подумали об этом и на помощь пришла старая идея частичного обновления изображения — вряд ли вся область изменится во время анимации.

Это значит, что вам нужно разделить картинку на девять частей, взять восемь из базовой и заменить центральную необходимой модификацией.

Как это:

Покадровая анимация и шейдеры в iOS

Теперь нам нужно это как-то реализовать.

Рисовать необходимую замену сверху больше не было необходимости — анимация с прозрачностью, а полупрозрачные элементы нельзя наслоить.

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

В результате нам удалось реализовать наш замысел с помощью шейдеров — мы рисуем один прямоугольник с двумя текстурами и с помощью пиксельного шейдера решаем, где что показывать.

Для реализации такого шейдера нам понадобятся два семплера, две прямоугольные области на соответствующих текстурах и четыре значения — minX, mixY, maxX, maxY, которые будут использоваться для переключения текстур.

Хочу отметить, что координаты прямоугольников на текстурах рассчитываются для полного изображения и для середины будут захватываться соседние кадры - это не проблема, лишние пиксели шейдер вырежет. Наши четыре параметра можно передать как один вектор из четырех компонентов по следующей схеме:

Покадровая анимация и шейдеры в iOS

Далее по этой схеме пишем пиксельный шейдер переключения:

   

precision mediump float; uniform sampler2D u_texture; // base texture uniform sampler2D u_overlay; // overlay texture uniform vec4 u_overlayRect; // in texture coordinates (minX, minY, maxX, maxY) varying vec4 v_fragmentColor; varying vec2 v_texCoord; // base texture coordinates varying vec2 v_overlayTexCoord; // extrapolated overlay texture coordinates void main() { if (v_overlayTexCoord.x > u_overlayRect.x && v_overlayTexCoord.y > u_overlayRect.y && v_overlayTexCoord.x < u_overlayRect.z && v_overlayTexCoord.y < u_overlayRect.w) { gl_FragColor = v_fragmentColor * texture2D(u_overlay, v_overlayTexCoord); } else { gl_FragColor = v_fragmentColor * texture2D(u_texture, v_texCoord); } }

После этого объединяем все кадры в одну текстуру (вместо четырёх!)

Покадровая анимация и шейдеры в iOS

И наслаждаемся анимацией в ответ на движение пальца по экрану без предупреждения о нехватке памяти!

Покадровая анимация и шейдеры в iOS

Теги: #OpenGL ES #GLSL #iOS #анимация #разработка для iOS
Вместе с данным постом часто просматривают: