luanti API 纹理修饰器

纹理修饰器

纹理修饰器是一串告诉 Luanti 如何处理图片的字符串,除动态媒体外,它是运行时动态生成纹理的唯一方式。
它也能用来简化模组,批量生成重复纹理,比如不同颜色的工具贴图。

ℹ️ 说明
纹理修饰器和硬件着色功能部分重叠。优先使用硬件着色,更灵活、产生的冗余纹理更少。

性能问题

  • 所有纹理在 CPU 生成,不在 GPU,速度慢,可能短暂卡住客户端线程
  • 纹理修饰器会永久留在客户端内存
  • 生成新修饰器时不会复用缓存
  • 解析器可能出现至少是二次方的时间复杂度

建议:

  • 尽量静态使用纹理修饰器
  • 动态生成的纹理越少越好,避免撑爆客户端缓存
  • 不要短时间内让客户端大量生成高开销纹理
  • 尽量别写又长又复杂的修饰器

已知 Bug

  • 大型修饰器可能卡死客户端
  • 部分修饰器可能导致越界内存读取,例:[lowpart:0:blank.png
  • 越界像素通常被当成纯白色(#FFFFFFFF)
  • 非法修饰器可能导致客户端段错误
  • 语法错误的部分可能被静默忽略

材质包(Texture Packs)

  • 纹理修饰器可用于方块、物品的纹理覆盖
  • 修饰器生成的纹理不能被材质包直接替换(只能通过覆盖替换),只有基础纹理可以
  • 部分修饰器依赖固定分辨率,低分辨率材质包通常可以向上缩放,高分辨率则需要缩小

💡 小贴士
[resize 强制缩放到你需要的尺寸,能更好地兼容各种材质包。


在 Lua 中使用

API

core.inventorycube(top, left, right)
唯一自带的纹理修饰工具函数。

参数:

  • topleftright:字符串,对应面的纹理修饰器

返回:
生成 [inventorycube{<top>{<left>{right> 格式修饰器,并自动转义。


字符串写法

Lua 有三种字符串写法:双引号、单引号、长字符串。
纹理名一般不包含引号,所以用哪种都行。

  • 引号字符串里写反斜杠需要转义:
    a.png^[mask:b.png\^c.png
    写成 "a.png^[mask:b.png\\^c.png"

  • 长字符串用双方括号 [[...]]内部不需要转义,非常适合写纹理修饰器:
    [[[combine:1x1:0,0=a.png]]

💡 小贴士
可以用元方法实现一套优雅的 DSL,帮你自动转义与格式化。


语法

⚠️ 警告
纹理修饰器只在客户端解析,服务器不做校验。出错轻则显示错误纹理,重则直接崩溃。
务必保证语法正确、数值合法。

基础规则:

  • <...> 表示必填参数
  • [...] 表示可选
  • 所有范围都是闭区间(包含起止值)

叠加(Overlaying)

^ 符号实现叠加:

  • 右侧纹理覆盖在左侧之上
  • 支持链式:a^b^c
  • 叠加前,像素少的纹理会缩放到多的那一张
  • 正确处理 Alpha 混合

参数转义

用反斜杠 \ 转义,只在**组合型修饰器**内需要。
必须转义:^:\

嵌套转义需要翻倍反斜杠:n 层嵌套需要 2ⁿ 个反斜杠。

inventorycube 转义规则特殊:

  • ^ 换成 &
  • 不支持嵌套

示例转义函数:

1
2
3
4
5
6
7
local function escape_argument(texture_modifier)
return texture_modifier:gsub(".", {
["\\"] = "\\\\",
["^"] = "\\^",
[":"] = "\\:"
})
end

分组(括号)

用括号 () 强制优先计算,只对叠加有效。
不能在组合修饰器里用来分隔参数,必须用转义。

错误:a^[lowpart:1:(b^c)
正确:a^[lowpart:1:b\^c


修饰器列表

所有修饰器都生成新纹理,不修改原图。


组合型修饰器(多图合并)

  • [mask:按位遮罩
  • [lowpart:贴下半部分
  • [combine:按坐标拼贴多图
  • [inventorycube:生成物品栏立方体

基础纹理修饰器

<base>^[brighten

每个像素颜色与白色50% 混合,提亮。

<base>^[noalpha

把 Alpha 通道强制设为 255(完全不透明)。

<base>^[makealpha:<r>,<g>,<b>

把 RGB 完全匹配的像素设为透明

<base>^[opacity:<ratio>

透明度整体缩放,ratio 0~255。

<base>^[invert:<mode>

反色通道,mode 可包含 r/g/b/a。

<base>^[transform<transforms>

旋转/翻转,支持数字或名称(不区分大小写):

数字名称效果
0I不变
1R90逆时针90°
2R180逆时针180°
3R270逆时针270°
4FX水平翻转
5FXR90水平翻转+逆时针90°
6FY垂直翻转
7FYR90垂直翻转+逆时针90°

<base>^[verticalframe:<framecount>:<frame>

按帧数垂直裁切动画纹理。
⚠️ framecount=0 会除零崩溃客户端。

<base>^[crack[<opacity>]:[<framecount>:]<tilecount>:<frame>

在纹理上叠加破损动画(crack_anylength.png)。

  • opacity 填 o → 只在完全不透明区域显示破损
  • tilecount:分块数,通常 1
  • frame:当前破损帧

<base>^[sheet:<w>x<h>:<x>,<y>

从精灵图中截取一格。

<base>^[multiply:<color>

RGB 通道与颜色相乘,忽略 Alpha。

<base>^[colorize:<color>[:<ratio>]

颜色混合:

  • ratio 0~255:0=原图,255=纯颜色
  • alpha:按纹理自身透明度混合

<base>^[mask:<texture>

按位与遮罩,只保留重叠不透明部分。

<base>^[lowpart:<percent>:<texture>

把另一张图的下百分之 N 贴上来。


基础纹理生成器(不需要底图)

[png:<data>

从 base64 编码的 PNG 生成纹理。

1
"[png:" .. core.encode_base64(core.encode_png(w, h, data))

⚠️ Luanti 5.4 及以下不支持,用作方块贴图可能崩溃。

[combine:<w>x<h>:<x>,<y>=<tex>:...

创建指定尺寸的透明图,按坐标拼贴其他纹理。
背景:透明黑 #00000000

[inventorycube{<top>{<left>{<right>

用三张图生成物品栏立方体图标。
尺寸公式:9 * max(4, min(64, 2^ceil(log2(max_size))))


实用示例

破损方块

default_stone.png^[crack:1:2

裁切

裁掉左上6px(16x16→8x8):
[combine:8x8:-8,-8=default_stone.png

进度条

嵌套 combine(分辨率相关)

1
[combine:256x48:0,0=bg.png:0,0=[combine\:128x48\:0,0=bar.png

lowpart + 旋转(分辨率无关)

1
bg.png^[transformR90^[lowpart:50:bar.png\^[transformR90^[transformR270