使用pygame进行动态纹理绘制(可能吗?需要了解哪些概念?)
我有两张图片:
我想把黑色的形状从纹理图中“切出来”,这样我最终得到的效果大概是这样的:
不过形状周围是透明的。请问用pygame可以做到吗?这个例子我是用GIMP制作的。
另外,这样做会不会对性能影响太大?因为我想在实时环境中对几个精灵每帧都这样处理(每秒30帧以上)。
2 个回答
5
如果你在使用带有预先渲染透明度和加法混合的图片,你可以得到透明度混合的遮罩:
import pygame
import sys
screen = pygame.display.set_mode( (800, 600) )
pygame.init()
background = pygame.image.load( "background.png" )
mask = pygame.image.load( "mask.png" )
# Create a surface to hold the masked image
masked_image = pygame.surface.Surface( background.get_size(), 0, mask )
# Blit the texture normally
masked_image.blit( background, (0,0) )
# Multiply by the pre-rendered, inverted mask
masked_image.blit( mask, (0,0), None, pygame.BLEND_MULT )
# masked_image now holds the 'cutout' of your texture blended onto a black
# background, so we need to blit it as such, i.e., using additive blending.
screen.fill( (0, 0, 0) )
screen.blit( masked_image, (10, 10), None, pygame.BLEND_ADD )
pygame.display.flip()
while True:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
这里的 background.png
和 mask.png
是:
+
=
8
我做了一个解决方案,不过在速度和美观上都不是最好的选择。你可以使用双重绘制,并设置颜色键来实现透明效果。这样,遮罩图像应该只有两种颜色:黑色和白色。需要注意的是,这种方法不能用于每个像素都有透明度的图像(RGBA),只能用于RGB图像。还有一个限制是,建议纹理和遮罩图像的大小要相同(如果不相同,你需要使用区域进行绘制)。
简单来说,步骤如下:
- 创建一个带有遮罩的表面。背景应该是白色(255,255,255),被遮罩的部分应该是黑色(0,0,0)。
- 创建或加载纹理到一个表面中。
- 为遮罩设置黑色的透明颜色键。
- 将遮罩绘制到纹理上(或者绘制到纹理的副本上)。此时,遮罩的黑色部分不会绘制到纹理上,因为我们已经用set_colorkey方法将黑色设置为透明。
- 现在将纹理(或纹理的副本)的颜色键设置为白色。记住,我们当前的纹理表面有白色和有纹理的部分。
- 将纹理绘制到屏幕上。由于我们将白色设置为透明,所以白色部分不会被绘制。
代码示例:
#!/usr/bin/python
# -*- coding:utf8 -*-
import pygame, sys
#init pygame
pygame.init()
#init screen
screen=pygame.display.set_mode((800,600))
screen.fill((255,0,255))
#loading the images
texture=pygame.image.load("texture.jpg").convert()
texture_rect=texture.get_rect()
texture_rect.center=(200,300)
mask=pygame.Surface((texture_rect.width,texture_rect.height)) # mask should have only 2 colors: black and white
mask.fill((255,255,255))
pygame.draw.circle(mask,(0,0,0),(texture_rect.width/2,texture_rect.height/2),int(texture_rect.width*0.3))
mask_rect=mask.get_rect()
mask_rect.center=(600,300)
tmp_image=texture.copy() # make a copy of the texture to keep it unchanged for future usage
mask.set_colorkey((0,0,0)) # we want the black colored parts of the mask to be transparent
tmp_image.blit(mask,(0,0)) # blit the mask to the texture. the black parts are transparent so we see the pixels of the texture there
tmp_rect=tmp_image.get_rect()
tmp_rect.center=(400,300)
tmp_image.set_colorkey((255,255,255))
screen.blit(texture,texture_rect)
screen.blit(mask,mask_rect)
screen.blit(tmp_image,tmp_rect)
pygame.display.flip()
while 1:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
我建议不要使用jpg作为遮罩,因为它是有损格式,推荐使用bmp或png(bmp更好)。记住,它不使用透明度,所以边缘不会进行抗锯齿处理,因此在2010年这不是一个好的解决方案 :)
这是结果的截图:
编辑: 再次好,
我用BLEND_ADD进行了绘制测试,结果很不错。这里是代码:
import pygame, sys
#init pygame
pygame.init()
#init screen
screen=pygame.display.set_mode((800,600))
screen.fill((255,0,255))
#loading the images
texture=pygame.image.load("texture.jpg").convert_alpha()
texture_rect=texture.get_rect()
texture_rect.center=(200,300)
mask=pygame.image.load("mask2.png").convert_alpha()
mask_rect=mask.get_rect()
mask_rect.center=(600,300)
textured_mask=mask.copy()
textured_rect=textured_mask.get_rect()
textured_rect.center=400,300
textured_mask.blit(texture,(0,0),None,pygame.BLEND_ADD)
screen.blit(texture,texture_rect)
screen.blit(mask,mask_rect)
screen.blit(textured_mask,textured_rect)
pygame.display.flip()
while 1:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
结果如下:
通过这个解决方案,你可以实现每个像素都有透明度的纹理效果。请注意,遮罩应该是带有透明通道的图像,所以不能使用jpg。最好使用png。
纹理图像(texture.jpg):
遮罩图像(mask2.png):