Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Алгоритм разбивки спрайтщита на отдельные изображения (http://www.flasher.ru/forum/showthread.php?t=206735)

Parez 26.02.2014 06:21

Алгоритм разбивки спрайтщита на отдельные изображения
 
Здравствуйте.
Появилась необходимость найти/придумать алгоритм, который разделял бы спрайтщит на отдельные изображения (BitmapData) исходя из альфа-канала. Что-то наподобии того, что делает программа Shoebox.
То есть нужно определить, где в спрайтщите заканчивается один фрейм и начинается другой. Фактически, обвести все отдельные непрозрачные области изображения в прямоугольные рамки.
Вот пример того, как это делает Shoebox:
http://www.fotolink.su/pic_s/9b123f5...3c5efb4103.jpg
1036x1038(327.72 kB)
хостинг изображений

Если кому-то интересно, зачем это мне вдруг понадобилось - вот ссылка на тему-предысторию: http://www.flasher.ru/forum/showthread.php?t=206728

Wolsh 26.02.2014 10:56

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

к слову, я бы вообще никакой xml не делал, а печатал ключ прямо на спрайтшите в виде пикселей. Распарсить ключ имхо быстрее чем загрузить и распарсить xml.
Не говоря уже о том, что в PNG можно встроить свой собственный chunk с инфой о кадрах. Ну, это все конечно справедливо, если Вы сами делаете спрайтшиты а не крадете.

caseyryan 26.02.2014 11:16

Цитата:

Не говоря уже о том, что в PNG можно встроить свой собственный chunk с инфой о кадрах. Ну, это все конечно справедливо, если Вы сами делаете спрайтшиты а не крадете.
Ну, я лично ничего плохого не вижу в том, чтобы взять чужой для тестов. Я сам не художник, и когда мне надо по-быстренькому набросать какой-то движок, то я не жду, пока мне нарисуют, а просто беру чужие картинки. Одно дело когда для тестов берешь, а потом заменяешь своим, и уже совсем другое, если в продакшене используешь чужое, без разрешения автора.
Цитата:

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

Wolsh 26.02.2014 11:27

caseyryan, я сильно сомневаюсь, что если бы Вы сами делали спрайтшиты, то создавали бы систему для определения границ кадров по прозрачностям. Уж наверное придумали бы, как сохранить и передать эту инфу. Я уже не говорю о том, что прозрачные области в PNG почти ничего не весят, и непонятен сам подход упихать все как сельдь в банке и потом мучиться с разделением, вместо того чтобы определиться с постоянной ячейкой под каждый кадр и пусть будет пустота, фиг с ней.

silin 26.02.2014 11:36

по всем пунктам согласен с Волшем, но чисто из 'любви к искусству' вариант решения через floodFill: находим непрозрачную точку, флудфилом красим все что с ней соприкасается непрозрачного, через getColorBoundsRect забираем кусок
Код AS3:

package 
{
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.geom.Point;
        import flash.geom.Rectangle;
 
 
        public class Main extends Sprite
        {
                [Embed(source = "test.png")]
                public static const test_png:Class;
                public function Main():void
                {
 
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
 
                        var bmd:BitmapData = Bitmap(new test_png()).bitmapData;
                        addChild(new Bitmap(bmd));
 
                        // типа карта непрозрачности
                        var map:BitmapData = bmd.clone();
                        map.threshold(map, map.rect, new Point(), ">", 0, 0xFF000000, 0xFF000000);
 
                        var tX:Number = 0;
 
                        do
                        {
                                var rec:Rectangle = getFragmentRect(map);
 
                                if (rec)
                                {
                                        // стираем обработанный кусок
                                        map.fillRect(rec, 0x0);
                                        // вынимаем из рабочей ьитмапдаты
                                        var fragmBmd:BitmapData = new BitmapData(rec.width, rec.height, true, 0x0);
                                        fragmBmd.copyPixels(bmd, rec, new Point());
 
                                        // смотрим
                                        var fragm:Bitmap = new Bitmap(fragmBmd);
                                        addChild(fragm);
                                        fragm.x = tX;
                                        fragm.y = bmd.height + 40;;
                                        tX += fragm.width + 40;
 
 
                                }
                        }while (rec);
 
                }
 
 
                public static function getFragmentRect(bmd:BitmapData):Rectangle
                {
 
                        // ищем первый непрозрачный пиксель
                        for (var i:int = 0; i < bmd.width; i++)
                        {
                                for (var j:int = 0; j < bmd.height; j++)
                                {
                                        if (bmd.getPixel32(i, j)>>24)
                                        {
                                                // заливаем каким-то отличным цветом
                                                var clr:uint = 0xFFFF0000;
                                                bmd.floodFill(i, j, clr);
 
                                                return bmd.getColorBoundsRect(0xFFFFFFFF, clr);
                                        }
                                }
                        }
 
                        return null;
                }
        }
 
}


Zebestov 26.02.2014 12:11

Цитата:

Сообщение от Wolsh (Сообщение 1160697)
Я уже не говорю о том, что прозрачные области в PNG почти ~ничего не весят, и непонятен сам подход упихать все как сельдь в банке и потом мучиться с разделением, вместо того чтобы определиться с постоянной ячейкой под каждый кадр и пусть будет пустота, фиг с ней.

Не соглашусь. В PNG да, пустота ничего не весит. Но при разворачивании в памяти пустотой пиксель весит те же 4 байта. К тому же сам размер атласа нужно стараться сдерживать в определенных рамках, допустимых конкретной платформой, чтобы при отрисовке графики поменьше "дергать" текстурами в GPU, что ощутимо влияет на производительность.

А вот подозрения уважаемого Wolsh на воровство контента я разделяю. Если у тебя есть картинка и к ней нет xml/json, это с большой вероятностью означает, что ты качнул ее с блога какого-то разработчика, который делится процессом работы или что-то вроде того.

Babylon 26.02.2014 14:13

Если делится, то это уже не воровство.

Zebestov 26.02.2014 14:26

Babylon не понимает разницы между "делится процессом работы" и "раздает исходники".

Parez 27.02.2014 00:39

Спасибо silin за интересную идею.
Не понимаю, зачем понадобилось разводить холивар по поводу воровства и обвинять меня в нём без особых оснований. Никто даже не догадался подумать, что на просторах интернета есть немало бесплатных спрайтщитов, которыми авторы делятся для таких как я, не умеющих рисовать. Есть и тайлсеты, и анимации персонажей. Это одна из причин, по которой я заинтересовался этим вопросом.
Вторая причина - это просто интерес к теме. Как я сказал в теме-предыстории, я только недавно обратил более пристальное внимание к теме спрайтщитов и их использования. И мне стало интересно (даже не по какой-то объективной причине, а просто из-за спортивного интереса) как можно (и можно ли вообще) автоматизировать процесс работы с абстрактным спрайтщитом, не имея дополнительных данных о нем.
Надеюсь, теперь тут будет больше постов по теме, а не обсуждений правильности того, что я делаю.

p.s
И неужели кто-то из вас думает, что если я соберусь делать какой-то коммерческий продукт, я буду использовать чужую графику? Это в первую очередь плохо для меня и для успеха того, что я буду делать. Если уж я соберусь делать что-то в серьёз, я не пожалею денег заплатить профессиональному художнику аниматору, чтобы он нарисовал для моего приложения УНИКАЛЬНУЮ графику, не скопированную ни от куда. Иначе это не серьёзно. Пока же я просто экспериментирую.

Zebestov 27.02.2014 00:47

Parez, не путай обвинения с обоснованными подозрениями.
Покажи мне ссылку на авторитетные сайты с бесплатными атласами с нерегулярной сеткой и без сопутствующего дескриптора.

Wolsh 27.02.2014 01:41

Цитата:

Пока же я просто экспериментирую.
В том то и дело, что экспериментируете Вы с взломом чужого спрайтшита, к которому у Вас нет ключа. Скачать дистрибутив Adobe Flash тоже не проблема. Но когда Вы начнете искать, как им воспользоваться без ключа, это станет проблемой. Еще проще пример: выйдите на улицу — машин просто толпы. Добрые люди решили поделиться. Правда, ключи почему то не оставили. Видимо, рассчитывают на Вашу смекалку?
В целом это не наезд даже. Я могу понять, что Вам захотелось поиграться, и что для коммерческого проекта Вы не сможете использовать чужой контент даже если захотите. Я вобщем-то говорил о другом: что Вам это все совершенно не нужно. Что если Вы сами будете делать себе спрайтшиты (не Вы так художник), то у Вас будет нужная инфа по границам кадров, и никакой "алгоритм" резки по прозрачностям Вам не понадобится. Он никогда не будет надежен на 100%.
Если просто хочется поиграться с нетривиальными методами битмапдаты, есть много всяких тем.
Например, буквицы. То есть написать класс (метод?), умеющий создавать картинку заданной буквы заданного шрифта, размера и т.п., на прозрачном фоне, но залитую либо цветом, либо градиентом, либо заданной растровой текстурой. И, естественно, обрезанной четко по размеру буквы. И чтобы Ё не становилось Е, а Й — И ;)

Parez 27.02.2014 04:14

Цитата:

Сообщение от Zebestov (Сообщение 1160770)
Parez, не путай обвинения с обоснованными подозрениями.
Покажи мне ссылку на авторитетные сайты с бесплатными атласами с нерегулярной сеткой и без сопутствующего дескриптора.

Ты видел, что я написал? Я могу дать тебе ссылку на сайт с royalty free спрайтщитами и др. графикой. Тот же opengameart.org. Меня уже, если честно, немного напрягает такой подход. Вы здесь расследование что ли провести решили? Не понятно, почему я вообще должен вам что-то объяснять (как и вы, очевидно, не обязаны отвечать на мои вопросы на форуме). Я задал вопрос, который сам по себе не противоречит никаким законам или моралям. Почему я это спрашиваю, как мне кажется, касается только меня. Насколько я знаю, на подобных форумах ответы вроде "а зачем тебе это" считаются дурным тоном.
Заданный вопрос звучит вполне конкретно и я не затем его задавал, чтобы "слушать" нравоучения.
Спасибо.

Добавлено через 14 минут
Цитата:

Сообщение от Wolsh (Сообщение 1160778)
В том то и дело, что экспериментируете Вы с взломом чужого спрайтшита, к которому у Вас нет ключа. Скачать дистрибутив Adobe Flash тоже не проблема. Но когда Вы начнете искать, как им воспользоваться без ключа, это станет проблемой. Еще проще пример: выйдите на улицу — машин просто толпы. Добрые люди решили поделиться. Правда, ключи почему то не оставили. Видимо, рассчитывают на Вашу смекалку?
В целом это не наезд даже. Я могу понять, что Вам захотелось поиграться, и что для коммерческого проекта Вы не сможете использовать чужой контент даже если захотите. Я вобщем-то говорил о другом: что Вам это все совершенно не нужно. Что если Вы сами будете делать себе спрайтшиты (не Вы так художник), то у Вас будет нужная инфа по границам кадров, и никакой "алгоритм" резки по прозрачностям Вам не понадобится. Он никогда не будет надежен на 100%.
Если просто хочется поиграться с нетривиальными методами битмапдаты, есть много всяких тем.
Например, буквицы. То есть написать класс (метод?), умеющий создавать картинку заданной буквы заданного шрифта, размера и т.п., на прозрачном фоне, но залитую либо цветом, либо градиентом, либо заданной растровой текстурой. И, естественно, обрезанной четко по размеру буквы. И чтобы Ё не становилось Е, а Й — И ;)

Грубо говоря, вы правы. Мне это, возможно, не пригодится в реальности. В данном случае я действительно просто хочу "поиграться с нетривиальными методами битмапдаты". +Если уж говорить об использовании чужих спрайтщитов, я так же хочу посмотреть (чисто для того, чтобы порадовать глаз), как какие-нибудь из моих проектов в теории будут смотреться с нормальной графикой. Разумеется, не для коммерческого использования. А в том, чтобы использовать подобные изображения в личных целях, на сколько я знаю, нет ничего незаконного. Фактически, я их просто смотрю.
Создавая тему, я надеялся, что получится обсудить варианты создания подобного алгоритма с опытными флэшерами, имеющими дело с подобными вещами, но никак не обсуждать моральные аспекты использования чужого артворка в личных целях.

Wolsh 27.02.2014 09:11

Мне тоже жаль, что Вы так и не поняли.
— Скажите мне, опытные люди, как выпить молоко молотком?
— О____________о Чаво???
— Вот только не надо! Ежу же понятно, молоток и молоко! Как?
— Да никак. Ну, то есть, можно конечно разбить бутылку и потом слизывать, но это будет очень долго и опасно. Лучше вот, трубочку возьмите.
— Эх вы! Я то надеялся поговорить со знающими людьми о правильном алгоритме питья молока молотком, а вы!

Вы поставили бессмысленную задачу. "Опытные флэшеры" сказали Вам, что она бессмысленная. Спрайтшиты придумали не для того, чтобы устраивать себе геморрой в рантайме. Вы ответили, что это такая игра, научиться делать что-нибудь бессмысленное. Силин Вам подыграл даже.
Удачи.

Инспектор_Котик 27.02.2014 14:47

Цитата:

Сообщение от Zebestov (Сообщение 1160770)
Parez, не путай обвинения с обоснованными подозрениями.
Покажи мне ссылку на авторитетные сайты с бесплатными атласами с нерегулярной сеткой и без сопутствующего дескриптора.

я скачивал отсюда http://www.spriters-resource.com/ правда там иногда кривые попадаются.

Zebestov 27.02.2014 14:56

Ресурс, предоставляющий лишь графику, надерганную из разных игр. Я спрашивал не о подобных помойках.

Инспектор_Котик 27.02.2014 15:11

А чем подобные помойки плохи для тренировок? Мне кажется для пробы пера вполне себе полигон для испытаний.

Zebestov 27.02.2014 15:19

Wolsh выше описал всю "ценность" этих тренировок.

silin 27.02.2014 15:28

Вложений: 1
а вот та же задачка, но для картинок с пересекающимися ректанглами
как бы еще более бессмысленное дело в контексте спрайтшитов, но пусть тоже будет раз уж
Код AS3:

package
{
        import flash.display.*;
        import flash.geom.*;
 
        public class Main extends Sprite
        {
                [Embed(source="test.png")]
                public static const test_png:Class;
 
                public function Main():void
                {
 
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
 
                        var bmd:BitmapData = Bitmap(new test_png()).bitmapData;
                        addChild(new Bitmap(bmd));
 
 
                        //разбиваем
                        var arr:Array = splitBitmapByAlpha(bmd);
 
                        // смотрим
                        var tX:Number = bmd.width + 10;
                        graphics.lineStyle(0, 0xC0C0C0);
                        for (var i:int = 0; i < arr.length; i++)
                        {
                                var fragm:Bitmap = new Bitmap(arr[i]);
                                addChild(fragm);
                                fragm.x = tX;
                                fragm.y = 10;
 
                                tX += fragm.width + 10;
                                graphics.drawRect(fragm.x, fragm.y, fragm.width, fragm.height);
                        }
 
                }
 
                public static function splitBitmapByAlpha(bmd:BitmapData):Array /*BitmapData*/
                {
 
                        var res:Array = [];
                        var w:int = bmd.width;
                        var h:int = bmd.height;
                        var k:int = 0;
                        var p0:Point = new Point();
 
                        // карта непрозрачности
                        var map:BitmapData = bmd.clone();
                        map.threshold(map, map.rect, p0, ">", 0, 0xFF000000, 0xFF000000);
 
 
                        // пока битмап не пустой
                        while (map.getColorBoundsRect(0xFF000000, 0x0, false).width)
                        {
                                // ищем следующую непрозрачную точку
                                while (!map.getPixel32(k % w, k / w)) k++;
 
                                // заливаем красным
                                map.floodFill(k % w, k / w, 0xFFFF0000);
                                // берем что залилось как маску
                                var mask:BitmapData = new BitmapData(w, h, true, 0x0);
                                mask.copyChannel(map, map.rect, p0, BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
                                // фрагмент
                                var fragmRect:Rectangle = mask.getColorBoundsRect(0xFF000000, 0x0, false);
                                var fragmBmd:BitmapData = new BitmapData(fragmRect.width, fragmRect.height, true, 0x0);
                                // вынимаем  по маске из основного
                                fragmBmd.copyPixels(bmd, fragmRect, p0, mask , fragmRect.topLeft);
                                // удаляем  отработанный кусок
                                map.threshold(mask, mask.rect, p0, "==", 0xFF000000, 0x0, 0xFF000000);
                                mask.dispose();
                                res.push(fragmBmd);
 
                        }
 
                        map.dispose();
                        return res;
                }
 
        }
 
}

upd. небольшая оптимизация (нет нужды искать на каждой итерации по всей карте, а можно продолжать от предыдущей)
alphaSplit.swf   (29.9 Кб)

Wolsh 27.02.2014 16:04

Мощно! ;)

Hauts 27.02.2014 20:35

Завидую столь крутым алгоритмическим навыкам Силина. Не знаю зачем, но сохраню себе.

Inet_PC 27.02.2014 21:28

Силин, круто!

Parez 27.02.2014 23:20

Цитата:

Сообщение от Wolsh (Сообщение 1160794)
Мне тоже жаль, что Вы так и не поняли.
— Скажите мне, опытные люди, как выпить молоко молотком?
— О____________о Чаво???
— Вот только не надо! Ежу же понятно, молоток и молоко! Как?
— Да никак. Ну, то есть, можно конечно разбить бутылку и потом слизывать, но это будет очень долго и опасно. Лучше вот, трубочку возьмите.
— Эх вы! Я то надеялся поговорить со знающими людьми о правильном алгоритме питья молока молотком, а вы!

Вы поставили бессмысленную задачу. "Опытные флэшеры" сказали Вам, что она бессмысленная. Спрайтшиты придумали не для того, чтобы устраивать себе геморрой в рантайме. Вы ответили, что это такая игра, научиться делать что-нибудь бессмысленное. Силин Вам подыграл даже.
Удачи.

В олимпиадах по программированию, например, тоже полно бессмысленных задачек, но подумать над некоторыми из них бывает очень интересно. Испытываю большое уважение к Silin. Пусть у задачи и нет прикладного смысла, но он не побрезговал её решить. Настоящий программист с мощной алгоритмической базой. Присоединяюсь к словам Hauts.
Спасибо, Silin.

Hauts 28.02.2014 06:54

Еще раз перечитав тему, задался вопросом, — а можно ли загонять описания (хмл или джэйсон) в мета-данные изображения? Получится ведь один валидный файл изображения с вшитой инфой о текстурках.


Часовой пояс GMT +4, время: 23:38.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.