runtime/ 是一个独立的 Rust 库(MIT),播放 PSD2Live 编译出的 .p2lrt 模型:参数驱动的变形、物理和动作片段,提供 C ABI 给其他语言和引擎调用。编辑器通过 :format-eval(JNA)调用同一个库。
| 部分 | 位置 | 许可证 |
|---|---|---|
.p2lrt 写出与导出目标 p2lrt |
:targets:runtime(P2lrt、P2lrtTarget) |
MIT |
| 读取、求值、物理、动作片段、C ABI | runtime/(crate p2l-runtime,cdylib + staticlib) |
MIT |
| C 头文件 | runtime/include/p2l_runtime.h |
MIT |
| JVM 绑定 | :format-eval(P2lRuntime、NativeGeometryEvaluator) |
MIT |
| 网页播放器 | :targets:web(导出目标 web:页面、p2l.js、运行时的 WebAssembly 构建) |
MIT |
Godot 4 节点 P2LCharacter |
runtime/godot/(GDExtension,godot-rust,Godot 4.3+),演示工程 runtime/godot/demo/ |
MIT |
构建:在 runtime/ 运行 cargo build --release,库位于 runtime/target/release/(Windows 为 p2l_runtime.dll)。Gradle 的 buildRuntime 在有 cargo 时自动构建:./gradlew run 使用它,打包时随应用资源分发;没有 cargo 时跳过,应用回退到编辑器求值器。P2lRuntime.locate() 依次查找系统属性 psd2live.runtime.library、环境变量 PSD2LIVE_RUNTIME(文件或目录)、系统属性 psd2live.runtime.dir、打包应用的资源目录和 java.library.path。
编辑器的导出烘焙(Spine、DragonBones、glTF)在运行时库可用时经 NativeGeometryEvaluator 求值,否则使用引擎求值器;两者逐姿势一致。编辑器软件预览(RigCanvasSupport.evaluate)同样经 NativePreview 使用运行时:首次遇到某个预览模型时由引擎作答并在后台编译,之后的帧走运行时;拖动中的临时模型不等待编译,失败或 -Dpsd2live.preview.runtime=false 时保持引擎。在带骨架的 tml 上单次求值约 0.5 毫秒,与引擎相当(JNA 调用与结果转换抵消了原生速度)。
预览画布可以选用运行时作为预览后端(「PSD2Live 运行时(p2lrt)」,见 CANVAS_RENDERER.md):后台把预览模型编译为 .p2lrt(含模拟),运行时按工作区时钟给出的完整姿势求值,P2lrtGlRenderer 按网页播放器的规则在窗口自己的 Skia OpenGL 上下文中绘制。扩展(高级)模式开启时每个视图的模型开启蒙皮与精确链接;实时模拟与碰撞由预览的物理开关控制(开启时以 p2l_update_stages(dt, P2L_STAGE_SIM) 按帧时间只推进实时模拟,暂停也不停;关闭时显示烘焙摆动)。工作区已经合成的物理结果直接保留,运行时不重复计算物理,程序化行为保持关闭。后台编译同时准备并缓存蒙皮权重,视图通过共享模型创建各自的姿势和模拟实例,切换模式不在渲染线程重新拟合。Cubism SDK 不可用时预览自动改用它。
扩展只作用于模型实际携带的数据:无适用扩展或仅有模拟扩展而物理关闭时,预览状态会说明原因。未烘焙的模拟不提供实时模拟数据;已启用且已烘焙的模拟若构建或校准失败,编译会报告具体模拟,避免静默丢失扩展。
小端二进制,是编译后 IR 的紧凑表示:画布、参数、变形器(父级在前)、部件、网格、Glue、绘制树、贴图页、物理组、动作片段和参数角色(如 EyeBlink、LipSync)。引用一律为索引。
导出默认写版本 2:文件头、块目录和 16 字节对齐、带 CRC 的块,字符串集中在字符串表,数组带编码并 4 字节对齐,另有参数面板(PGUI)与生成器信息(META)。布局与演进规则见 P2LRT_V2.md。导出选项 v1 写版本 1(单一顺序流,逐字段布局见 P2lrt.kt 的文档注释),供尚未更新的播放器使用;compress 用 deflate 压缩能变小的块(贴图页除外),strip_names 去掉显示名称、保留 id。
读取器(runtime/src/rig.rs、container.rs)同时读两个版本,解析为同一个 Rig,求值代码只有一份;校验引用、网格索引、关键形尺寸、块的位置与对齐、块内记录是否正好读完,跳过不认识的可选块,遇到不认识的必需块报出其标签。块可用 deflate 或 zstd 压缩(导出设置 compress,加 zstd 用 zstd)。
求值输出每个网格在画布像素坐标(y 向下)中的顶点、透明度、乘算/屏幕色和绘制顺序。规则全部通过黑盒探测编辑器求值器得到(WarpProbeTool、RuntimeConformanceTool),未参考其实现:
- 参数:钳制到范围;循环参数只回绕范围之外的值,两端保持原值。
- 关键形网格:多线性插值。值与某个关键点相差小于 0.001 时取该关键点。稀疏网格中缺失的格子按零形状计入(网格偏移为零,变形器的绝对形状为原点),权重不重新分配。标志通道(翻转)取不大于当前值的关键点。
- Warp:单位正方形内按格子双线性或沿 (1,0)–(0,1) 对角线分成两个三角形插值;外部在 [-2, 3]² 内用一层较粗的虚拟格子延伸,额外格点取格子四角的平均仿射框架,按三角形插值;更远处只用仿射框架。
- 旋转变形器:角度为关键形角度加基准角。父级为旋转时,原点经父级变换,角度和缩放与父级叠加;父级垂直翻转或父级缩放为负时,子框架额外旋转 180°;父级水平翻转不影响子框架方向;自身翻转只作用于子坐标。父级为 Warp 时,框架保持刚性:原点经格子映射,角度随格子在原点上方 0.1 处沿 v 方向的走向旋转,缩放继承格子上方最近旋转的缩放。
- 混合形:每个绑定按参数在相邻关键点之间线性混合(不取整到关键点),中性关键点和没有形状的关键点不贡献;权重乘以各限制参数的分段线性系数。变形器和通道的形状是目标值,叠加的是“目标 − 默认姿势下的值”;网格形状是目标偏移,叠加的是“目标偏移 − 默认姿势下的偏移”。
- 透明度:每一级(变形器、网格)先钳制到 [0, 1] 再与父级相乘;部件透明度不计入网格透明度。
- Glue:在全部变形之后,每对顶点各自按自己的权重乘强度向对方移动。
- 绘制顺序:每个绘制组按子项的绘制顺序排序,子组以其部件按通道与混合形求出的绘制顺序为键(无部件时取静态值);键加千分之一后取整,相同时保持树中顺序;隐藏网格不绘制。规则取自引擎渲染顺序接口的文档说明,未与原生渲染逐帧比对。
文件中的扩展块提供 Cubism 等价求值之外的功能,全部默认关闭;p2l_set_advanced 开启,关闭时求值与核心求值逐位一致。布局与语义见 P2LRT_V2.md。
- 运行时蒙皮(
P2L_SKIN):在膝、肘等关节处弯折的网格,烘焙时按键取样,键之间沿弦插值。运行时把骨骼框架逐顶点两骨线性混合,加上“当前混合 − 混合在键之间的插值”。这在每个键上为零,键之间把弦换成弧。权重在开启时拟合到烘焙的关键形;骨架裁剪或折叠掉的骨骼作为虚拟骨骼随文件提供,宿主可通过p2l_bone_*读取骨骼变换来挂接物件。 - 精确链接(
P2L_EXACT_LINKS):键控在同一圆上的枢轴沿圆弧插值。 - 实时模拟(
P2L_SIM)与碰撞(P2L_COLLISION):已烘焙的布料与头发以编辑器的 XPBD 求解器实时运行,替换烘焙的模式参数与摆锤;碰撞体是沿网格顶点的圆或胶囊。
验证:advanced_tests(已知解析解的手臂、链接、虚拟骨骼和悬挂网格);p2lrt-conformance --advanced 要求每个样例在蒙皮的键上与烘焙一致(全部为 0);--sim 用 RuntimeConformanceTool.simulation 的随机布料轨迹比较求解器,与编辑器逐位一致(含碰撞);--sim-rig 用 tml 后发的烘焙模拟端到端比较,前半秒误差 0.21 像素,全程平均 0.22 像素。差异来自两边求值目标时约 1e-4 像素的浮点差,布料会把它放大。
按 Cubism 运行时读取 physics3.json 的方式实现,包括其特有行为:输入按参数范围中点归一化;固定步长(Fps)时在帧间插值输入、输出在最后两步之间插值;不限步长时输出滞后一帧;平移旋转时复用已旋转的 x;只有角度输出带缩放,平移输出的缩放为零;超过 5 秒的积累时间清零。与编辑器 PhysicsEngine 在随机摆锤组和样例模型上逐帧比较,误差小于 2e-5。
另有 Cubism 运行时的三项:纵向(Y)输入输出(PHYS 版本 2,见 P2LRT_V2.md;编辑器与 Cubism Editor 都不产生纵向,physics3 导出可写出)、风力(p2l_physics_wind,加到每个粒子受的力上,与 physics3 的 Wind 相同)和稳定化(p2l_physics_stabilize,按当前姿势把每条摆锤直接放到受力方向上的静止位置并写出输出,与 Cubism 的 Stabilization 相同)。风力为零时结果与此前逐位一致。
曲线段与编辑器相同(线性、Bezier(时间控制点限制在段内)、阶梯、反阶梯);循环片段按时长回绕,单次片段停在末尾。Player 一次播放一个片段,切换时按片段的淡入淡出时间(缺省 1 秒,余弦缓动)交叉过渡;片段权重为淡入与淡出系数之积(与 Cubism 相同),每个被替换的片段都会完整淡出,连续快速切换时不会丢掉仍在淡出的片段。
宿主可开启:眨眼(EyeBlink 角色,每 2–6 秒一次,闭合 0.1 秒、保持 0.05 秒、睁开 0.15 秒,乘到当前值上;p2l_blink_settings 可改间隔与各阶段时长)、呼吸(Breath 设置为范围内的正弦,AngleX/Y/Z、BodyAngleX 叠加小幅摆动)、视线(look_at(x, y) 经临界阻尼跟随,驱动 AngleX/Y、BodyAngleX、EyeBallX/Y,AngleZ 随 x·y 倾斜)和口型(lip_sync(level),LipSync 参数取较大值;p2l_lip_sync_samples 以一段音频样本的均方根乘增益作为张开量)。p2l_behavior_strength 调整呼吸摆动幅度、视线转动幅度与跟随速度。角色由编辑器编译时按存在的标准参数写入;moc3 的 model3.json 仍只写 EyeBlink 与 LipSync 两组。更新顺序:动作片段 → 行为 → 物理 → 变形。
一个句柄对应一个已加载模型,持有参数、动作播放器和物理状态。典型流程:p2l_rig_load → 设置参数(p2l_parameter_values / p2l_set_parameter)→ p2l_update(dt)(动作、物理、变形)或 p2l_evaluate → 读取 p2l_mesh_vertices、p2l_mesh_opacity、p2l_mesh_colors,按 p2l_render_order 由后往前绘制,贴图由 p2l_texture_png 提供(p2l_texture_info 给出贴图页类型:内嵌 PNG、KTX2 或模型旁的文件)。p2l_rig_load_ex 可要求校验块的 CRC,p2l_format_support 列出支持的版本与块。表情(p2l_expression)在动作片段之后、程序化行为之前叠加;p2l_hit_test 返回画布点下的点击区域;p2l_mesh_user_data 读取网格的用户数据;p2l_pose_show 切换部件互斥组(导出设置 pose_groups),被替换的部件随 p2l_update 淡出。p2l_parameter_values 是宿主设置的姿势,每次 p2l_update 都从它重新开始叠加动作、表情、行为和物理,叠加结果不写回,所以眨眼、呼吸和加法表情不会逐帧累积;本帧实际使用的值由 p2l_parameter_current 读取。所有函数接受空句柄;返回的指针在句柄释放(姿势数据在下次求值)前有效。
ABI 1.1 增加的部分(都是新函数,1.0 的函数行为不变,只有越界下标的返回值改为可区分的值):
- 模型与实例:
p2l_model_load读取一次文件得到只读、可跨线程共享的模型,p2l_rig_create在其上创建各自持有参数、动作与物理状态的句柄,p2l_model_free后已创建的句柄仍持有模型;p2l_rig_load等于两者合一。一个句柄不能被两个线程同时使用(读也不行,p2l_bone_transform会更新句柄)。 - 分层更新与宿主层:
p2l_update_stages(dt, stages)只运行所选的层(动作、表情、行为、部件姿势、物理、实时模拟,顺序不变),未选的层既不推进也不叠加。p2l_set_parameter_override(index, value, weight)是宿主层:在动作与表情之后、行为与物理之前把参数按权重拉向给定值(面捕等),物理仍随之摆动;p2l_parameter_values仍是最底层。 - 部件与隔离组:
p2l_part_*给出部件 id、名称、父部件、标志和分组方式(直通、整组排序、隔离)。p2l_render_commands是保留隔离组边界的绘制顺序(网格下标;-2 - 部件开组,-1收组),组的混合模式、透明度合成模式、遮罩(遮罩部件展开为其网格)由p2l_part_group/p2l_part_masks给出,求值后的组透明度与乘算/屏幕色由p2l_part_composite给出:绘制树中该组的通道覆盖组合成的静态值,与编辑器一致。p2l_set_part_opacity设置宿主的部件透明度,与部件姿势一样乘到其下所有网格上。p2l_mesh_part给出网格所属部件,p2l_mesh_alpha_blend给出网格的透明度合成模式。 - 文件信息:参数名称与标志(循环、混合形参数)、吸附值和参数面板(
PGUI:二维摇杆、分组树、标签),画布原点与每单位像素,动作片段的名称、分组、时长、帧率、循环与淡入淡出,正在播放的片段、当前时间与跳转(p2l_clip_seek只移动片段时间,淡入照常),表情、点击区域与网格的显示名称,生成器信息(META)。 - 其他:
p2l_behavior_seed重设眨眼的随机种子,进程中第一个之后的句柄自动取各自的种子;越界下标的取值函数返回 NaN(数值)或 -1(下标、模式),空句柄仍返回 0;p2l_alloc按长度精确分配并清零;非 PNG 贴图页的p2l_texture_png把长度写为 0;p2l_parameter_index按p2l_parameter_id给出的字符串查找。
ABI 1.2 增加的部分(同样只有新函数):
- 动作层:最多
P2L_MAX_LAYERS(16)层,每层一次播放一个片段,按层序叠在下层之上,p2l_set_layer_weight设该层覆盖下层的权重。p2l_play_layer(layer, clip, priority)只在优先级不低于该层正在播放片段的优先级时开始(片段播完或停止后为 0),对应 Cubism 动作管理器的优先级;p2l_play与p2l_clip_*操作第 0 层。 - 动作事件与非参数曲线:来自
CEXT(见 P2LRT_V2.md)。每次更新经过的事件由p2l_event_count/p2l_event给出(文本、层、片段、时间)。片段设置的部件透明度与整体透明度乘到网格上,p2l_evaluate只求宿主姿势,因此不带它们;眨眼与口型效果作用于对应角色参数。有自身淡入淡出的曲线按 Cubism 的规则取权重。 - 多个表情:
p2l_expression_add/p2l_expression_remove让多个表情同时生效(各自淡入淡出,按开始先后叠加),p2l_expressions_playing列出正在生效的;p2l_expression仍是只保留一个。 - 整体透明度与颜色覆盖:
p2l_set_opacity乘到全部网格上(与片段设置的整体透明度相乘,p2l_opacity读取乘积);p2l_set_mesh_colors/p2l_set_part_colors用宿主给的乘算/屏幕色替换求值结果,网格自身的设置优先于其所在部件链上最近的设置。 - 物理与行为:
p2l_physics_wind、p2l_physics_stabilize、p2l_blink_settings、p2l_behavior_strength、p2l_lip_sync_samples,见上文“物理”“程序化行为”。
ABI 1.3 增加 p2l_render 与 p2l_render_texture(见下文“软件渲染”)。ABI 1.4 增加:
- 变化标志:
p2l_mesh_changes给出网格是否绘制(在绘制顺序中且不透明度大于 0),以及与上一次求值相比可见性、不透明度、绘制顺序值、在绘制顺序中的位置、顶点、乘算/屏幕色是否改变,对应 Cubism 的 dynamic flags,宿主只需上传改变的部分;首次求值后全部置位。所有改变姿势的入口(p2l_update、p2l_update_stages、p2l_evaluate、p2l_set_advanced、p2l_physics_stabilize)结束时更新。 - 日志:
p2l_set_log接收加载失败、句柄失效与渲染器无法解码的贴图页。 - 宿主分配器:
p2l_set_allocator让运行时此后的全部内存都来自宿主的分配与释放函数(大小与对齐照给);必须在使用运行时的其他任何部分之前、在单一线程中调用,运行时已向系统申请过内存时返回 false 且不改变。由默认开启的host-allocator特性提供(运行时作为 Rust 库被 Godot 节点等使用时关闭)。C 示例实测:渲染 tml 样例的 7570 次分配全部经宿主分配器。
写出端:IR 的 Clip 增加 events、targetCurves,Curve 增加 fadeIn / fadeOut,PhysicsSource 增加 Y;p2lrt 导出写 CEXT 与按需写 PHYS 版本 2,moc3 导出的 motion3 写出 UserData、PartOpacity 与 Model(Opacity、EyeBlink、LipSync)曲线和曲线淡入淡出,physics3 写出 Y;cmo3 没有纵向物理,略去纵向输入输出。编辑器的动作编辑尚不提供事件与非参数曲线的编辑入口,这些数据来自 IR。
绘制规则写在头文件开头,以 SoftwareRasterizer 为准:贴图为直通 alpha,规则在预乘颜色上计算;片段颜色先乘乘算色、再按 c + s·a − c·s 叠屏幕色,最后乘不透明度与遮罩覆盖(遮罩网格在该点纹理 alpha 的最大值,反相取 1 − 覆盖;实时播放器可用 alpha ≥ 0.5 的模板近似);开启剔除时只画画布坐标(y 向下)中顺时针的面;Cubism 的普通、叠加、乘算按其预乘公式(叠加与乘算保留目标 alpha),扩展模式按 W3C 合成公式;混合模式与透明度合成模式有 P2L_BLEND_*、P2L_ALPHA_* 常量。
调用在运行时内部 panic(缺陷,或读取器放行却无法求值的模型)时不会展开到宿主:该次调用按空句柄返回,句柄失效,p2l_rig_failure 给出原因,此后它与空句柄相同,直到 p2l_rig_free;加载中(含首次求值)panic 时 p2l_rig_load 返回空并写出原因。WebAssembly 构建的 panic 仍会中止实例(该目标不支持栈展开)。
ABI 版本:头文件的 P2L_ABI_VERSION_MAJOR / P2L_ABI_VERSION_MINOR 与库的 p2l_abi_version()(major << 16 | minor)。增加函数时次版本加一,修改或删除函数时主版本加一;宿主用 P2L_ABI_COMPATIBLE(p2l_abi_version()) 检查,没有 p2l_abi_version 的库早于 1.0。p2l_version 只是库的构建版本。JVM 绑定加载库时要求主版本相同、次版本不低于绑定所需,否则视为没有运行时;求值或更新后句柄失效时抛出异常(软件预览因此回退到编辑器求值器,运行时预览后端与导出报告错误)。cargo test 校验头文件声明的函数与库导出的函数一一对应、版本号一致。
cargo test:每条求值规则一个小模型单元测试(数值来自探测结果),以及 Warp、动作片段测试;format_tests逐块拼出版本 2 文件,覆盖压缩、CRC、块目录与各种拒绝情形、全部数组编码、贴图页类型和参数面板。RuntimeConformanceTool(PSD2LIVE_TOOLS=1):生成 80 个随机模型(Warp、旋转、嵌套、稀疏网格、混合形、Glue、通道、部件、混合)、样例和本地工程的参考姿势,以及物理轨迹;cargo run --release --bin p2lrt-conformance -- ../build/tools/runtime-conformance(物理为runtime-physics)逐例比较。每例同时写出版本 2、版本 1,以及 deflate 和 zstd 压缩的版本 2,四者必须读成相同的Rig,并逐位得到相同姿势。顶点误差上限为 0.02 像素;超出的姿势按自身条件数评判:把任一参数移动其范围的百万分之一时顶点移动最多的距离(灵敏度),误差不得超过它的两倍。网格内部插值用双精度。当前全部一致,唯一超出 0.02 的是 blend-6 的一个姿势(0.10 像素,灵敏度同为 0.10,该网格此时不透明度 3e-5)。
- GPU 渲染由宿主完成:运行时提供几何与属性,并以
p2l_render(CPU 软件渲染,见下节)画出遮罩与全部合成模式;GPU 宿主按同一规则自行绘制(Web 目标的绘制见导出目标)。
p2l_render(ABI 1.3)把最近一次求值画进宿主给的 RGBA8 图像,规则与参考光栅器 SoftwareRasterizer 相同:双线性预乘采样、像素中心与左上规则、按纹理 alpha 的遮罩(含反相)、隔离组图层、全部颜色与透明度合成模式和剔除。变换为画布到图像的仿射(空指针时按画布等比放入图像左上),输出为预乘或直通 alpha,可画在已有内容之上。内嵌 PNG 贴图页由运行时自带的解码器解出(非隔行,全部颜色类型),KTX2 与外部文件页由宿主经 p2l_render_texture 提供像素。供没有自带渲染器的宿主(C/C++、引擎插件、缩略图与校验)使用,逐像素运行在 CPU 上。验证:SoftwareRenderParityTest 在覆盖 90 种合成组合、隔离组(通道驱动的不透明度与颜色、网格与部件遮罩、反相、嵌套)、遮罩、乘算/屏幕色与剔除的模型上,于三种姿势与缩放下与参考光栅器逐像素比较,最大通道差 ≤ 1/255;把 conjoint 的重叠权重故意改错时该测试报出 77/255 的差异。
- C/C++:
runtime/examples/c/render_example.c经共享模型加载、播放一秒并用p2l_render写出 BMP;build_example.bat用 MSVC 以 C 与 C++ 各编译一次(/W4 /WX,头文件无警告),两者输出逐字节相同。Unreal 以第三方模块方式使用同一头文件与库。 - .NET / Unity:
bindings/csharp/P2lNative.cs是由generate.py从头文件生成的全部 P/Invoke 声明(cargo test校验其与导出函数一致),P2l.cs提供字符串辅助与自动释放的P2lRig;Smoke.cs以 C# 6 编译后用Marshal.Prelink解析全部 129 个入口点,并加载、播放、渲染 tml 样例。bindings/unity/P2LCharacter.cs把模型每帧用软件渲染画进Texture2D,只按所用 Unity API 的桩代码做过类型检查,未在 Unity 中运行。 - Android:
runtime/build_android.sh用 NDK 的 clang 为 arm64-v8a、armeabi-v7a、x86_64 构建libp2l_runtime.so,三者各导出全部 129 个函数。iOS 需在 Mac 上构建,未在此验证。
导出目标 web 写出可直接部署的文件夹:index.html、p2l.js(ES 模块 P2LPlayer)、p2l_runtime.wasm 与模型。播放器用 WebGL 绘制,按头文件的合成规则画出全部颜色与透明度混合组合和隔离组:普通(over)与 Cubism 的叠加、乘算用混合函数,其余组合先把网格包围盒内的下层复制到纹理、在着色器中合成;隔离组按 p2l_render_commands 画入图层,闭合时按组的模式、不透明度、乘算/屏幕色与遮罩合成;遮罩经模板缓冲(按纹理 alpha 0.5 裁剪,支持反相);开启剔除的网格只画正面。WebPlayerCheckTool(PSD2LIVE_TOOLS=1)生成覆盖 90 种组合与 16 种隔离组的模型和逐像素参考图,Edge(无界面)中与参考相差至多 1/255;页面提供动作与表情选择、口型滑块,视线跟随指针,点击显示所在的点击区域;文件带有高级模式数据时,页面提供开关。WebAssembly 构建作为资源随仓库提交,修改运行时后用 ./gradlew :targets:web:updateWasm 刷新(需要 rustup target add wasm32-unknown-unknown);单元测试核对播放器调用的每个函数都由该构建导出。tml 样例在 Edge(无界面)中显示正确。
runtime/godot/ 用 cargo build --release 构建,P2LCharacter 的属性与方法见其 README。节点按头文件的绘制规则绘制:每个网格在自己的画布项中按 render_commands 排序,贴图加载时预乘,着色器施加乘算/屏幕色、不透明度与遮罩覆盖后按颜色与透明度合成模式合成——普通+over、Cubism 加算/乘算(任意透明度模式)与 out 用硬件混合,其余读取下方颜色在着色器中计算。隔离组把内容画进与目标视口同尺寸的离屏视口(层),在组的位置按组的混合模式、透明度模式、不透明度、乘算/屏幕色与遮罩合成,可嵌套;Forward+ 与 Mobile 的后缓冲复制会丢失 alpha,层内每个读取下方的项因此各用一个视口,先复制此前的层内容再读取;组外读取屏幕,下方按不透明处理(透明窗口下为近似)。遮罩画进覆盖视口(每个视口三组遮罩),网格与层在自己的像素读取覆盖,反相遮罩取 1 − 覆盖;同一组遮罩重叠处 alpha 相加(参考取最大值)。开启剔除的网格只提交正面三角形(画布坐标中 (b − a) × (c − a) < 0),遮罩不剔除。RuntimeSamplesTool 的特性模型在 Godot 中与软件光栅器参考图一致(差值 ≤ 2/255,含反相遮罩);GodotLayerSamplesTool(PSD2LIVE_TOOLS=1)生成覆盖全部颜色×透明度合成模式(不透明背景上与隔离组内)及组的颜色、不透明度、混合模式、网格/部件遮罩、反相遮罩与嵌套的纯色模型和期望值,Godot 4.7 在 Forward+、Mobile 与 Compatibility 下各采样点差值 ≤ 1.2/255。验证:演示工程的 smoke_test.gd 在无界面模式加载模型并推进一秒;--shot 在窗口中渲染一帧,tml 与 ds 样例显示正确。