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

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

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

4 ответа

Решение

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

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

В документации 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), Если вы используете метод, описанный выше, это приведет к изменению альфа-пикселя каждого пикселя, поэтому процесс не может быть полностью изменен.

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

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

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

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

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

Если вы хотите, вы можете изменить альфа-значение каждого пикселя с помощью модулей draw и surfarray. При указании цвета используйте кортеж из четырех целых чисел: (красный, зеленый, синий, альфа). Параметр альфа варьируется от 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()

Если во входном изображении включена альфа-коррекция на пиксель, но для прозрачности используется только один бит (например, спрайты.png с прозрачным фоном или текстом), вы можете довольно легко преобразовать прозрачный фон в фоновый цвет-альфа, и затем используйте 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

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

  • Выполнение редактирования по пикселям для изменения альфа-канала перед блиттингом
  • Размытие белой или черной, полупрозрачной поверхности с помощью special_flags=BLEND_RGBA_MULT или BLEND_RGBA_SUB на исходной поверхности.
Другие вопросы по тегам