在OpenGL中,纹理是不断被创建然后绘制,绑定纹理是相对昂贵的,所以将许多小图像统一存储在一张较大的图片上一次性绑定纹理,然后多次绘制它的一小部分。将纹理打包为一个大图片可以使用工具 TexturePacker, 不过在 libGDX 中,提供了一个gdx-tools工具,这里可以使用这个工具来打包纹理。
使用gdx-tools,只需要引入 gdx-tools 这个工具jar包即可。
Gradle
dependencies {
...
api "com.badlogicgames.gdx:gdx-tools:$gdxVersion"
}
Maven
<dependencies>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-tools</artifactId>
<version>${gdx-version}</version>
</dependency>
</dependencies>
import com.badlogic.gdx.tools.texturepacker.TexturePacker;
public class MyPacker {
public static void main (String[] args) throws Exception {
String inputDir = "E:\\workspace\\game\\block\\block-game\\android\\assets\\source_image";
String outputDir = "E:\\workspace\\game\\block\\block-game\\android\\assets\\handle_images";
String packFileName = "blocks";
TexturePacker.process(inputDir, outputDir, packFileName);
}
}
inputDir: 需要打包的图片文件夹
outputDir: 打包后生成的xxx.atlas xxx.png等保存的文件夹
packFileName: 打包生成的文件名
打包完成后就可以使用 TextureAtlas 类在应用程序中轻松引用资源了。
具体清查看 https://github.com/crashinvaders/gdx-texture-packer-gui
java -cp gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker inputDir [outputDir] [packFileName]
TexturePacker 可以一次打包 inputDir 路径中的所有图像。给定一个目录,它递归地扫描所有图像文件。对于 TexturePacker 遇到的每个图片目录,它都将图片打包到一个更大的纹理中,称为页面。如果一个目录中的图像不适合单个页面的最大大小,则将使用多个页面。
同一目录中的图像放在同一组页面上。如果所有的图片都放在一个页面上,那么就不应该使用子目录,因为在一个页面上应用程序只会执行一个纹理绑定。否则,可以使用子目录隔离相关的图像,以最小化纹理绑定。例如,在游戏中,可能希望将所有的 “游戏game” 图像放在与 “暂停菜单 pause menu” 图像不同的目录中,因为这两组图像是连续绘制的: 所有游戏图像都绘制(一个绑定) ,然后在顶部绘制暂停菜单(另一个绑定)。如果图像在一个目录中,导致多于一个页面,每个页面可以包含游戏和暂停菜单图像的组合。这将导致多个纹理绑定到渲染游戏和暂停菜单,而不是只有一个。
子目录还可以用于对具有相关纹理设置的图像进行分组。像运行时内存格式(RGBA,RGB 等)和过滤(最近的,线性等)等设置是每纹理。每个纹理需要不同设置的图片需要放在单独的页面上,所以应该放在单独的子目录中。
若要使用子目录进行组织,而不必为每个子目录输出一组页面,可以参考 combineSubdirectories 设置。为了避免子目录路径被用于 atlas 文件中的图像名称中,可以参考 delandentpaths 设置。
每个打包目录可以放一个 “pack.json” 文件,它是 TexturePacker.Settings 的 JSON 表示形式,用来设置打包配置。 每个子目录从其父目录继承所有设置。子目录中设置的任何设置都会覆盖父目录中设置的设置。如下是整个默认的 json 示例:
{
pot: true,
paddingX: 2,
paddingY: 2,
bleed: true,
bleedIterations: 2,
edgePadding: true,
duplicatePadding: false,
rotation: false,
minWidth: 16,
minHeight: 16,
maxWidth: 1024,
maxHeight: 1024,
square: false,
stripWhitespaceX: false,
stripWhitespaceY: false,
alphaThreshold: 0,
filterMin: Nearest,
filterMag: Nearest,
wrapX: ClampToEdge,
wrapY: ClampToEdge,
format: RGBA8888,
alias: true,
outputFormat: png,
jpegQuality: 0.9,
ignoreBlankImages: true,
fast: false,
debug: false,
combineSubdirectories: false,
flattenPaths: false,
premultiplyAlpha: false,
useIndexes: true,
limitMemory: true,
grid: false,
scale: [ 1 ],
scaleSuffix: [ "" ],
scaleResampling: [ bicubic ]
}
注意,这是 libgdx 的自定义的JSON 格式,不是严格的json文件格式,因此 key 的双引号可以不用写。
配置项 | 描述 | 默认值 |
---|---|---|
pot | If true, output pages will have power of two dimensions.(不懂, 感觉是排列方式不同) | true |
paddingX / paddingY | 边距 | 2 |
bleed | 如果为true, 则根据最接近的非透明像素的 RGB 值设置透明像素的 RGB 值。这可以防止在为透明像素采样 RGB 值时出现过滤伪影。 | true |
bleedIterations | 执行的 bleed 迭代的数量。 | 2 |
edgePadding | 如果为true,一半的 paddingX 和 paddingY 将被用于包装材质的边缘。 | true |
duplicatePadding | 如果为 true,则将边缘像素复制到填充中。paddingX/paddingY应该大于2 | false |
rotation | 如果为true,TexturePacker 将尝试通过90度旋转图像来实现更有效的打包。在游戏中使用时必须特别注意正确地绘制这些区域。 | false |
minWidth / maxWidth / minHeight / maxHeight | 最大/最小输出宽高 | minWidth、minHeight为16,maxWidth、maxHeight为1024 |
square | 如果为 true,则强制输出页面具有相同的宽度和高度。 | false |
stripWhitespaceX /stripWhitespaceY | 如果为true,则输入图像左右/上下边缘的空白像素将被移除。在游戏开发使用中必须特别注意正确地绘制这些区域。 | false |
alphaThreshold | 从0到255。当空白被删除时,低于这个值的 Alpha 值被视为零。 | 0 |
filterMin / filterMag | 给纹理缩小/放大的过滤器设置 | Texture.TextureFilter 枚举类中的类型,默认为Nearest |
wrapX / wrapY | 纹理在x / y轴方向上的打包设置 | ClampToEdge |
format | 纹理在内存中使用的格式 | RGBA8888 |
alias | 如果为true,则两个像素相同的图像将只打包一次 | true |
outputFormat | 图片的输出格式,支持 png 或者 jpg | png |
jpegQuality | 输出为jpg时的输出质量设置 | 0.9 |
ignoreBlankImages | 如果为true,纹理打包不会添加完全空白的图像区域。 | true |
fast | 如果为true,纹理打包将不会有效率,但执行打包速度更快。 | false |
debug | 如果为 true,则在输出页面上绘制边框线以显示打包图像边界。 | false |
combineSubdirectories | 如果为 true,则将包含设置文件和所有子目录的目录打包,就像它们在同一个目录中一样。子目录中的所有设置文件都被忽略。 | false |
flattenPaths | 如果为true,则打包后使用的图像名称将不会带上子目录前缀。这时每个子目录的图像文件名必须唯一的,不能和其他子目录下的图像文件名重复。 | false |
premultiplyAlpha | 如果为true, 则 RGB 将乘以 alpha。 | false |
useIndexes | 是否使用图像索引 | true |
limitMemory | 如果为true,则在任何给定时间内,内存中只有一个图像,但每个图像将被读取两次。如果为 false,则在打包期间将所有图像保存在内存中,但只读取一次。 | true |
grid | 如果为true,则图像将按顺序以统一的格子排列。 | false |
scale | 打包缩放设置, 为一个数字数组 | [1] |
scaleSuffix | 对于每个缩放图像,设置输出文件后缀。如果省略,多个缩放的文件将以相同的名称输出到每个缩放的子目录。 | [ "" ] |
scaleResampling | 对于每个缩放,用于将源重采样到缩放尺寸的插值类型。nearest, bilinear 或者 bicubic。 | [ bicubic ] |
1. 纹理过滤选项 纹理打包使用的过滤器为 Texture.TextureFilter 枚举类中指定的过滤器类型,上面配置的选项filterMin和filterMag的选项如下:
2. NinePatches
如果一个图像文件名在文件扩展名前以 “.9” 结尾,那么它被认为是一个 NinePatches, NinePatches图像必须有一个1px 的透明边框。上边缘和左边缘可以选择有一个连续的黑色像素线,表示分裂的信息,即哪一部分的 NinePatches 将拉伸。底部和右边缘可以选择有一个连续的黑色像素线,表示填充信息,即如何在 NinePatches 顶部的内容应插入。当这个图像被打包时,1px 的边框被移除,分割和填充信息被存储在打包文件中。TextureAtlas 允许使用分割信息为该区域创建 NinePatch 实例。
3. useIndexes(图像索引)
如果图像文件名以下划线结尾,然后是一个数字(例如 animation_23.png) ,则该数字被认为是“索引”,并单独存储。存储图像名称时不使用下划线和索引。TextureAtlas 允许检索所有同名图像的列表,并按索引排序。这在打包动画图像资源时很容易使用,而不会丢失帧的顺序。
打包完成后输出目录包含为一个文本的描述文件和一堆图像,使用示例如下:
TextureAtlas atlas;
atlas = new TextureAtlas(Gdx.files.internal("packedimages/pack.atlas"));
AtlasRegion region = atlas.findRegion("imagename");
Sprite sprite = atlas.createSprite("otherimagename");
NinePatch patch = atlas.createPatch("patchimagename");