导出到游戏引擎

「导出」窗口

导出(Ctrl+E)紧跟在窗口标题栏中的导入之后,打开一个与「导入」窗口外观相同的窗口(D51):

  1. 资产管线——开始时为标题栏资产选择框所显示的那个。它写出的内容在资产节点图中设计。
  2. 导出文件夹——输入路径,或选择…一个。项目会记住它。
  3. 立即导出——按项目当前打开的状态导出,无论是否已保存:导出从不保存项目,未命名的项目也按原样导出。

导出窗口:资产管线、文件夹、将要写出的文件以及「导出」按钮

在你按下「导出」之前,窗口会列出导出将写出的每个文件,命名方式与 pxr names 相同:每个文件都显示其在文件夹中的路径和类型(精灵表、JSON、GIF…),文件夹中已存在的文件会标注将替换。当你更改资产管线、文件夹或项目时,列表会重新生成——带一个小小的加载提示,绝不会卡住窗口。无法按原样导出的管线(比如两个输出写入同一个文件)会在那里说明原因,「导出」会等到问题修复后才可用。

按下后,这些行就在原位成为导出:每一行在写出前显示加载指示,之后显示一个勾、它的大小、打开(用系统默认的程序打开)和显示文件夹。出错时,错误信息显示在出错的那个文件上。停止会中途结束导出:已写出的文件保留,正在写出的文件被删除。导出运行时可以关闭窗口;点击「导出」会再次打开它。

它运行的正是命令行所运行的内容:pxr render PROJECT --pipeline NAME -o FOLDER,在独立的进程中运行,所以 Pixor 保持响应——针对项目当前打开状态的快照,该快照写入生成的文件夹(其中文件路径改为绝对路径),导出结束后删除。文件按 pxr render 对该项目的命名方式命名:以项目命名,未命名的项目则以其模型命名。每个文件都由管线重新写出:资产节点图中节点生成的内容从不复制。

所有文件都放进该文件夹。精灵表的文件名取自项目的 PNG 节点(out/hero.png 写出 FOLDER/hero.png);路径位于精灵表文件夹之下的文件,在 FOLDER 下保持其相对位置,其他路径(压缩包、动画、在别处命名的图标)只保留最后一部分。

导出写出的内容

每次导出都会写出一张精灵表:每个动作和朝向一行,每帧一列,所有单元格大小相同,轴心点在每个单元格中位于同一像素。在资产节点图中给精灵表添加文件节点(或在命令行中使用 --export),就会在旁边得到同名的文件。每个文件都是从精灵表连出的一个节点,带有自己的设置。--export all 会写出下面除 p8 和 video 之外的所有格式,这两种只有点名时才会写出:卡带只能容纳专为它制作的精灵表,而每个片段和朝向的无压缩视频可能有好几 GB。它们不会写入同一个文件:如果项目中有两个会写入同一文件,pxr names 会拒绝它。

格式 文件 适用场景
png name.png 精灵表,一个索引色 PNG(索引 0 为透明)
json name.json 单元格矩形、帧时长、每个动作和朝向一个标签、轴心点。采用 Aseprite 的「array」布局,因此为 Aseprite 编写的导入器都能读取
aseprite name.aseprite 一个索引色 Aseprite 文件:图层 final、lines、flat,以及风格节点图的每个额外输出各一个图层;每个动作和朝向一个标签;逐帧时长;一个 pivot 切片
normal name_normal.png 布局相同的法线贴图,用于 2D 光照
depth name_depth.png 布局相同的深度图:最近处为白色,最远处为深色,整张精灵表使用同一刻度(meta.pixor.depth 以米为单位给出两者);没有内容的地方透明。用于排序、雾效和 2.5D 光照
emission name_emission.png 每个发光像素以其自身颜色显示,亮度与发光强度一致(发光材质或模型的自发光贴图);其他地方透明。用于辉光和泛光
layers name_lines.png、name_flat.png,以及风格节点图每个额外输出对应的 name_LAYER.png 线稿和平涂颜色图层以精灵表形式输出,风格节点图指定了节点图像时也一并输出
palette name.hex, name.gpl 调色板(Lospec 和 GIMP 格式)
godot name.tres 一个 Godot 4 SpriteFrames 资源
gif name_walk_Southeast.gif, … 每个动作和朝向一个 GIF 动画,停留表现为帧延迟,用于分享和预览
apng name_walk_Southeast.apng, … 与 PNG 动画相同,带有精确的毫秒延迟
video name_walk_Southeast.avi, … 每个动作和朝向一段视频:未压缩的 AVI,每个像素保持原样,用于预告片或商店页面
light-kit name_ramps.png、name_normal.png、name_light.png、着色器 在引擎中实现调色板正确的光照(参见下文)
报告 name_report.png 标出每项检查结果的精灵表(参见下文)
p8 name.p8 一个 PICO-8 卡带(参见游戏机模式)
zip 它节点上的路径 资产节点图中的一个 ZIP 压缩包节点:连接到它的文件,或者导出写出的全部内容

每一行以其动作和朝向命名:walk_Southeast。

精灵表取用哪些帧、如何排列,以及一次渲染写出多少个文件,都由资产节点图决定:在你重新连线之前,是一个「精灵表」节点及其「文件」节点。

帧的名称,以及它们是什么

精灵表中的每一帧都有一个名称和一个 id,它们回答两个不同的问题。

名称是一个模板,一种基于你项目自身词汇的模式,因此简单的默认值正是新手想要的,而工作室也能遵循并非由它自己制定的命名规范:

{project}_{action}_{side}_{index:2}.{ext}     hero_walk_East_00.png

可用的词有 {project}、{object}、{action}、{side}、{layer}、{set}(「精灵」节点绘制该帧所用的部件组)、{size}、{index} 和 {ext}。{index:3} 会用零把数字补足三位。{{ 和 }} 写出一个花括号。Pixor 不认识的词会在你输入模板时报错,而不会生成一个名为 hero_{genre}_00.png 的文件;内容为空的词会连同它前面的分隔符一起省略,因此没有朝向的精灵是 hero_Static_00.png。

不能用于文件名的值(/ \ : * ? " < > |)会被拒绝,而不是悄悄替换;空格会变成 _。唯一的例外是 Pixor 自己的词:名为 lib:walk 的库片段在名称中写作 lib-walk,因为那个冒号属于 Pixor,而不是你。

两帧如果会得到相同的名称,会在渲染任何东西之前就被拒绝。在命令行中用 --names 设置,或保存在项目中:

pxr project set hero.pixor --names '{object}/{action}-{side}-{index:3}.{ext}'
pxr names hero.pixor                  # what it will write, without rendering
pxr names hero.pixor --json           # the same, for a build script

ID 说明的是帧是什么,而不是它落在哪里。它是物体、动作、朝向、动作中的时间和图层的哈希值,写在 JSON 中每一帧的旁边以及 .aseprite 的用户数据中。重新打包精灵表、添加片段或修改内边距只会移动矩形,不会改变 ID,因此按 ID 引用帧的构建不会在每次运行打包器时都出问题。以另一种帧率重新采样片段确实会改变它的 ID,因为那是不同的帧。

更小的精灵表

在资产节点图的排列节点上(或在命令行中):

  • 裁剪空白(--trim)把每一帧裁剪到只剩它的像素。JSON 给出每一帧在完整格子中的位置(spriteSourceSize、trimmed: true),Godot 文件则设置每一帧的 margin,因此引擎仍会把每一帧放在轴心点上。
  • 重复帧只存储一次(--dedupe):完全相同的帧(停留的姿势、静止物体的各个朝向)共用同一个位置。
  • 精灵表最大宽度(--max-width 4096)在精灵表变得更宽之前另起一行,适用于有纹理尺寸限制的引擎和 GPU。
  • 精灵表最大高度(--max-height 2048)把超过此高度的精灵表拆分为多页,每页放完整的片段:hero_1.png、hero_2.png,各自附带 JSON 和其他文件。
  • 每行帧数(--columns 8)在一行中放这么多帧,每个片段紧接着上一个排列:即缩略图表,或引擎导入器要求的固定网格。
  • 由另一个朝向生成的朝向(资产节点图的翻转节点):左右对称的模型,从左边看和从右边看再翻转是一样的,所以西侧根本不必渲染——取东侧摄像机的精灵,翻转为西,精灵表中的 walk_West 就由 walk_East 生成,像素、法线、碰撞框和根运动都会镜像。只渲染彼此不同的摄像机,其余的翻转即可。
  • 每个朝向的角度都写在 JSON 中:每一帧上(pixor.degrees),以及汇总在 meta.pixor.sides 下({"South": 0, "Southeast": 45, ...}):从正面起算的角度,从上方看为逆时针,与 --sides 的取值方式相同。游戏用这张表把角度换算成行。

阴影图层

阴影图层(--shadow contact 或 --shadow drop)会写出 name_shadow.png,排布与精灵表相同:阴影落下的地方为黑色,其余地方透明。接触是脚下的一团阴影,大小与模型的占地面积相符;投射是背离主光投在地面上的剪影。用你喜欢的不透明度把它画在精灵下方,或单独排序。资产节点图的「图层」节点可以指定 shadow,再用「叠加」把它放到同一张精灵表的精灵下方(资产节点图)。

运行时的颜色循环

使用循环材质时,JSON 会在 meta.pixor.cycles 下列出每种材质("material" 及其在调色板中的 "indices",按循环顺序排列),Pixor 还会写出 name_index.png,即以调色板索引表示的精灵表。引擎可以在每个 tick 轮换这些调色板条目,而不必存储更多帧。与其共用相同明暗色的其他材质也会随之循环,这与任何调色板循环一样;要让循环材质独立,就给它单独的颜色。

多个模型的场景与视差背景

一个项目可以包含不止一样东西:多个模型摆放在地面上,渲染成一张图,共用一个光源,彼此之间有阴影——一个村庄角落、一间地牢房间、一处营地,或用免费素材库制作的商店页面美术图。

每一项都是一个物品:一个模型,它所在的位置、朝向和大小——即场景节点图中的一个物品节点,添加在其链的末尾,后面的环形或散布会重复它。在命令行中,每个 --item 就是一个:

pxr project new camp.pixor \
  --item tent.glb@-1.8,-1.6,25,1.2 \
  --item campfire.pixoritem@0,0 \
  --item barrel.glb@2,1,0,1,2 \
  --ground 7,5,#5d7a45 \
  --size 200
pxr render camp.pixor

@x,z[,yaw[,scale[,layer]]] 是物品所在的位置(单位为米,x 向右,z 朝向摄像机);--ground W,D[,#rrggbb] 在它们下方放一个地面。加上 :clip[,phase],该物品就会播放自己的片段,从片段中自己的位置开始,而旁边的物品保持静止。路径相对于项目。

视差图层(一个视差图层文件节点,2 到 8 层,或 --parallax N)按深度把画面拆分成图层,用于卷轴背景:每层都在同一舞台、用同一调色板单独渲染,越远的图层越暗、越偏蓝,向雾的颜色(--haze)过渡,就像远处看起来那样(关闭远处图层加雾,或使用 --haze none,则每层都按原样保持在调色板上,适合调色板固定的游戏)。物品的 layer 把它放到某一层(0 是最远的一层);其余的按深度分配。Pixor 会写出 name_layer0.png、name_layer1.png……、name_parallax.json(每层的图像和建议的滚动速度,最远层为 0.25,最近层为 1)和 name_parallax.png(所有图层叠在一起)。任何模型都可以拆分,不只是由多个模型组成的场景。资产节点图的「图层」节点以 layer0、layer1…… 命名图层,把它放到它自己生成的精灵表上(资产节点图)。pxr project set --parallax N --haze #rrggbb|none 会在项目上同时设置两者。

游戏机模式

对于自制主机和幻想主机,在「风格」下选择一个控制台(或 --console)。Pixor 随后使用该主机自身的颜色及其限制:

游戏机 颜色 每个精灵 注释
Game Boy 4 种绿色明暗色 3 + 透明 按亮度排列的明暗色
NES 54 色主调色板 3 + 透明 也按 8 × 8 图块检查
PICO-8 它的 16 全部 16 导出 .p8 卡带(勾选 p8;精灵表必须能放进 128 × 128:将最大宽度设为 128)
TIC-80 它的 16(Sweetie 16) 全部 16 用 TIC-80 的 import sprites 导入 PNG
C64 它的 16 3 + 透明 多色精灵:像素宽度加倍;保持宽度为偶数(C64 精灵为 24 px)

当精灵只能使用三种颜色时,Pixor 会挑选最能覆盖模型阴影、基础色和亮部的三种游戏机颜色,因此每一帧、每个朝向都使用同样的三种颜色。风格部分会说明屏幕上的帧是否符合要求;pxr console check sheet.png 会检查整张精灵表(颜色、每帧和每个图块的颜色数、双宽像素对、尺寸),并从精灵表内的配方中读取游戏机类型。在游戏机模式下,每次渲染都会对写出的精灵表执行同样的检查,不符合时会失败(退出状态 1,并列出问题)。你自己的调色板在游戏机模式下会保留,而不会被游戏机的调色板替换——因此在 Game Boy 上使用十六色调色板会被明确指出,而不是悄悄换成那四种绿色。NES 的颜色由 Pixor 根据游戏机的视频信号计算得出,其他游戏机使用其公开的数值。

引擎中符合调色板的光照

引擎用法线贴图配合平滑着色给精灵打光,会引入调色板里从未有过的颜色。勾选灯光套件(或 --export light-kit),精灵就能响应游戏内的光照,同时每个受光像素都保持在自身色阶的某一级上,保留 Pixor 的色带、色相偏移和高光。Pixor 会在精灵表旁写出:

文件 是什么
name_ramps.png 每个像素的色阶(红色通道中为色阶编号 + 1;光照不影响的像素,如线条,为 0)
name_normal.png 法线,视图空间:x 向右,y 向上,z 指向摄像机
name_light.png 查找纹理:每个色阶一行,每个光照级别一列,然后是高光颜色,再然后是两列根本不是颜色的数据——该色阶自身的高光阈值,因为光泽或金属材质比哑光材质更容易出现高光
pixor_palette_light.gdshader, name_light.tres Godot 着色器,以及设置好所有纹理的材质:把材质放到 Sprite2D 或 AnimatedSprite2D 上
PixorPaletteLight.shader Unity 着色器:用它为 SpriteRenderer 创建材质,并设置三张贴图
pixor_palette_light.fsh, .vsh GameMaker 着色器;注释说明了如何绑定贴图

这些着色器用一盏主光(light_dir,指向光源,位于法线空间中)、预设的补光,以及镜面高光和轮廓高光进行照明,高光的阈值按色阶从查找纹理中读取,与 Pixor 自身的做法相同。把 specular 或 rim 设为 -1 到 1 之间的数值,会对整个精灵覆盖它们;大于 1 则关闭这些高光;小于 -1(默认值)则使用查找纹理中的值。只有当四个相邻像素之一也有高光时才会绘制高光,这是 Pixor 自己防止孤立亮像素的规则——min_highlight 设为 1 即可关闭它。可以用脚本移动灯光,例如朝向一支火把:material.set_shader_parameter("light_dir", dir)。导入这三张贴图时不要过滤、不要压缩、不要 mipmap。要在导出前查看效果,在精灵上开启 2D 光照预览(L),并选择光照方式:灯光套件:灯光会转向指针,画面通过同一张查找纹理、按同样的规则(高光只出现在另一个高光旁边,没有色阶的像素不受影响)进行照明,与着色器的效果一致。使用渲染时的灯光,画面看起来与 Pixor 绘制的完全相同(例外是色带边缘的少数像素);投射阴影、抖动以及动画精灵表的闪烁平滑是 Pixor 独有的,因此对于要在引擎中照明的精灵表,请关闭投射阴影。JSON 在 meta.pixor.light_kit 下列出这些文件和灯光。

调色板变体

添加变体(--variant NAME,可重复)以其他颜色导出同一张精灵表。Pixor 以调色板索引绘制,所以变体只改变调色板:每个像素、线条和明暗都保持原位。

  • 效果:hit-flash、frozen、poisoned、petrified、burning、silhouette、selected,时段 dawn、noon、dusk、night,以及季节 autumn 和 winter(绿色变成橙色,或变得苍白、覆雪)。
  • 队伍颜色:team:blue(或 red、green、yellow、purple、orange、teal、pink、white、black,或 team:#3050e0)只为队伍颜色重新着色——即用 --team 或在材质下标记的材质或颜色——皮肤、钢铁和黄金保持原样。每种明暗色都保持原有亮度,因此色阶依然清晰可辨。一个精灵生成四支队伍:--team cloth --variant team:red --variant team:blue --variant team:green --variant team:yellow。JSON 在 meta.pixor.team 下列出队伍的调色板索引,供在运行时通过下方查找纹理重新着色的引擎使用。
  • 所有颜色旋转:hue:120 把每种彩色明暗色的色相旋转 120 度;灰色保持灰色。
  • 其他调色板:palette:pixor-8 或 palette:my-colours.hex 会把每种颜色移到该调色板中最接近的颜色,同时保持明暗分开。

每个变体都是 name_<variant>.png。只要有变体,Pixor 还会写出两个用于运行时交换调色板的文件,这样一张精灵表就能用于每个等级和队伍:

  • name_index.png:每个像素以灰度值表示其调色板索引的精灵表(0 表示透明);
  • name_lut.png:一张宽 256 像素的查找纹理,每套调色板一行(第 0 行是精灵表自身的,第 k 行是变体 k)。

着色器查找 lut(index / 255, row)。JSON 在 meta.pixor.variants 下列出变体及其所在行。

每次导出中都包含的配方

Pixor 导出的每个文件都记得生成它的项目:精灵表、它的图层表和贴图(_lines、_flat、_normal、_depth、_emission、_shadow)、调色板变体和索引表、.aseprite,以及每个 GIF(在注释中)和 APNG。把其中任何一个拖到 Pixor 上(或在打开项目中选择它),就能找回项目:如果 .pixor 文件还在就打开它,否则根据配方重建一个新项目。路径以相对于导出文件的形式保存;无法转为相对路径的只保留文件名,所以你分享的精灵表不会暴露你的文件夹名。取消勾选文件中的配方(或传入 --no-recipe)即可不写入配方。

Godot 4

  1. 把 name.png 和 name.tres 一起复制到你的项目中,放在同一目录。
  2. .tres 从 res://name.png 加载精灵表。如果你把它放在别处,从命令行导出时传入 --godot-path res://path/name.png,或编辑 .tres 顶部的路径。
  3. 创建一个 AnimatedSprite2D,把它的 Sprite Frames 设为 name.tres。每个动作和朝向都是一个循环动画,并带有帧停留。
  4. 要得到清晰的像素,请把 Texture > Filter 设为 Nearest。

Unity

  • 使用 Aseprite Importer 包(2D Aseprite Importer):把 name.aseprite 拖进 Assets。每个标签都会变成一个动画片段;使用 final 图层。
  • 不使用它时:把 name.png 作为 Sprite(Multiple)导入,Filter Mode 设为 Point,Compression 设为 None,并按格子大小切片(格子大小在 name.json 的 meta.pixor.cell 中)。轴心点在 meta.pixor.pivot 中,以距格子左上角的像素数表示。

GameMaker

把 name.png 作为精灵长条导入:每个动画用 Strip 布局导出(--layout strip),或按单元格大小切分网格。把原点设为 name.json 中的轴心点。

Aseprite

打开 name.aseprite,或在 Aseprite 文件节点上点击打开(Pixor 会在 PATH 以及常见的 Steam 和 itch 文件夹中查找 Aseprite,找不到时会询问位置)。标签列出了每个动作和朝向。final 图层可见;lines 和 flat 是用于手工修饰的隐藏辅助图层,风格节点图命名的每个额外输出也是,位于 final 之上。文件为索引色模式,使用 Pixor 的调色板。

在上面绘制,并保留你的作品。添加你自己的图层并绘制,然后在 Pixor 中修改模型或外观,再重新烘焙:

pxr rebake out/hero.aseprite

Pixor 只管它写出的内容,别的一概不碰。重新烘焙会再次渲染项目,并且:

  • 在无人绘制过的地方,替换 Pixor 生成的图层(final、lines、flat)的像素;
  • 完全保留你的图层——从不移动、重命名、重新排序或重新上色——并且每个绘制的画格都留在绘制时所在的帧上。每一帧都带有一个由其内容(动作、朝向、时间)构成的 id,因此如果行走动画在中间增加了三帧,你画的眼睛仍会留在原来的姿势上,而不会滑到新的姿势上——重新烘焙还会逐帧说明这一点:moved your paint on frame 1 is on frame 2 now,以及哪些帧是新增的(--json 中的 moved 和 new_at);
  • 让你绘制时使用的每种颜色保持原有索引,新颜色添加到调色板末尾——或者,如果你在 Aseprite 中把精灵表转成了灰度或 RGB,就相应地以灰度或彩色写出渲染结果;
  • 保留你的切片,它们的关键帧仍位于原来的帧上,无论这些帧移到了哪里;
  • 用标签标出模型从你的绘制下方移开的帧,pxr check,并让绘制内容保持原位。

有两件事它不会自行决定,在你决定之前会把两者都保留:

发生了什么 重新烘焙做了什么
你在 Pixor 自己的某个图层上绘制了内容 Pixor 的图层得到新的渲染;你的修改移到正上方你自己的图层 final edits 中;该帧被标记为 pxr conflict
你绘制过的某一帧不在新的渲染中(片段变短了) 该帧会连同你的绘制保留在末尾,并标记为 pxr removed

两种方式都不会丢失任何东西。在你指定怎么做之前,pxr rebake 会以退出码 7 退出:--resolve keep 把你的修改保留为你自己的图层,--resolve pixor 采用 Pixor 的渲染并丢弃修改。--dry-run 说明重新烘焙会做什么,但不写入任何内容;--json 以供工具读取的形式说明;扩展则会在对话框中问你同样的问题。

GIF 与 APNG

每个动作和朝向都成为一个单独的循环文件(不循环的片段只播放一次)。帧使用精灵的调色板,索引 0 为透明。GIF 或 APNG 节点上的比例(--anim-scale K)按整数倍放大,取值从 1 到 16,因此 64 px 的精灵可以输出为 256 px 的 GIF,每个像素依然清晰。

GIF 以百分之一秒为单位存储延迟,所以每帧的延迟会被取整,但片段的总时长保持不变。浏览器会把低于 20 ms 的延迟显示为 100 ms,因此 GIF 的帧不会短于 20 ms:高于 50 fps 时,GIF 会省略那些显示时间更短的帧,播放时长与片段一致。APNG 存储精确的毫秒数,与 JSON 一样按累计时间取整,所以 12 fps 片段的帧为 83 和 84 ms。如果网站只接受 PNG,可以把 .apng 文件重命名为 .png。资产节点图的图层节点所绘制的片段,会按精灵表的显示方式为该图层生成动画——只有线条、只有平涂颜色;法线、深度或自发光贴图的图层则为精灵生成动画,因为 GIF 只能容纳调色板颜色。

视频

每个片段一段视频会把每个动作和朝向写成 name_walk_Southeast.avi:一个无压缩的 AVI,24 位色,任何编辑器和转换器都能打开,而且毫无损失——没有编解码器会把像素抹糊。它的节点有三项设置:

  • 比例(1 到 16,初始为 4):一个美术像素对应多少个视频像素。
  • 每秒帧数(1 到 100,初始为 30):视频以单一速率播放,所以精灵帧按其持续时长重复写入多次,片段的长度误差保持在一个视频帧以内。
  • 背景:精灵后面的内容。视频没有透明度。

命令行中的 --export video 使用初始值,或使用 --video-scale K、--video-fps N 和 --video-background #RRGGBB。--export all 不包含视频:需要单独指定。

它没有压缩,所以很大——比例为 64 的 4 px 精灵每帧约 200 KB——超过 1 GB 的视频会被拒绝写出。要放到网上,请先转换:ffmpeg -i hero_walk_South.avi -crf 0 hero_walk_South.mp4。

普通引擎和你自己的代码

读取 name.json:frames[i].frame 是单元格矩形,frames[i].duration 是它的停留时长(毫秒);meta.frameTags 把帧分组为动画,只播放一次而不循环的标签带有 "repeat": "1",与 Aseprite 的写法相同。frames[i].pixor 记录帧的 tag(所属帧标签的名称)、它在其中的 index、它的 action 和 side、它的 id,以及它的 pivot——引擎在单元格中放置精灵的点,除非某个标签节点为该片段指定了自己的轴心点,否则就是精灵表的轴心点。meta.slices 中的轴心点切片在轴心点变化处都有关键帧,.aseprite 文件中的轴心点切片也有同样的关键帧。

根运动

以原地导出的片段每帧多两个值,以像素为单位并保留小数(x 向右,y 向下):

  • frames[i].pixor.root:模型根骨骼所在的位置,从片段开始时的位置算起。
  • frames[i].pixor.root_delta:根骨骼到下一帧移动的距离。对最后一帧而言,它是到片段结束时的移动量,因此循环行走会保持相同的速度。

要让角色像片段中那样移动,在每帧结束时把 root_delta 加到精灵的位置上。

物品栏图标

pxr icons(或资产节点图中的图标节点,在导出项目时生成)把模型变成风格统一的物品栏图标:每个模型都在工作室灯光布置下以相同的 ¾ 角度渲染,尺寸为 16、24、32 和 48 像素(或用 --sizes 指定),剪影使用其稀有度的颜色(--rarity common|uncommon|rare|epic|legendary),使用 --framed 时放在类似物品栏格子的带框图块上。每个图标是一个 PNG,每个尺寸生成一张图集 icons_N.png,并附带说明每个图标位置的 icons_N.json。指向一个文件夹,就能把整个素材包变成一套图标——在应用中,把文件夹拖到窗口上并开启用图标代替精灵:尺寸、稀有度(除非你指定,否则取自每个文件的名称)和边框都在那里,配方会作为 icons.pixoricons 保存在图标旁边:

pxr icons library/pickups --out icons --rarity epic --framed

--rarity from-name 根据文件名中的某个词为每个模型赋予稀有度(potion_rare.glb、Sword-Epic.glb;没有这类词则为普通),JSON 中会写明每个图标的稀有度。文件按名称顺序读取,所以无论文件夹如何排列,图集都相同。

配方保存整套图标包:--save pack.pixoricons 写出文件夹和设置(路径相对于配方),pxr icons pack.pixoricons 会逐字节重新生成图标包。加入文件夹的道具会在下次运行时加入;配方后面的参数只修改该次运行的一项设置(pxr icons pack.pixoricons --sizes 64)。

体素与精灵堆叠

MagicaVoxel 的 .vox 和其他模型一样打开:其场景中的每个模型都放在场景节点图指定的位置(按 MagicaVoxel 中显示的方式旋转和移动),包括它的调色板,发光材质的体素也会发光。一个体素按十分之一米读取,+Z 朝上。

pxr voxels MODEL -o hero.vox --height 32 把任意模型转换为体素,高 32:表面从其纹理和颜色中采样,内部填充,每个体素都使用外观自己的调色板(--preset、--palette 及其他外观选项),所以体素与精灵一致。加上 --stack 还会写出精灵堆叠:hero_stack.png 把模型切成水平切片并排排列,从底部开始,每片都从上方看;hero_stack.json 记录切片的尺寸和数量。游戏把第 k 片画在第 k - 1 片上方一个像素处,并让它们一起旋转,精灵堆叠就是这样模拟 3D 的。

pxr voxels knight.glb -o knight.vox --height 32 --stack --preset selout

检查一切是否匹配

pxr audit folder --style game.pixorkit 读取文件夹中每个导出的 PNG 和 .aseprite 文件,并依据每个文件内的配方对照套件进行检查:预设、灯光布置、视图、摄像机俯仰、主光、光照色带、线条、调色板和每米像素数,以及它用到的每种颜色是否都在套件的调色板中。没有套件时,以第一个文件为参照。每一处差异都会列出;只要有差异,退出状态就为 1,因此可以用来把关构建。

在应用中,一致性面板(三个人形的按钮,一致性面板:同时显示所有朝向,或按 B)会把当前帧的所有朝向并排显示在同一条地面线上,标出每个剪影的顶部,并在下方列出其宽度、高度和颜色数。按钮下方:

  • 剪影把每个朝向都只画成其形状,只用一种颜色:一个剪影看不懂的姿势,在游戏尺寸下也看不懂。
  • 轴心点标出每个朝向站立和转动所围绕的像素。双脚不在轴心点上的朝向会在精灵转身时滑动。
  • 颜色数量写出每个朝向的颜色数;当各朝向之间高度相差超过一个像素(各朝向之间高度不同…),或某个朝向比另一个多出好几种颜色(通常是只有一侧受光)时,看板会给出提示。

上面的 pxr audit 是针对整个文件夹的那一半:每张精灵表都对照同一个套件。

检查发现的问题,标在相关像素上

Pixor 所做的每项检查——孤立像素、单像素画出的线条拐角、过粗的线条、调色板外的颜色、颜色数超出游戏机模式限制的图块或帧——都会标出涉及的像素,而不只是在导出时打印一行文字。

  • 在应用中:精灵上方的检查按钮(警告三角形)会在帧上画出标记,风格和资产步骤中的报告区域列出迄今渲染的每一帧的每个问题。点击其中一项,Pixor 会跳到那一帧和朝向,并显示标记。在列表下方,每类问题都会说明由哪个设置决定——孤立像素由清理决定,锯齿拐角由线条决定,颜色由调色板决定,游戏机限制由游戏机模式决定,翻转后与导出镜像不一致的朝向——转到会打开该设置。
  • 镜像朝向:资产节点图中有「翻转」节点时,将被翻转绘制的朝向会与其翻转来源比较,如果模型不够对称,会在你还在选择时就标出会发生变化的像素——而不只是在导出时给出警告。
  • 导出时:勾选报告(或 --export report),Pixor 会在精灵表旁写出 name_report.png:标出了每个问题的精灵表。单个像素会被填色;图块或帧会被框起来,所以相关内容仍然可见。
颜色 内容
青色 孤立像素(orphan)
黄色 在一个像素内转角的线条
品红色 两像素见方的线条块:粗线条
红色 不在调色板上的像素
橙色 颜色数超出游戏机允许范围的 8 x 8 图块
深橙色 颜色数超出游戏机允许范围的帧
粉色 游戏机没有的颜色
紫罗兰色 与其镜像来源一侧不同的像素
绿色箱子 因纹理文件缺失而以纯色绘制的部件:把文件放到模型旁边

像素效果

场景节点图中的效果节点(在大纲的效果下列出)会添加一个由 3D 粒子绘制的效果:爆炸、命中火花、斩击、魔法爆发、治疗、传送门、烟团、尘土、循环火焰、雨、雪、萤火虫和落叶。每个都是单独的动作(fx-explosion……),经过与模型相同的管线渲染,因此使用精灵的调色板、像素大小、光照和线条:看起来就像同一个游戏里的东西。可以设置它的帧数、大小、能量、位置和种子(相同的种子总是得到相同的像素);让它跟随一根骨骼(从手中发出的斩击、枪口的闪光),并在某个片段上播放(斩击下的挥动,或在 Pixor 中设置关键帧的片段);勾选仅效果可以不画模型,只把它画成与角色精灵表对齐的单独图层。命中帧标记打中目标的那一帧:JSON 在 meta.pixor.hits 下列出它。命令行:--effect fireflies:12 --effect-clip shatter --effect-hit 6,片段也可以是在 Pixor 中制作的——在闪光下设置碎片飞散的关键帧。空项目界面上与导入…和浏览免费模型并列的创建效果(或 pxr effect explosion -o fx.png)可以完全不用模型生成效果。

碰撞框、受击框和挂点

检查器中部件的包围盒(或 --hitbox、--hurtbox)会把它设为碰撞框(造成伤害:剑)或受击框(可被击中:身体),骨骼的 JSON 中的挂点(或 --socket)则把它设为挂点(手、枪口)。这样每一帧的 JSON 都会带有 pixor.boxes(part、kind、x、y、w、h,以格子像素为单位,取自每个部件实际覆盖的像素)和 pixor.sockets(每根骨骼以格子像素表示的位置),游戏代码无需猜测就能检测命中和挂载特效。模型文件也可以标记部件(pxr.box)。

纸娃娃图层

挂载了道具时,纸娃娃图层(--paper-doll)还会写出 name_base.png,即在同一画布上不带道具的模型,以及每个道具一个图层(name_sword.png),包含其可见像素及周围的线条。从底层开始叠放,就能得到完整的精灵表;替换道具的图层即可更换装备。name_stacked.png 是按这种方式叠放的结果,与引擎的叠放方式相同:用于确认它们能对齐的预览。每一块的像素都与精灵表完全相同;底层是不带这些部件绘制的身体,因此它与精灵表的差别仅在部件边缘几像素范围内,以及部件在身体上投下阴影的地方——如需精确叠放的图层,请关闭投射阴影(--no-shadow)。「精灵」节点用部件组绘制的行属于该节点自己的精灵表,不属于这些图层。(应用会用 pxr 从已保存的项目生成它们,项目有改动时会先保存,因此图层就是屏幕上显示的内容。)

属于模型一部分的装备——与角色一起建模、而不是作为道具挂载的头盔、盾牌、披风——是一个部件:

pxr render knight.glb --clip all --paper-doll --piece helmet:Knight_Helmet --piece gear:Round_Shield,1H_Sword
pxr project set knight.pixor --paper-doll --piece helmet:Knight_Helmet

每个配件列出它由哪些部件组成(与大纲中列出的名称一致),并成为一个单独的图层 name_helmet.png,与道具完全一样(在应用中,部件的自己的纸娃娃图层会让它成为一个配件,并以它命名):只包含可见的像素,所以身体后面的盾牌在被身体挡住的地方是隐藏的。底图渲染时不含任何配件和道具,所以头盔遮住的部分——下面的头——会画出来。--no-pieces 会从项目中清除配件。资产节点图的图层节点以 base 或配件、道具的名称作为图层,按需要排布这些图层(资产节点图)。

在浏览器中免费用你自己的模型试试本页介绍的内容。

在浏览器中试用 获取 Pixor