图像和雪碧

Pyglet提供了使用本机操作系统服务加载和保存各种格式的图像的函数。如果 Pillow 库,则可以支持许多其他格式。Piglet还包括用于加载PNG和BMP的内置编解码器,而不需要外部依赖。

加载的图像可以高效地作为纹理提供给OpenGL,而OpenGL纹理和帧缓冲区可以作为要保存或以其他方式操作的pyglet图像进行检索。

如果你做过任何游戏或图形编程,你可能熟悉“精灵”的概念。pyglet还提供了一个高效和全面的 Sprite 类,用于在屏幕上显示带有可选变换(如缩放和旋转)的图像。如果你打算对屏幕上的图像做任何涉及移动和放置的事情,你可能会想要使用精灵。

加载图像

可以使用 pyglet.image.load() 功能::

kitten = pyglet.image.load('kitten.png')

如果要分发包含图像的应用程序,请考虑使用 pyglet.resource 模块(请参见 应用程序资源 )。

在没有任何额外论点的情况下, pyglet.image.load() 将尝试使用任何可用的图像解码器加载指定的文件名。这将允许您加载PNG、GIF、JPEG、BMP和DDS文件,也可能加载其他文件,具体取决于您的操作系统和其他安装的模块(有关详细信息,请参阅下一节)。如果无法加载图像,则会引发 ImageDecodeException 将会被唤醒。

您可以从任何类似文件的对象加载图像,只要 read 方法,通过指定 file 关键字参数::

kitten_stream = open('kitten.png', 'rb')
kitten = pyglet.image.load('kitten.png', file=kitten_stream)

在本例中为文件名 kitten.png 是可选的,但向解码器提供有关文件类型的提示(否则在提供文件对象时不使用它)。

显示图像

图像绘制通常在窗口的 on_draw() 事件处理程序。直接绘制单独的图像是可能的,但通常您会希望为屏幕上图像的每个外观创建一个“精灵”。

小精灵

Sprite是一个功能全面的类,用于在窗口中显示图像或动画的实例。图像和动画实例主要涉及图像数据(大小、像素等),而精灵也包括其他属性。其中包括x/y位置、比例、旋转、不透明度、色调、可见性以及水平和垂直缩放。多个精灵可以共享相同的图像;例如,数百个子弹精灵可能共享相同的项目符号图像。

Sprite是在给定图像或动画的情况下构造的,可以直接使用 draw() 方法:

sprite = pyglet.sprite.Sprite(img=image)

@window.event
def on_draw():
    window.clear()
    sprite.draw()

如果使用动画创建,精灵会自动处理动画最新帧的显示。下面的示例使用Scheduled函数在屏幕上逐渐移动Sprite:

def update(dt):
    # Move 10 pixels per second
    sprite.x += dt * 10

# Call update 60 times a second
pyglet.clock.schedule_interval(update, 1/60.)

如果需要绘制多个精灵,请使用 Batch 强烈建议一下子把它们都画出来。这比调用 draw() 在循环中的每一个上:

batch = pyglet.graphics.Batch()

sprites = [pyglet.sprite.Sprite(image, batch=batch),
           pyglet.sprite.Sprite(image, batch=batch),
           # ...  ]

@window.event
def on_draw():
    window.clear()
    batch.draw()

当精灵被收集成一批时,不能保证它们将被提取的顺序。如果需要确保某些精灵先于其他精灵绘制(例如,风景片可能先于字符精灵绘制,而字符精灵可能先于某些粒子效果精灵绘制),请使用两个或更多 OrderedGroup 对象以指定绘图顺序::

batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
foreground = pyglet.graphics.OrderedGroup(1)

sprites = [pyglet.sprite.Sprite(image, batch=batch, group=background),
           pyglet.sprite.Sprite(image, batch=batch, group=background),
           pyglet.sprite.Sprite(image, batch=batch, group=foreground),
           pyglet.sprite.Sprite(image, batch=batch, group=foreground),
           # ...]

@window.event
def on_draw():
    window.clear()
    batch.draw()

为获得最佳性能,应根据需要使用尽可能少的批处理和组。(请参阅 着色器和渲染 部分,了解有关批处理和组渲染的更多详细信息)。这将减少绘制每一帧的内部和OpenGL操作的数量。

此外,尝试将图像合并到尽可能少的纹理中;例如,使用 pyglet.resource.image() (见 应用程序资源 )或与 纹理存储箱和地图集 )。一个常见的陷阱是使用 pyglet.image.load() 方法加载大量图像。这将导致为加载的每个图像创建单独的纹理,从而导致每个帧的大量OpenGL纹理绑定开销。

简单图像闪光灯

直接绘制图像的效率较低,但对于简单的情况可能足够了。属性可以将图像绘制到窗口中 blit() 方法:

@window.event
def on_draw():
    window.clear()
    image.blit(x, y)

这个 xy 坐标定位要绘制图像的锚点的位置。例如,若要将图像居中 (x, y) **

kitten.anchor_x = kitten.width // 2
kitten.anchor_y = kitten.height // 2
kitten.blit(x, y)

您还可以指定可选的 z 组件添加到 blit() 方法。除非更改了默认投影或启用了深度测试,否则该选项不起作用。在下面的示例中,绘制了第二个图像 behind 第一个,尽管它是在它之后绘制的::

from pyglet.gl import *
glEnable(GL_DEPTH_TEST)

kitten.blit(x, y, 0)
kitten.blit(x, y, -0.5)

默认的pyglet投影的深度范围为(-1,1)--无论是否启用深度测试,使用该范围之外的z值绘制的图像都将不可见。

具有Alpha通道的图像可以与现有帧缓冲区混合。为此,您需要为OpenGL提供一个混合方程式。以下代码片段实现了最常见的Alpha混合形式,但也可以使用其他技术:

from pyglet.gl import *
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

在您的程序中,在绘制任何图像之前,您只需要调用上面的代码一次(如果只使用Sprite,这是不必要的)。

支持的图像解码器

下表显示了哪些编解码器在Piglet中可用。

模块

班级

描述

pyglet.image.codecs.dds

DDSImageDecoder

读取包含压缩纹理的Microsoft DirectDraw Surface文件

pyglet.image.codecs.wic

WICDecoder

使用Windows图像组件服务对图像进行解码。

pyglet.image.codecs.gdiplus

GDIPlusDecoder

使用Windows GDI+服务来解码图像。

pyglet.image.codecs.gdkpixbuf2

GdkPixbuf2ImageDecoder

使用GTK-2.0 GDK函数来解码图像。

pyglet.image.codecs.pil

PILImageDecoder

PIL Image类的包装接口。

pyglet.image.codecs.quicktime

QuickTimeImageDecoder

使用Mac OS X QuickTime对图像进行解码。

pyglet.image.codecs.png

PNGImageDecoder

PNG解码器是用纯Python编写的。

pyglet.image.codecs.bmp

BMPImageDecoder

用纯Python编写的BMP解码器。

这些类中的每一个都向 pyglet.image 以及它支持的文件扩展名。这个 load() 函数将首先尝试每个具有匹配文件扩展名的图像解码器,然后再尝试其他解码器。只有当每个图像解码器都无法加载图像时, ImageDecodeException 被引发(异常的起始点将是尝试的第一个解码器)。

您可以覆盖此行为并指定要使用的特定解码实例。例如,在下面的示例中,始终使用纯Python PNG解码器,而不是操作系统的解码器:

from pyglet.image.codecs.png import PNGImageDecoder
kitten = pyglet.image.load('kitten.png', decoder=PNGImageDecoder())

除非您的应用程序必须解决操作系统解码器中的特定缺陷,否则不建议使用此方法。

支持的图像格式

下表列出了可以在每个操作系统上加载的图像格式。如果安装了Pillow,还可以阅读它支持的任何其他格式。请参阅 Pillow docs 以获取此类格式的列表。

延拓

描述

窗口

Mac OS X

Linux [5]

.bmp

Windows位图

X

X

X

.dds

Microsoft DirectDraw Surface [6]

X

X

X

.exif

EXIF

X

.gif

图形交换格式

X

X

X

.jpg .jpeg

JPEG/JIFF图像

X

X

X

.jp2 .jpx

JPEG2000

X

.pcx

PC画笔位图图形

X

.png

便携网络图形

X

X

X

.pnm

PBM可移植任意地图图形位图

X

.ras

太阳栅格图形

X

.tga

TrueVision Targa图形

X

.tif .tiff

标记图像文件格式

X

X

X

.xbm

X11位图

X

X

.xpm

X11图标

X

X

唯一支持的保存格式是PNG,除非安装了PIL,在这种情况下,可以写入它支持的任何格式。

使用图像

这个 pyglet.image.load() 函数返回一个 AbstractImage 。对象的实际类别取决于所使用的解码器,但所有加载的图像都将具有以下属性:

width

图像的宽度,以像素为单位。

height

图像的高度,以像素为单位。

anchor_x

锚点到图像左边缘的距离,以像素为单位

anchor_y

锚点到图像底边的距离,以像素为单位

虽然某些图像格式可能包含固有的锚点,但锚点默认为(0,0)。锚点用于在绘制图像时将其与空间中的点对齐。

您可能只想使用完整图像的一部分。您可以使用 get_region() 方法返回源图像的矩形区域的图像::

image_part = kitten.get_region(x=10, y=10, width=100, height=100)

这将返回尺寸为100x100的图像。从以下位置提取的区域 kitten 对齐后,矩形的左下角与图像的左侧和底部分别为10个像素和10个像素。

图像区域可以像使用完整图像一样使用。注意,对图像区域的改变可以反映在源图像上,也可以不反映在源图像上,并且源图像的改变可以反映在任何区域图像上,也可以不反映在任何区域图像上。你不应该假设这两种行为中的哪种。

抽象图像层次结构

以下各节将介绍各种具体的图像类。所有图像子类 AbstractImage ,它提供了前面部分描述的基本界面。

../_images/abstract_image.png

这个 AbstractImage 类层次结构。

任何类的图像都可以转换为 TextureImageData 使用 get_texture()get_image_data() 上定义的方法 AbstractImage 。例如,要加载图像并将其用作OpenGL纹理,请执行以下操作:

kitten = pyglet.image.load('kitten.png').get_texture()

如果对象已经属于所请求的类,则访问这些方法之一不会有任何损失。下表显示了如何将具体类转换为其他类:

原班级

.get_texture()

.get_image_data()

Texture

没有变化

glGetTexImage2D

TextureRegion

没有变化

glGetTexImage2D ,裁剪生成的图像。

ImageData

glTexImage2D [1]

没有变化

ImageDataRegion

glTexImage2D [1]

没有变化

CompressedImageData

glCompressedTexImage2D [2]

不适用 [3]

BufferImage

glCopyTexSubImage2D [4]

glReadPixels

您应该尽量避免使用 glGetTexImage2DglReadPixels 这是因为这会通过在视频总线的“错误”方向上传输数据,特别是在较旧的硬件上传输数据,从而造成相当大的性能损失。

访问或提供像素数据

这个 ImageData 类将图像表示为像素数据的字符串或序列,或表示为cTypes指针。节距和组件布局等细节也存储在班级中。您可以访问 ImageData 属性的任何图像的 get_image_data() **

kitten = pyglet.image.load('kitten.png').get_image_data()

一种新的设计 ImageData 是允许应用程序以它们喜欢的格式访问细节,而不是必须了解每个操作系统和OpenGL使用的许多格式。

这个 pitchformat 属性确定字节的排列方式。 pitch 给出每一连续行之间的字节数。假定数据是从左到右、从下到上排列的,除非 pitch 是负的,在这种情况下,它从左到右,从上到下运行。不需要排得紧紧的;更大的 pitch 值通常用于将每行与机器字边界对齐。

这个 format 属性提供颜色组件的数量和顺序。它是一个由一个或多个字母组成的字符串,对应于下表中的组件:

R

红色

G

绿色

B

蓝色

A

Alpha

L

亮度

I

强度

例如,格式字符串 "RGBA" 对应于四个字节的颜色数据,按红、绿、蓝、阿尔法的顺序。请注意,机器字符顺序对格式字符串的解释没有影响。

格式字符串的长度始终给出每像素的字节数。因此,给定图像的最小绝对间距为 len(kitten.format) * kitten.width

若要检索特定格式的像素数据,请使用 get_data 方法,指定所需的格式和间距。下面的示例将紧凑的行读入 RGB 格式(如果有Alpha分量,将被丢弃)::

kitten = kitten.get_image_data()
data = kitten.get_data('RGB', kitten.width * 3)

data 始终返回字符串,但是可以从ctype数组、stdlib数组、字节数据列表、字符串或ctype指针设置像素数据。要设置图像数据,请使用 set_data ,再次指定格式和间距::

kitten.set_data('RGB', kitten.width * 3, data)

您还可以创建 ImageData 通过将这些属性中的每一个都提供给构造函数来直接执行。这是将纹理从其他程序或库加载到OpenGL中的任何简单方法。

性能问题

Piglet可以使用多种方法将像素数据从一种格式转换为另一种格式。它将始终努力选择最有效的手段。例如,向OpenGL提供纹理数据时,将按顺序检查以下可能性:

  1. 是否可以使用内置的OpenGL像素格式直接提供数据 GL_RGBGL_RGBA

  2. 是否存在处理这种像素格式的扩展?

  3. 数据可以用一个正则表达式进行转换吗?

  4. 如果以上都不可能,图像将被分割成单独的扫描线,并对每个扫描线进行正则表达式替换;然后,这些线将再次连接在一起。

下表显示了哪些图像格式可以直接与上面的步骤1和2一起使用,只要图像行紧密排列(即间距等于宽度乘以组件数量)。

格式

所需的扩展

"I"

"L"

"LA"

"R"

"G"

"B"

"A"

"RGB"

"RGBA"

"ARGB"

GL_EXT_bgra and GL_APPLE_packed_pixels

"ABGR"

GL_EXT_abgr

"BGR"

GL_EXT_bgra

"BGRA"

GL_EXT_bgra

如果图像数据不是这些格式中的一种,将构造一个正则表达式将其提取为一种。如果行不是紧密排列的,或者图像是从上到下排序的,则在应用正则表达式之前将拆分行。这些格式中的每一个都可能会导致性能下降--如果可能,您应该避免使用此类格式进行实时纹理更新。

图像序列和地图集

有时,一个图像被用来保存多个图像。例如,“精灵工作表”是包含角色精灵动画所需的每个动画帧的图像。

Pyglet提供了方便的类,用于从这样的复合图像中提取单独的图像,就好像它是一个简单的Python序列一样。离散图像也可以使用纹理箱和图集打包到一个或多个较大的纹理中。

../_images/image_sequence.png

AbstractImageSequence类层次结构。

图像网格

“图像网格”是通过在其上绘制一个虚构的网格来将其分割成几个较小的图像的单个图像。下图显示了用于 Astraea 举个例子。

../_images/explosion.png

由排列在网格中的八个动画帧组成的图像。

此图像有一行和八列。这是您创建 ImageGrid 使用::

explosion = pyglet.image.load('explosion.png')
explosion_seq = pyglet.image.ImageGrid(explosion, 1, 8)

现在可以访问网格中的图像,就像访问它们自己的图像一样:

frame_1 = explosion_seq[0]
frame_2 = explosion_seq[1]

包含多行的图像可以作为一维序列访问,也可以作为(行、列)元组访问;如下图所示。

../_images/image_grid.png

具有多行和多列的图像网格以及可用于访问它的切片。

图像序列可以像Python中的任何其他序列一样进行切片。例如,以下代码获取动画中的前四帧:

start_frames = explosion_seq[:4]

为了高效呈现,您应该使用 TextureGrid 。这对网格使用单一纹理,从切片返回的每个单独的图像都将是 TextureRegion **

explosion_tex_seq = image.TextureGrid(explosion_seq)

因为 TextureGrid 也是一种 Texture ,您可以将其用作单个图像,也可以一次性用作整个网格。

3D纹理

TextureGrid 对于从单个纹理绘制多个精灵非常有效。然而,您可能会遇到的一个问题是相邻图像之间的出血。

当OpenGL将纹理渲染到屏幕上时,默认情况下,它通过对附近的纹理像素进行内插来获得每种像素颜色。您可以通过切换到 GL_NEAREST 但是,您会失去平滑缩放、扭曲、旋转和亚像素定位的好处。

您可以通过始终在每个图像帧周围保留1像素的清晰边框来缓解该问题。但是,如果您使用的是mipmap,则这不会解决问题。在此阶段,您将需要3D纹理。

您可以从任何图像序列或从 ImageGrid 。图像必须都具有相同的维度,但是它们不必是2的幂(Piglet通过返回 TextureRegion 就像常客一样 Texture )。

在下面的示例中,将上面的爆炸纹理上载到3D纹理中:

explosion_3d = pyglet.image.Texture3D.create_for_image_grid(explosion_seq)

您也可以将每个图像存储为单独的文件并使用 pyglet.image.Texture3D.create_for_images() 以创建3D纹理。

创建后,3D纹理的行为与任何其他纹理一样 AbstractImageSequence ;切片返回 TextureRegion 用于纹理中的图像平面。不同于 TextureGrid 尽管如此,你不能把一个 Texture3D 它的全部。

纹理存储箱和地图集

当艺术家有很好的工具来构建适当格式的较大图像,并且所包含的图像都具有相同的大小时,图像网格非常有用。但是,将单独的图像作为单独的文件保存在磁盘上通常更简单,仅在运行时将它们合并为更大的纹理以提高效率。

A TextureAtlas 最初是一个空纹理,但可以随时向其添加任何大小的图像。该图集负责跟踪纹理中的“自由”区域,并将图像放置在纹理中的适当位置以避免重叠。

这是有可能的 TextureAtlas 以耗尽新图像的空间,因此应用程序需要知道要初始分配的纹理的正确大小,或者在每个地图集填满时维护多个地图集。

这个 TextureBin 类提供了一种管理多个地图集的简单方法。下面的示例加载图像列表,然后将这些图像插入到纹理框中。得到的列表是一个 TextureRegion 映射到更大的共享纹理图集的图像::

images = [
    pyglet.image.load('img1.png'),
    pyglet.image.load('img2.png'),
    # ...
]

bin = pyglet.image.atlas.TextureBin()
images = [bin.add(image) for image in images]

这个 pyglet.resource 模块(请参见 应用程序资源 )在内部使用纹理存储箱以高效地自动打包图像。

动画

虽然图像序列和图集提供了相关图像的存储,但它们本身并不足以描述完整的动画。

这个 Animation 类管理一系列 AnimationFrame 对象,每个对象引用一个图像和一个持续时间(以秒为单位)。图像的存储由应用程序开发人员决定:它们可以是离散的,也可以打包到纹理图集中,或任何其他技术。

可以使用以下命令直接从GIF 89a图像文件加载动画 load_animation() (在Linux、Mac OS X和Windows上受支持)或使用类方法从图像列表或图像序列手动构建(在这种情况下,还需要提供计时信息)。这个 add_to_texture_bin() 方法提供了一种将图像帧打包到纹理框中以进行高效访问的便捷方法。

应用程序可以访问单个帧以用于任何类型的呈现,或者整个动画可以直接与 Sprite (见下一节)。

下面的示例加载一个GIF动画,并将该动画中的图像打包到纹理框中。子画面用于在窗口中显示动画::

window = pyglet.window.Window()

animation = pyglet.image.load_animation('animation.gif')
bin = pyglet.image.atlas.TextureBin()
animation.add_to_texture_bin(bin)
sprite = pyglet.sprite.Sprite(img=animation)

@window.event
def on_draw():
    window.clear()
    sprite.draw()

pyglet.app.run()

当动画加载到 pyglet.resource (见 应用程序资源 )这些帧将自动打包到纹理存储箱中。

此示例程序位于 examples/programming_guide/animation.py ,以及一个示例GIF动画文件。

帧缓冲区

为了简化使用帧缓冲区,pyglet提供了 FrameBufferRenderBuffer 上课。它们的工作方式与您预期的一样,并且允许以一种简单的方式添加纹理附件。附件和目标类型可以指定为::

from pyglet.gl import *

# Prepare the buffers. One texture (for easy access), and one Renderbuffer:
color_buffer = pyglet.image.Texture.create(width, height, min_filter=GL_NEAREST, mag_filter=GL_NEAREST)
depth_buffer = pyglet.image.Renderbuffer(width, height, GL_DEPTH_COMPONENT)

# Create a Framebuffer, and attach:
framebuffer = pyglet.image.Framebuffer()
framebuffer.attach_texture(color_buffer, attachment=GL_COLOR_ATTACHMENT0)
framebuffer.attach_renderbuffer(depth_buffer, attachment=GL_DEPTH_ATTACHMENT)

# When drawing:
framebuffer.bind()

Pyglet还在“默认”帧缓冲区上提供了一个简单的抽象,作为 AbstractImage 层级结构。

../_images/buffer_image.png

这个 BufferImage 层级结构。

不能直接创建缓冲区映像;相反,您必须通过 BufferManager 。使用 get_buffer_manager() 要获取此单件对象::

buffers = image.get_buffer_manager()

只能获得左后颜色缓冲区(即,前台缓冲区不可访问,缓冲区管理器不支持立体声上下文):

color_buffer = buffers.get_color_buffer()

可以像对待任何其他图像一样处理此缓冲区。例如,可以将其复制到纹理、获取其像素数据、将其保存到文件等。如果您要保存正在运行的应用程序的“屏幕截图”,这将非常有用:

image_data = color_buffer.get_image_data()
image_data.save("screenshot.png")

深度缓冲区可以类似的方式获得::

depth_buffer = buffers.get_depth_buffer()

当深度缓冲区转换为纹理时,使用的类将是 DepthTexture ,适用于阴影贴图技术。

辅助缓冲器和模板钻头是通过请求一个来获得的,然后将其标记为“使用中”。这允许多个库和您的应用程序协同工作,而不会在模板位或辅助缓冲区名称中发生冲突。例如,要获得可用模板位::

mask = buffers.get_buffer_mask()

缓冲区管理器维护对缓冲区掩码的弱引用,因此当您释放对它的所有引用时,它将返回到可用掩码池中。

类似地,获得空闲辅助缓冲区::

aux_buffer = buffers.get_aux_buffer()

使用模具或辅助缓冲区时,请确保在创建窗口时显式请求这些缓冲区。看见 OpenGL configuration options 了解更多细节。

OpenGL成像

本节假定您熟悉OpenGL中的纹理映射(例如, OpenGL Programming Guide )。

从任何对象创建纹理 AbstractImage ,呼叫 get_texture() **

kitten = image.load('kitten.jpg')
texture = kitten.get_texture()

纹理由自动创建和使用 ImageData 当闪光灯发射时。当目标是高性能或3D应用时,直接使用纹理是很有用的。

这个 Texture 类表示任何纹理对象。这个 target 属性提供纹理目标(例如, GL_TEXTURE_2D )和 id 纹理名称。例如,要绑定纹理::

glBindTexture(texture.target, texture.id)

质地尺寸

OpenGL 2.0之前的实现要求纹理的维度是2的幂(即,1、2、4、8、16、...)。由于这一限制,Pyglet将始终创建这些维度的纹理(有几个不符合2.0版后的实现)。这可能会导致用户对从非标准尺寸文件加载的纹理进行blit操作,从而产生意外的结果。为了解决这个问题,pyglet返回一个 TextureRegion 较大的纹理仅对应于被原始图像覆盖的纹理部分。

A TextureRegion 有一个 owner 引用较大纹理的属性。以下会议演示了这一点:

>>> rgba = image.load('tests/image/rgba.png')
>>> rgba
<ImageData 235x257>         # The image is 235x257
>>> rgba.get_texture()
<TextureRegion 235x257>     # The returned texture is a region
>>> rgba.get_texture().owner
<Texture 256x512>           # The owning texture has power-2 dimensions
>>>

A TextureRegion 定义了一个 tex_coords 属性,该属性提供用于映射整个图像的四元组的纹理坐标。 tex_coords 是由3元组浮点组成的4元组;也就是说,每个纹理坐标都以3维形式给出。以下代码可用于渲染纹理区域的四边形:

texture = kitten.get_texture()
t = texture.tex_coords
w, h = texture.width, texture.height
array = (GLfloat * 32)(
     t[0][0], t[0][1], t[0][2], 1.,
     x,       y,       z,       1.,
     t[1][0], t[1][1], t[1][2], 1.,
     x + w,   y,       z,       1.,
     t[2][0], t[2][1], t[2][2], 1.,
     x + w,   y + h,   z,       1.,
     t[3][0], t[3][1], t[3][2], 1.,
     x,       y + h,   z,       1.)

glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
glInterleavedArrays(GL_T4F_V4F, 0, array)
glDrawArrays(GL_QUADS, 0, 4)
glPopClientAttrib()

这个 blit() 方法可以做到这一点。

使用 pyglet.image.Texture.create() 方法从较大的2次方纹理创建纹理区域,或使用 GL_texture_rectangle_ARB 分机。

纹理内部格式

Piglet根据源图像的 format 属性。下表描述了如何选择它。

格式

内部格式

具有3个组件的任何格式

GL_RGB

具有2个组件的任何格式

GL_LUMINANCE_ALPHA

"A"

GL_ALPHA

"L"

GL_LUMINANCE

"I"

GL_INTENSITY

任何其他格式

GL_RGBA

请注意,此表并不表示格式组件与其对应的OpenGL组件之间有任何映射。例如,格式为 "RG" 将使用 GL_LUMINANCE_ALPHA 作为其内部格式;亮度通道将从红色和绿色分量求平均值,而Alpha通道将为空(最大)。

使用 pyglet.image.Texture.create() 类方法创建具有特定内部格式的纹理。

纹理过滤

默认情况下,所有纹理都是使用平滑创建的 (GL_LINEAR )过滤。在某些情况下,您可能希望应用不同的过滤器。例如,复古风格的像素艺术游戏需要更清晰的纹理。为了实现这一点,PAS GL_NEAREST 发送到 min_filtermag_filter 创建纹理时的参数。也可以通过设置 default_min_filterdefault_mag_filter 属性上的类属性 Texture 班级。这将导致由pyglet在内部创建的所有纹理使用以下值:

pyglet.image.Texture.default_min_filter = GL_LINEAR
pyglet.image.Texture.default_mag_filter = GL_LINEAR

保存图像

任何图像都可以使用 save 方法:

kitten.save('kitten.png')

或者,指定类似文件的对象::

kitten_stream = open('kitten.png', 'wb')
kitten.save('kitten.png', file=kitten_stream)

以下示例显示如何抓取应用程序窗口的屏幕截图:

pyglet.image.get_buffer_manager().get_color_buffer().save('screenshot.png')

请注意,除非安装了Pillow库,否则图像只能保存为PNG格式。