Blitted OpenGL 纹理占用更少的内存和 CPU
Blitted OpenGL Textures take less memory and CPU
我正在使用 pygame + pyopengl 制作游戏,现在我正尝试在这种情况下制作视频播放器。为此,我使用 ffmpeg 加载不同的视频格式,然后将每个帧转换为 opengl 纹理,如下所示,然后播放视频。
class Texture(object):
def __init__(self, data, w=0, h=0):
"""
Initialize the texture from 3 diferents types of data:
filename = open the image, get its string and produce texture
surface = get its string and produce texture
string surface = gets it texture and use w and h provided
"""
if type(data) == str:
texture_data = self.load_image(data)
elif type(data) == pygame.Surface:
texture_data = pygame.image.tostring(data, "RGBA", True)
self.w, self.h = data.get_size()
elif type(data) == bytes:
self.w, self.h = w, h
texture_data = data
self.texID = 0
self.load_texture(texture_data)
def load_image(self, data):
texture_surface = pygame.image.load(data).convert_alpha()
texture_data = pygame.image.tostring(texture_surface, "RGBA", True)
self.w, self.h = texture_surface.get_size()
return texture_data
def load_texture(self, texture_data):
self.texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.texID)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.w,
self.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texture_data)
问题是当我加载给定视频的所有纹理时,我的 RAM 超出了上限,大约 800mb。但是可以通过在每个纹理加载时 blit 来解决这个问题,如下所示。
def render():
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0, 0, 0, 1.0)
def Draw(texture, top, left, bottom, right):
"""
Draw the image on the Opengl Screen
"""
# Make sure he is looking at the position (0,0,0)
glBindTexture(GL_TEXTURE_2D, texture.texID)
glBegin(GL_QUADS)
# The top left of the image must be the indicated position
glTexCoord2f(0.0, 1.0)
glVertex2f(left, top)
glTexCoord2f(1.0, 1.0)
glVertex2f(right, top)
glTexCoord2f(1.0, 0.0)
glVertex2f(right, bottom)
glTexCoord2f(0.0, 0.0)
glVertex2f(left, bottom)
glEnd()
定义更新(t):
使成为()
绘制(t, -0.5, -0.5, 0.5, 0.5)
# Check for basic Events on the pygame interface
for event in pygame.event.get():
BASIC_Game.QUIT_Event(event)
pygame.display.flip()
虽然这将 RAM 消耗降低到可接受的值,但加载时间比视频长度更长。
我真的不明白为什么 opengl 会这样工作,但是有没有一种方法可以在不先 blitting 的情况下提高纹理的效率?
根据你现在问题中的代码,我无法确定,但我猜这是因为你正在为每一帧创建一个新的 Texture
实例,这意味着您要为视频的每一帧调用 glGenTextures(1)
。这会在内存中为视频的每一帧分配一个新缓冲区,然后存储该帧的完整未压缩版本。
当您 blit 图像时,您并没有生成新的纹理,而只是覆盖了旧的纹理。这是您想要的解决方案,但您的实施方式效率低下。
有许多方法可以更改纹理中的数据而无需在 CPU 上进行 blitting(假设 pygame blitting)以加快速度,此答案中列出了一些方法:
我正在使用 pygame + pyopengl 制作游戏,现在我正尝试在这种情况下制作视频播放器。为此,我使用 ffmpeg 加载不同的视频格式,然后将每个帧转换为 opengl 纹理,如下所示,然后播放视频。
class Texture(object):
def __init__(self, data, w=0, h=0):
"""
Initialize the texture from 3 diferents types of data:
filename = open the image, get its string and produce texture
surface = get its string and produce texture
string surface = gets it texture and use w and h provided
"""
if type(data) == str:
texture_data = self.load_image(data)
elif type(data) == pygame.Surface:
texture_data = pygame.image.tostring(data, "RGBA", True)
self.w, self.h = data.get_size()
elif type(data) == bytes:
self.w, self.h = w, h
texture_data = data
self.texID = 0
self.load_texture(texture_data)
def load_image(self, data):
texture_surface = pygame.image.load(data).convert_alpha()
texture_data = pygame.image.tostring(texture_surface, "RGBA", True)
self.w, self.h = texture_surface.get_size()
return texture_data
def load_texture(self, texture_data):
self.texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.texID)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.w,
self.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texture_data)
问题是当我加载给定视频的所有纹理时,我的 RAM 超出了上限,大约 800mb。但是可以通过在每个纹理加载时 blit 来解决这个问题,如下所示。
def render():
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0, 0, 0, 1.0)
def Draw(texture, top, left, bottom, right):
"""
Draw the image on the Opengl Screen
"""
# Make sure he is looking at the position (0,0,0)
glBindTexture(GL_TEXTURE_2D, texture.texID)
glBegin(GL_QUADS)
# The top left of the image must be the indicated position
glTexCoord2f(0.0, 1.0)
glVertex2f(left, top)
glTexCoord2f(1.0, 1.0)
glVertex2f(right, top)
glTexCoord2f(1.0, 0.0)
glVertex2f(right, bottom)
glTexCoord2f(0.0, 0.0)
glVertex2f(left, bottom)
glEnd()
定义更新(t): 使成为() 绘制(t, -0.5, -0.5, 0.5, 0.5)
# Check for basic Events on the pygame interface
for event in pygame.event.get():
BASIC_Game.QUIT_Event(event)
pygame.display.flip()
虽然这将 RAM 消耗降低到可接受的值,但加载时间比视频长度更长。
我真的不明白为什么 opengl 会这样工作,但是有没有一种方法可以在不先 blitting 的情况下提高纹理的效率?
根据你现在问题中的代码,我无法确定,但我猜这是因为你正在为每一帧创建一个新的 Texture
实例,这意味着您要为视频的每一帧调用 glGenTextures(1)
。这会在内存中为视频的每一帧分配一个新缓冲区,然后存储该帧的完整未压缩版本。
当您 blit 图像时,您并没有生成新的纹理,而只是覆盖了旧的纹理。这是您想要的解决方案,但您的实施方式效率低下。
有许多方法可以更改纹理中的数据而无需在 CPU 上进行 blitting(假设 pygame blitting)以加快速度,此答案中列出了一些方法: