Комментарии 38
Трава лишь немного изменила оттенок, с этим можно смириться, но вот камни пострадали критически.
Фиг с ними с камнями, там на небе вылезли адские артефакты!
На самом деле вопрос-то в другом. А какой смысл jpg использовать? В видеопамяти это всё-равно не будет храниться в jpg. Да и для пиксельарта png явно предпочтительнее будет.
0
На небо я специально попросил не смотреть.) У меня не стандартный загрузчик. было проще на всё формат поменять, поэтому небо пострадало. В рабочем коде небо выглядит как в версии RGB888.
Про jpg я даже придумал, зачем. Например, фотография человеки на прозрачном фоне в png может занять на диске больше. Мне не нужно, но вдруг.
Про jpg я даже придумал, зачем. Например, фотография человеки на прозрачном фоне в png может занять на диске больше. Мне не нужно, но вдруг.
0
Для этого есть формат DXT.
В своё время еще S3 компания придумала такую штуку как S3TC — сжатые в видеопамяти текстуры. Как раз для экономии видеопамяти, их сейчас вроде бы все карточки поддерживают.
Касаемо решаемой у вас проблемы — надо создавать текстуру в A1R5G5B5 формате и прямо при загрузке задавать альфу. То есть ваш шейдер применить при загрузке совтово. Вы и на памяти экономить будете и еще не будете ронять производительность ифами в шейдере.
А чтобы выровнять гамму, можно как раз таки создать палитру и в шейдере проводить цветокоррекцию, чтобы цвета были идентичны тем, что в 8888 версии.
В своё время еще S3 компания придумала такую штуку как S3TC — сжатые в видеопамяти текстуры. Как раз для экономии видеопамяти, их сейчас вроде бы все карточки поддерживают.
Касаемо решаемой у вас проблемы — надо создавать текстуру в A1R5G5B5 формате и прямо при загрузке задавать альфу. То есть ваш шейдер применить при загрузке совтово. Вы и на памяти экономить будете и еще не будете ронять производительность ифами в шейдере.
А чтобы выровнять гамму, можно как раз таки создать палитру и в шейдере проводить цветокоррекцию, чтобы цвета были идентичны тем, что в 8888 версии.
0
Вообще и камни должны бы выглядеть нормально. Если бы рисовались под такой формат изначально (что для пиксельарта логично вполне, он же канонично палитровый). Автоматика при сильном сжатии цветового пространства очень портит картинку.
0
В файле на диске всего 32 цвета и он занимает 20 килобайт. Но Андроид не умеет в палитры, поэтому 32 цвета из палитры в видеопамяти превращаются в 32 бита на пиксель. Вручную красивее перерисовать не получится, потому что банально нет другого цвета, т.е. нельзя оттенки использовать, потому что их нет. Всего 4 бита на канал.
0
Кажется дошло откуда проблема. Там не палитра, а просто обрезанная компонента.
А передавать в шейдер палитру отдельной текстурой нельзя?
А передавать в шейдер палитру отдельной текстурой нельзя?
0
Можно! Это уже тема для следующей статьи.) Там ещё вдвое можно использование памяти уменьшить, но несколько усложняется подготовка файлов. Нужно выгружать палитру в отдельный полноцветный файл, сохранять текстуру в градациях серого и сохранять во второй файл (андроид поддерживает однобайтные текстуры альфа-канала, который можно использовать не как альфа-канал). А потом уже в шейдере брать тексель из серой текстуры и по его значению брать цвет из текстуры-палитры.
Зато становятся доступны все фишки использования палитр и даже больше.
Зато становятся доступны все фишки использования палитр и даже больше.
0
Без условного оператора можно сделать так: gl_FragColor.a = (float)(pixel.rgb != vec3(1.0,0.0,1.0));
0
А это мысль! bool приводится к float в шейдерах? Я ж только учусь…
0
но лучше протестировать, как будет быстрее. возможно, отключение блендинга и discard с условием будет производительнее
0
Проверил. В GLESv2 такое не компилируется.(
0
Про discard отличная идея! Можно не умножать цвет текселя на цвет вершины, если она прозрачна. Спасибо, дополню статью.
0
Лучше замерить производительность в стресс-тестах (очень много спрайтов с прозрачностью, сотни тысяч) на мобильных устройствах в режимах с условием, без условия и discard без блендинга (отключение режима прозрачности). Тогда статья будет еще полезнее.
0
Отключение умножения не поможет — насколько я знаю, шейдер все равно выполняется весь, без разницы, в каком месте произойдет discard. Думаю, если я не прав, меня поправят.
0
Действительно, про discard пишут о критическом падении скорости, в зависимости от оборудования и вариантов использования. Всё сложно.) Если соберусь проверить производительность разных вариантов прозрачности, обязательно напишу статью.
0
можно же так, чтобы обе прозрачности учитывались
gl_FragColor.a = pixel.a * float(pixel.rgb != vec3(1.0,0.0,1.0));
gl_FragColor.a = pixel.a * float(pixel.rgb != vec3(1.0,0.0,1.0));
+1
Думаю, это — ответ победитель.) Слегка подправил, чтобы прозрачность вершины тоже учитывалась и всё встало на свои места. Даже немного стыдно, что до столь простого варианта сам не додумался.
0
Ничего страшного, все приходит с опытом. Есть некоторые вопросы, на которые не могут ответить бывалые программисты.
0
Ох, вы на меня потратили первый комментарий за 4 года… Я тут тоже почти бесправный, поэтому могу отблагодарить за подсказку только искренним Спасибо!
0
Все верно — discard ломает всю внутреннюю оптимизацию для любых «tile-based deferred rendering»-gpu, например, всех power sgx-ы (а это все девайсы мобильные девайсы apple). Поэтому тот же альфа-блендинг предпочтительнее по скорости, чем discard по условию. Почитать подробнее можно, например, вот тут: http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-TileBasedArchitectures.pdf.
0
Не понял. А для чего это надо? Картинки в png с прозрачностью и все работает.
0
4 байта на пиксель, против 2-3 байт с использованием шейдера. Только для экономии видеопамяти.
0
Я не понимаю как вы экономите… формат 4444 у вас, так?
Значит вы резервируете по 4 бита на пиксель на прозрачность, которую не используете. И при этом урезаете по паре бит.
Значит вы резервируете по 4 бита на пиксель на прозрачность, которую не используете. И при этом урезаете по паре бит.
0
0
Я просил не смотреть на небо.) В игре оно загружается в формат 565 и качество не страдает. Речь только о текстурах уровня, а там всего 32 цвета изначально, никакой дизеринг не поможет — разрядности не хватает.
Результат 4444 выглядит так, будто вы просто уменьшили количество цветов, а не уменьшили разрядность. В чём ужимали цвета?
Результат 4444 выглядит так, будто вы просто уменьшили количество цветов, а не уменьшили разрядность. В чём ужимали цвета?
0
Результат 4444 выглядит так, будто вы просто уменьшили количество цветов, а не уменьшили разрядность
Уменьшил именно разрядность, но сохранил для простоты в обычный RGB8888. Использовал свой варварский метод:
for (int i = 0; i < pixCount; i++)
{
// RGBA5651
int r = pix[i].r & 0xF8;
int g = pix[i].g & 0xFC;
int b = pix[i].b & 0xF8;
pix[i].r = qrand() % 8 > pix[i].r - r ? r : r + 7;
pix[i].g = qrand() % 4 > pix[i].g - g ? g : g + 3;
pix[i].b = qrand() % 8 > pix[i].b - b ? b : b + 7;
// RGBA4444
// int r = pix[i].r & 0xF0;
// int g = pix[i].g & 0xF0;
// int b = pix[i].b & 0xF0;
// int dr = pix[i].r - r;
// int dg = pix[i].g - g;
// int db = pix[i].b - b;
// pix[i].r = qrand() % 16 > dr ? r : r + 15;
// pix[i].g = qrand() % 16 > dg ? g : g + 15;
// pix[i].b = qrand() % 16 > db ? b : b + 15;
}
0
Вот! Вы вот правильно округлили до ближайшего, а автоконверт округляет до меньшего, поэтому в данном случае искажения цвета получились сильнее. В оригинале цвет rgb(42;30;37) был округлён до rgb(34;17;34). Странные цифры из-за float. Если нормально округлить до (48;32;32), то выглядит более прилично даже без дизеринга.
Но принципиально ничего не изменилось: RGB444 — 4096 цветов, RGB565 — 65535 доступных цветов.
Но принципиально ничего не изменилось: RGB444 — 4096 цветов, RGB565 — 65535 доступных цветов.
0
Способ округления и формулы дизеринга — это достойно отдельной статьи.
В вашем случае можно вообще написать свой конвертер, благо это просто и быстро. 32 цвета — это 5 бит, ну пусть 6 вместе с битом прозрачности. Хотя можно пожертвовать одним цветом для хромакея. В итоге один конвертер будет переводить картинку в массив пикселей по 5 бит на штуку (на этапе разработки и компоновки ресурсов игры), а другой (в клиенте игры) разжимать все это обратно в любой удобный формат. Вполне вероятно, что такой массив данных удачно сожмется каким нибудь RLE.
Но это, конечно, не изменит размер данных в оперативке, просто уменьшит вес клиента.
В вашем случае можно вообще написать свой конвертер, благо это просто и быстро. 32 цвета — это 5 бит, ну пусть 6 вместе с битом прозрачности. Хотя можно пожертвовать одним цветом для хромакея. В итоге один конвертер будет переводить картинку в массив пикселей по 5 бит на штуку (на этапе разработки и компоновки ресурсов игры), а другой (в клиенте игры) разжимать все это обратно в любой удобный формат. Вполне вероятно, что такой массив данных удачно сожмется каким нибудь RLE.
Но это, конечно, не изменит размер данных в оперативке, просто уменьшит вес клиента.
0
Статья как раз об уменьшении данных в оперативке. С занимаемым местом на диске проблем как раз нет. Файл из примера на диске занимает 20 килобайт, а в памяти 1 мегабайт. Использование 565 с прозрачным цветом уменьшает до 512 килобайт. Если текстур много, то для не самых новых девайсов это будет существенная разница. В данный момент на диске все текстуры занимают 400 килобайт (и можно ещё ужать), а в памяти уже 5 мегабайт. С данным шейдером они уменьшаются до 2.5 мегабайт. Некоторые текстуры будут пережаты в ETC1, чтобы в памяти ещё меньше занимать.
0
Немного не правильно посчитал, забыл умножить на 4 байта. 400КБ на диске в памяти занимают 20 мегабайт. В формате 565 с colorkey занимают 10 мегабайт.
0
Я, может быть, скажу сейчас какую-нибудь глупость… Но если цветов всего 20, может быть имеет смысл упаковать текстуру в любой формат, самый наименьший. А шейдеру подсовывать палитру для коррекции, одномерную текстуру. Или просто настроить коррекцию по палитре. Будет идеальный цвет на выходе и минимальная разрядность тестуры в памяти. В вашем случае в 1 8888 текстуру можно было бы упаковать в каждый канал по 1 спрайту, у которого будет по 256 цветов + палитра. Экономия выйдет больше, точность идеальная.
0
Совершенно верно! Так и сделано в самой игре, но это тема для второй статьи. Плюс, там рассказывается, как именно подготовить текстуру, чтобы она занимала 1 байт на пиксель. Просто это намного сложнее, чем кажется (нет нативной поддержки палитризованных изображений), поэтому это будет отдельная статья. Вернее, с точки зрения программирования сложностей никаких, но вот подготовить текстуру индексов и текстуру с палитрой не так просто, как хотелось бы.
Плюс в игре реализованы некоторые визуальные эффекты за счёт динамического изменения палитры. Но я сейчас доделыванием игры занят и не хочу отвлекаться на статью, но она обязательно будет. Позже.)
Плюс в игре реализованы некоторые визуальные эффекты за счёт динамического изменения палитры. Но я сейчас доделыванием игры занят и не хочу отвлекаться на статью, но она обязательно будет. Позже.)
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Добавление ColorKey в libGDX