PyGame:具有每像素透明度的半透明精灵
有没有办法在PyGame中显示可以控制透明度的表面?我想要一个表面,它每个像素都有自己的透明度,然后我想以可变的透明度来显示它,而不改变这个表面的数据,并且保持透明度不变。也就是说,表面上的物体形状要保持不变,但它们的“内容”可以变得更透明或更不透明。
换句话说,我想把源图像每个像素的透明度和在运行时计算的表面透明度结合起来。
4 个回答
当然可以。Surface类的文档里有详细说明怎么做。其实就分为两种情况:
s = pygame.Surface((16, 16), flags=pygame.SRCALPHA)
第一种是在创建Surface对象的时候设置一个标志:
s = pygame.image.load('spam.png')
s.convert_alpha()
第二种是给一个还没有透明通道的表面添加一个透明通道:
pygame.image模块的文档提到,对于带透明的PNG图片,使用convert_alpha是必须的。
如果你想的话,可以用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()
Pygame的官方文档提到,你不能把表面透明度和每个像素的透明度结合在一起。不过,如果你使用的是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乘法
把它绘制到第一个表面上。通过把第二个图像的红色、绿色和蓝色部分设置为255,这样乘法就不会影响图像的颜色,但会根据给定的透明度因子来调整透明度通道。
需要注意的是,上面的方法和调用set_alpha()
是不同的,因为set_alpha()
可以通过调用set_alpha(255)
来恢复。如果你使用上面的方法,所有像素的透明度都会被改变,所以这个过程不能简单地逆转。
在查看了PyGame和SDL的文档后,我得出结论,我想要的功能在PyGame中用标准函数是无法实现的。
SDL的文档说明,逐像素的透明度和整个表面的透明度不能一起使用,前者总是优先级更高。要实现我想要的效果,唯一的方法就是写一段代码,在进行图像合成之前,更新源图像的逐像素透明度值。