Я работаю над Megaman- подобной игрой, где мне нужно изменить цвет определенных пикселей во время выполнения. Для справки : в Megaman, когда вы меняете выбранное оружие, палитра главного героя меняется, отражая выбранное оружие. Меняются не все цвета спрайта, а только определенные .
Этот вид эффекта был обычным и довольно простым в NES, поскольку у программиста был доступ к палитре и логическому отображению между пикселями и индексами палитры. Однако на современном оборудовании это немного сложнее, потому что концепция палитр не одинакова.
Все мои текстуры являются 32-битными и не используют палитры.
Есть два способа достижения желаемого эффекта, но мне любопытно, есть ли лучшие способы легко достичь этого эффекта. Мне известны два варианта:
- Используйте шейдер и напишите немного GLSL, чтобы выполнить поведение «замена палитры».
- Если шейдеры недоступны (скажем, потому что видеокарта их не поддерживает), то можно клонировать «оригинальные» текстуры и генерировать разные версии с предварительно примененными изменениями цвета.
В идеале я хотел бы использовать шейдер, так как он кажется простым и требует немного дополнительной работы, в отличие от метода дублированной текстуры. Я беспокоюсь о том, что дублирование текстур только для того, чтобы изменить их цвет, приводит к потере VRAM.
Изменить : я в конечном итоге использовал прием принятого ответа и вот мой шейдер для справки.
uniform sampler2D texture;
uniform sampler2D colorTable;
uniform float paletteIndex;
void main()
{
vec2 pos = gl_TexCoord[0].xy;
vec4 color = texture2D(texture, pos);
vec2 index = vec2(color.r + paletteIndex, 0);
vec4 indexedColor = texture2D(colorTable, index);
gl_FragColor = indexedColor;
}
Обе текстуры являются 32-битными, одна текстура используется в качестве справочной таблицы, содержащей несколько палитр одинакового размера (в моем случае 6 цветов). Я использую красный канал исходного пикселя в качестве указателя на таблицу цветов. Это сработало как шарм для достижения Megaman-подобной замены палитры!
Есть 2 способа, которыми я могу думать, чтобы сделать это.
Способ № 1: GL_MODULATE
Вы можете сделать спрайт в оттенках серого, а
GL_MODULATE
текстуру, когда он нарисован одним сплошным цветом.Например,
Это не дает вам большой гибкости, в основном вы можете становиться только светлее и темнее одного и того же оттенка.
Способ № 2:
if
постановка (плохо для производительности)Другая вещь, которую вы могли бы сделать, это закрасить ваши текстуры некоторыми ключевыми значениями, включающими R, G и B. Так, например, первый цвет (1,0,0), 2-й цвет (0,1,0), 3-й цвет (0,0,1).
Вы объявляете пару униформ как
Тогда в шейдере конечный цвет пикселя будет что-то вроде
color1
,color2
,color3
, Являются формы , так что они могут быть установлены до запуска шейдера ( в зависимости от того, что «костюм» Megaman в), то шейдер просто делает все остальное.Вы также можете использовать
if
операторы, если вам нужно больше цветов, но вам нужно, чтобы проверки на равенство работали правильно (текстуры обычно находятсяR8G8B8
в диапазоне от 0 до 255 каждая в файле текстур, но в шейдере у вас есть плавающие rgba)Способ № 3: просто избыточно хранить разноцветные изображения в спрайт-карте
Это может быть самый простой способ, если вы не безумно пытаетесь сохранить память
источник
Я бы использовал шейдеры. Если вы не хотите их использовать (или не можете), я бы использовал одну текстуру (или часть текстуры) на цвет и использовал только чистый белый. Это позволит вам тонировать текстуру (например, сквозную
glColor()
), не беспокоясь о создании дополнительных текстур для цветов. Вы даже можете менять цвета на ходу без дополнительной работы с текстурами.источник
«Меняются не все цвета спрайта, а только некоторые».
Старые игры делали палитры, потому что это было все, что у них было. В наши дни вы можете использовать несколько текстур и комбинировать их различными способами.
Вы можете создать отдельную текстуру маски в градациях серого, которую вы используете, чтобы решить, какие пиксели будут менять цвет. Белые области в текстуре получают полную цветовую модификацию, а черные области остаются неизменными.
В шейдерном языке:
Или вы можете использовать фиксированную функцию мультитекстурирования с различными режимами объединения текстур.
Очевидно, есть много разных способов сделать это; Вы можете поместить маски для разных цветов в каждый из каналов RGB или модулировать цвета путем изменения оттенка в цветовом пространстве HSV.
Другой, возможно, более простой вариант - просто нарисовать спрайт, используя отдельную текстуру для каждого компонента. Одна текстура для волос, одна для доспехов, одна для сапог и т. Д. Каждая из них окрашивается отдельно.
источник
Во-первых, это обычно называется езда на велосипеде (паллетный езда на велосипеде), так что это может помочь вашему Google-фу.
Это будет зависеть от того, какие именно эффекты вы хотите создать, и от того, имеете ли вы дело со статическим 2D-контентом или динамическим 3D-материалом (т. Е. Хотите ли вы иметь дело со спайтами / текстурами или визуализировать целую 3D-сцену, а затем поменять ее местами). Также, если вы ограничиваете себя количеством цветов или используете полный цвет.
Более полный подход, использующий шейдеры, заключается в том, чтобы на самом деле создавать индексированные по цвету изображения с текстурой поддона. Создайте текстуру, но вместо того, чтобы иметь цвета, выберите цвет, который представляет индекс для поиска, а затем используйте другую текстуру цветов, которая является пластиной. Например, красный может быть координатой t текстур, а зеленый - координатой s. Используйте шейдер для поиска. И Анимировать / Изменить цвета этой текстуры поддона. Это будет очень близко к ретро-эффекту, но будет работать только для статического 2D-контента, такого как спрайты или текстуры. Если вы работаете с подлинной ретро-графикой, то вы можете создавать фактические индексированные цветные спрайты и писать что-то для импорта их и поддонов.
Вы также захотите потренироваться, если собираетесь использовать «глобальный» поддон. Например, сколько старого оборудования будет работать, меньше памяти для поддонов, так как вам нужен только один, но сложнее для создания ваших иллюстраций, поскольку вы должны синхронизировать поддон по всем изображениям) или для каждого изображения свой собственный поддон. Это даст вам больше гибкости, но использует больше памяти. Конечно, вы можете сделать и то и другое, также вы можете использовать только поддоны для вещей, которые вы катаете на велосипеде. Также определите, в какой степени вы не хотите ограничивать свои цвета, например, в старых играх было бы 256 цветов. Если вы используете текстуру, то вы получите количество пикселей, поэтому 256 * 256 даст вам
Если вы просто хотите дешевый эффект фальшивки, такой как текущая вода, вы можете создать 2-ю текстуру, которая будет содержать маску серого в области, которую вы хотите изменить, а затем использовать мачтовые текстуры, чтобы изменить оттенок / насыщенность / яркость на величину в текстура маски в оттенках серого. Вы можете быть еще ленивее и просто изменить оттенок / яркость / насыщенность всего, что находится в цветовой гамме.
Если вам это нужно в полном 3D, вы можете попробовать сгенерировать индексированное изображение на лету, но это будет медленным, так как вам придется искать паллету, вы также, вероятно, будете ограничены в диапазоне цветов.
В противном случае вы можете просто подделать его в шейдере, если color == поменять цвет, поменять его местами. Это было бы медленно и работало бы только с ограниченным числом мест замены цветов, но не должно вызывать стресса у любого современного оборудования, особенно если вы работаете только с 2D-графикой и всегда можете пометить, какие спрайты меняют цвета и используют другой шейдер.
В противном случае действительно подделайте их, сделайте кучу анимированных текстур для каждого состояния.
Вот отличная демонстрация циклического перемещения паллет в HTML5 .
источник
Я считаю, что если бы достаточно быстро, чтобы цветовое пространство [0 ... 1] было разделено на два:
Таким образом, значения цвета от 0 до 0,5 зарезервированы для нормальных значений цвета; и 0.5 - 1.0 зарезервированы для «модулированных» значений, где 0.5..1.0 соответствует любому диапазону, выбранному пользователем.
Только цветовое разрешение усекается от 256 значений на пиксель до 128 значений.
Возможно, можно использовать встроенные функции, такие как max (color-0.5f, 0.0f), чтобы полностью удалить if (обмен их на умножения на ноль или единицу ...).
источник