PDA

Просмотр полной версии : Нетривиальная задача по оптимизации графики


s8000_1
09.06.2012, 17:40
Всем привет.

Есть боёвка, в ней присутствуют юниты. Юнитов примерно 10 на бой. Каждый юнит может хитро атаковать, у юнита 3 атаки. Как конкретно - см. fla во вложении, символ в библиотеке, например, unit5_Las_vegas_attack3_shot.

Проблема в том, что на слабых ноутах даже одна такого рода комплексная анимация, проигрываемая единовременно, снижает fps с 31 до 20. Потому встала задача оптимизировать графику и её воспроизведение.

Пошел по пути растеризации векторной графики.

cacheAsBitmap

Не работает, просто потому, что в анимациях в 90% экземплярах мувиков используются трансформации масштаба и поворот

отрисовка кадров мувиклипов через draw

Проблема 1.

Чтобы сфотографировать все кадры, необходимо проиграть мувиклип полностью и в обработчике enter_frame делать draw. Через gotoAndStop() я не смог добиться того, чтобы мувиклип стал таким, каким он реально в находится этом кадре вместе со своими детьми. Приходится делать stage.invalidate() и ждать события Event.RENDER, которое приходит всё равно через кадр. Поэтому время отрисовки всех атак всех юнитов равно сумме времени воспроизведения каждой атаки. Можно делать параллельно, это сокращает время раза в три, но не более того. Среднее время атаки 6 секунд, и в 3 параллельных потока оно будет рендерить графику ~= 1 минуту, а это очень долго для игры, т. к. бои частые.

Вопрос 1.

Есть ли какое-либо решение, которое мувиклип со всеми детьми отрисовывает быстрее, чем время проигрывания этого мувиклипа?

Проблема 2.

Если отрисовать всю атаку как есть, т. е. без каких-либо оптимизаций, на весь кадр атаки, то получившаяся BitmapData занимает около 100 мб памяти. 30 анимаций никак не уместишь в максимально допустимую память 500 мб. При таком подходе сохраняется очень много полупрозрачностей, поэтому я немного помянял способ сохранения - не таймлайн главного мувиклипа, а "фотки" детей в своих границах. Объем получилось сократить до 50 мб, но это всё равно много. Если перейти еще на более глубокий уровень и фотографировать не детей, а детей детей, то я не уверен, что это позволит сильно сократить объем, а уж тем более увеличить какую-либо производительность.

Пробовал хранить данные не в BitmapData, а в ByteArray, предварительно сконверченным через PNEncoder2 (самый быстрый, судя по тестам). Объем становится приемлемым (~15мб), раскодировка всех картинок (порядка 1500) loader'ом очень быстрая, работает замечательно. Но конвертор в PNG каждую атаку конвертирует очень долго, и время пререндера увеличивается еще раза в три. А три минуты ожидания пререндера тоже неприемлемы для игроков.

По этой же причине не можем хранить все пререндеры в asset'ах. Очень много весит.

Вопрос 2.

Есть ли способы как-то уменьшить объем сложных анимаций в памяти и решить проблему2?

Использование GPU и фреймворка starling

Проблема 3.

Можно сделать свой конвертор мувиклипов, который превращает классы детей этого мувиклипа в текстуры, сохраняет информацию о трансформации детей и плеер, который создает starling.display.MovieClip'ы из этих текстур и располагает в правильных трансформациях. Проблема оперативной памяти будет не такой острой, т. к. сохраняются нетрансформированные текстуры, которые переиспользуются и трансформируются.

Проблема долгого времени конвертации остаётся.

Но я не тестировал этот вариант как очень сложный, и не уверен, что starling-мувики из текстур поворачиваются/трансформируются с хорошим качеством + будут быстрее.

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

Вопрос 3.

Наверняка я не первый, кто столкнулся с подобной проблемой. Может быть где-то есть какой-нибудь класс для starling'а, которые конвертят мувиклипы как есть и проигрывают их?

Вопрос 4.

Есть ли ещё способы увеличить производительность такой графики? Мне тут сообщили, что в игре "Легенда" вообще каждый слой игрового мира - отдельная флэшка на html. Но не факт, что это было сделано из-за производительности, скорее из-за того, что какие-то куски игры написаны на as2.

Hauts
09.06.2012, 17:58
Попробуйте растеризовать покадрово.

wvxvw
09.06.2012, 18:02
Ну как-то я бы даже не думал о том, чтобы конвертировать картинки в рантайме. Один раз записать и с ними скомпилировать. Можно их записывать не каждую по отдельности, а как видео, и соответственно так и проигрывать. Если видео встроено в MovieClip то внутри можно делать переход по кадрам так же, как в клипе. Но я не думаю, что разнича между встраиванием картинок и видео будет значительной.
Как я видел, что это делают:

клипы с последовательностями картинок.
большие картинки с раскадровкой, по которым потом перемещаются с помощью scrollRect.
видео.

Со старлингом работать не приходилось.

Hauts
09.06.2012, 18:08
По-моему, старлинг растеризует клипы. Поэтому, думаю, вам лучше попробовать программно растеризовать анимацию и посмотреть на разницу в скорости, должно быть быстрее. А потом уже и попробовать к старлингу прикрутить.

s8000_1
09.06.2012, 18:10
wvxvw, раскадровка всего клипа "в лоб" - это около 5 мб картинок. Соответственно, 1 юнит = 15 мб, 10 юнитов - 150 мб, 150 мб обычно грузить дольше, чем в рантайме то же самое переконвертить. Если делать раскадровку не в "лоб", а делать раскадровки детей, чтобы было поменьше картинок, и их трансформировать, то производительность не увеличивается.

Про видео я как-то не задумывался, надо будет попробовать. Не знаете, как movieCilp сохранить в видео? Я навскидку во флэше не нашел кодировщика, использовать внешние?

Добавлено через 2 минуты
Hauts, про растеризацию я целую проблему 1 (тм) написал :) А старлинг не работает с обычными мувиками, ему нужны раскадровки. Просто этот способ очень долгий для теста и не факт, что получится как надо. Потому и спросил, может, кто уже написал конвертор/плеер.

Hauts
09.06.2012, 18:15
Сохранить в видео с прозрачностью проще всего перегнав последовательность .png, полученных программно и потом уже в видео собраных. Если просто из флэша экспортом пользоваться — анимация вложеных клипов будет проигнорирована.

Раскадровка "в лоб" и не нужна. Храните вектр, работайте с растром, получите и относительно небольшой вес и производительность в рантайме. Вот только растеризация займет некоторое время, плеер подвиснуть может.

s8000_1
09.06.2012, 18:19
Hauts, именно про это я и написал в проблеме 1. Растеризация рантайм = 3 минуты ожидания игрока, что плохо.

TanaTiX
09.06.2012, 18:29
А если пойти путем разделения и упрощения анимации. В приведенном примере я видел какое-то подобие выстрела. Может его реализовать отдельным объектом - так размер битмапы явно уменьшиться. За счет этого можно выиграть в количестве потребляемой памяти.

samana
09.06.2012, 18:31
Посмотрите ещё и на вариант (http://www.ant-karlov.ru/iz-vektora-v-rastr.html) Антона.

wvxvw
09.06.2012, 19:13
15 Мегабайт картинок, это даже с сжатием? Это как-то очень много даже для полноценной десктопной игры... Откуда их столько? Сорри, я не могу флешку отркыть - нечем.

s8000_1
09.06.2012, 19:21
wvxvw, ну там около того, плюс минус. 1 атака 1 юнита - ~200 кадров 500х500, если с прозрачностями. Даже, если кадр занимает 25кб, что мало, вес одной сжатой анимации получается 5 мб :) В векторе всё 200кб занимает суммарно для 1 юнита. Но притормаживает на слабеньких ноутах.

Добавлено через 30 минут
samana, проверил вариант Антона, он страдает всеми теми недостатками, что я описал, для больших сложных анимаций не годится.

Добавлено через 25 часов 35 минут
Затестил starling. Производительность х10, экономия памяти в два раза, т. к. оно как-то хитро жмет текстуры. Отныне буду использовать только его.

upd. Нет, не буду. Собрал стату в своих играх, у 34% юзеров или нет 11 плеера, или software rendering :(