Подтвердить что ты не робот

PyGame: полупрозрачные спрайты с пикселем alpha

Можно ли отображать поверхности PyGame с управляемой альфой? Я хотел бы взять поверхность с собственной альфа-пикселью и отобразить ее с переменным уровнем прозрачности, не затрагивая поверхностные данные, и сохранить прозрачность без изменений, т.е. Объекты на поверхности будут сохранять свои формы, но их "содержимое" становится более или менее полупрозрачный.

Другими словами, я хочу объединить альфа-пиксель из исходного изображения с альфа-поверхностью, рассчитанной во время выполнения.

4b9b3361

Ответ 1

После проверки документации PyGame и SDL я пришел к выводу, что то, что я просил, не выполнялось в PyGame, используя стандартные функции.

SDL docs заявляют, что альфа-альфа-альфа и альфа-альфа не могут быть объединены с первыми, которые всегда имеют приоритет. Единственный способ добиться эффекта, который я хочу, - написать код, который обновляет пиксельные значения альфа-данных поверхности источника до blit.

Ответ 2

Да, вы можете. документация класса Surface объясняет, как это сделать. Это сводится только к двум случаям: Либо вы устанавливаете флаг во время создания объекта Surface:

s = pygame.Surface((16, 16), flags=pygame.SRCALPHA)

Или вы даете альфа-канал поверхности, которая еще не имеет этого:

s = pygame.image.load('spam.png')
s.convert_alpha()

Документация модуля pygame.image гласит, что применение PNG с прозрачностью требует применения convert_alpha.

Если вы хотите, вы можете изменить альфа-значение каждого пикселя с помощью рисования модулей и всплытия. При указании цвета используйте кортеж из четырех целых чисел: (красный, зеленый, синий, альфа). Параметр альфа составляет от 0 (полностью прозрачный) до 255 (полностью непрозрачный).

import pygame
pygame.init()
screen = pygame.display.set_mode((320, 200))
screen.fill((200, 100, 200))
s = pygame.Surface((64, 64), flags=pygame.SRCALPHA)
for i in range(64):
    pygame.draw.line(s, (0, 0, 0, i*4), (0, i), (64, i))

screen.blit(s, (50, 30))
pygame.display.flip()

Ответ 3

Документация Pygame говорит, что вы не можете комбинировать альфа-поверхность с альфа-пикселем, но если вы используете Pygame 1.8. 1 или новее, вы можете обойти это, используя параметр special_flags для .blit().

Вот как я это сделал:

# Load an image with per-pixel alpha
s = pygame.image.load('spam.png')
s.convert_alpha()

# Simulate s.set_alpha(alpha)
alpha_img = pygame.Surface(s.get_rect().size, pygame.SRCALPHA)
alpha_img.fill((255, 255, 255, alpha))
s.blit(alpha_img, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)

Как это работает, нужно создать вторую поверхность того же размера, что и первая, и включить ее в первый раз, используя умножение RGBA. Благодаря тому, что компоненты R, G и B второго изображения равны 255, умножение не повлияет на цвет изображения, но будет масштабировать альфа-канал по данному альфа-коэффициенту.

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

Ответ 4

Если ваше входное изображение имеет пиксельную альфа-версию, но использует только один бит для прозрачности (например,.png спрайты с прозрачным фоном или текстом), вы можете преобразовать прозрачный фон в фона colorkey-alpha довольно легко, а затем используйте set_alpha() для смешивания всей текстуры на что угодно.

Это быстрая и грязная вспомогательная функция, которую я использовал для угасания текстовых эффектов и других вещей:

def convert_to_colorkey_alpha(surf, colorkey=pygame.color.Color("magenta")):
    newsurf = surface.Surface(surf.get_size())
    newsurf.fill(colorkey)
    newsurf.blit(surf, (0, 0))
    newsurf.set_colorkey(colorkey)
    return newsurf

Несколько других трюков, которые могут решить эту проблему, могут быть:

  • Выполнение редактирования на пиксель для изменения альфа-канала перед blitting
  • Нанесите на поверхность исходного изображения белую или черную заполненную полупрозрачную поверхность с особыми_флагами = BLEND_RGBA_MULT или BLEND_RGBA_SUB.