При разработке 2D-игр часто приходится сталкиваться с покадровой анимацией, и чем выше ее качество, тем больше памяти она потребляет. С этой проблемой мы столкнулись при рендеринге анимации волос персонажа — художники рисуют полсотни кадров чудесной графики с кучей мелких деталей, а это очень быстро занимает всю доступную память.
Мы собрали его, измерили, и получилось 4 текстуры по 16 мегабайт каждая.
Детализация графики того стоит, но для одной анимации это многовато :) Нам нужно это всё упаковать.
Мы подумали об этом и на помощь пришла старая идея частичного обновления изображения — вряд ли вся область изменится во время анимации.
Это значит, что вам нужно разделить картинку на девять частей, взять восемь из базовой и заменить центральную необходимой модификацией.
Как это:
Теперь нам нужно это как-то реализовать.
Рисовать необходимую замену сверху больше не было необходимости — анимация с прозрачностью, а полупрозрачные элементы нельзя наслоить.
Вторая очевидная реализация с рисованием с использованием девяти прямоугольников пронизана шероховатостями на стыках, особенно если есть масштабирование сцены.
В результате нам удалось реализовать наш замысел с помощью шейдеров — мы рисуем один прямоугольник с двумя текстурами и с помощью пиксельного шейдера решаем, где что показывать.
Для реализации такого шейдера нам понадобятся два семплера, две прямоугольные области на соответствующих текстурах и четыре значения — minX, mixY, maxX, maxY, которые будут использоваться для переключения текстур.
Хочу отметить, что координаты прямоугольников на текстурах рассчитываются для полного изображения и для середины будут захватываться соседние кадры - это не проблема, лишние пиксели шейдер вырежет.
Наши четыре параметра можно передать как один вектор из четырех компонентов по следующей схеме:
Далее по этой схеме пишем пиксельный шейдер переключения:
После этого объединяем все кадры в одну текстуру (вместо четырёх!)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); } }
И наслаждаемся анимацией в ответ на движение пальца по экрану без предупреждения о нехватке памяти!
Теги: #OpenGL ES #GLSL #iOS #анимация #разработка для iOS
-
Volkspc — Android И Debian Одновременно
19 Oct, 24 -
Стандарт Доступности Контента Wai-Wcag 1.0
19 Oct, 24 -
Ускорение Opera Mobile 8.65
19 Oct, 24 -
Очиститель Мыслей
19 Oct, 24