PyGame:使用每个像素的alpha值创建半透明精灵。

13

是否可能显示具有可控透明度的PyGame表面?我想使用可变的半透明水平显示带有自己的每个像素alpha的表面,而不会影响表面数据并保持透明度完好无损,即表面上的对象将保持其形状,但其“内容”会变得更加透明或不透明。

换句话说,我想在运行时将源图像的每个像素alpha与计算的每个表面alpha相结合。

4个回答

7

Pygame文档指出,您不能将表面alpha与逐像素alpha相结合,但如果您使用的是Pygame 1.8.1或更新版本,则可以通过在.blit()中使用special_flags参数来解决此问题。

以下是我的做法:

# Load an image with per-pixel alpha
s = pygame.image.load('spam.png')
s = 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,乘法不会影响图像的颜色,但它将按给定的alpha因子缩放alpha通道。
请注意,上述方法与调用set_alpha()的方法不同,因为可以通过调用set_alpha(255)来撤消set_alpha()。如果使用上述方法,则将更改每个像素的像素alpha值,因此该过程无法直接撤消。

self 应该改为 s 吗? - Jason

4

在检查了PyGame和SDL文档后,我得出结论:使用标准函数无法在PyGame中完成我所需的操作。

SDL文档指出,像素级透明度和表面级透明度不能组合使用,前者始终占据优先位置。实现我想要的效果的唯一方法是编写代码,在blit之前更新源表面的像素级透明度值。


4
是的,你可以。Surface类的文档解释了如何实现。它只有两种情况:要么在创建Surface对象时设置一个标志:
s = pygame.Surface((16, 16), flags=pygame.SRCALPHA)

或者你可以给一个还没有alpha通道的表面添加一个:

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

pygame.image模块的文档指出,对于具有透明度的PNG图片,应用convert_alpha是必要的。

如果您想要修改每个像素的alpha值,可以使用draw和surfarray模块。在指定颜色时,请使用一个由四个整数组成的元组:(红色,绿色,蓝色,alpha)。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()

+1 例子总是受欢迎的,特别是当它能够正常工作并展示所需内容时 :D - admalledd
5
好的,那就解释如何显示具有每像素透明度的表面(例如来自PNG文件的表面)。 我已经知道了这一点。但我正在寻找一种用代码可控透明度来显示这些表面的方法。 例如,使这些精灵从完全透明到其原始每像素透明度。类似于Surface.set_alpha(),但不会禁用表面中已经存在的每像素透明度。 将每像素透明度与整体透明度值混合。 - Maciej Miąsik

1
如果您的输入图像启用了每像素 alpha,但仅使用单个位进行透明度(例如,具有透明背景或文本的 .png 精灵),则可以相当轻松地将透明背景转换为颜色键-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 之前对 alpha 通道进行逐像素编辑
  • 将填充了白色或黑色的半透明表面使用 special_flags=BLEND_RGBA_MULT 或 BLEND_RGBA_SUB 模式 blit 到源表面上。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接