颜色矩阵
FrameBuffer 通过两个方法支持原生 4x4 RGBA 矩阵变换:colorMatrix(...) 和
colorMatrixUniform(...)。
当你想以逐单元格的强度变换特定单元格时,使用 colorMatrix(...)。当你想将一个变换应用到整个缓冲区时,使用
colorMatrixUniform(...)。
两个方法都基于归一化的 RGBA 值(0.0 到 1.0)工作,可以针对前景、背景或两者通道。
API
import { TargetChannel } from "@opentui/core"
frameBuffer.colorMatrix(
matrix: Float32Array,
cellMask: Float32Array,
strength = 1.0,
target = TargetChannel.Both,
)
frameBuffer.colorMatrixUniform(
matrix: Float32Array,
strength = 1.0,
target = TargetChannel.Both,
)
矩阵格式
矩阵必须是恰好 16 个浮点数,按行优先顺序排列。
每一行定义一个输出通道:
Row 0: [r->r, g->r, b->r, a->r] // output red
Row 1: [r->g, g->g, b->g, a->g] // output green
Row 2: [r->b, g->b, b->b, a->b] // output blue
Row 3: [r->a, g->a, b->a, a->a] // output alpha
每个单元格分两步进行变换:
newColor = M * color
output = original + (newColor - original) * strength
这意味着 strength = 0.0 保持原始颜色,strength = 1.0 应用完整的矩阵结果。
目标通道
使用 TargetChannel 枚举来选择受影响的颜色缓冲区:
TargetChannel.FG(1):仅前景TargetChannel.BG(2):仅背景TargetChannel.Both(3):前景 + 背景
colorMatrix 单元格遮罩格式
cellMask 使用打包的三元组:
[x, y, perCellStrength, x, y, perCellStrength, ...]
x和y是单元格坐标perCellStrength会与方法的strength相乘- 末尾不完整的值(不是 3 的倍数)会被忽略
- 越界或非有限值的坐标会被跳过
- 非有限值的有效强度会被跳过
此方法适用于仅影响缓冲区一部分的效果,例如扫描线、暗角或局部调色。
colorMatrixUniform 行为
colorMatrixUniform 将相同的矩阵应用到所选通道的每个像素。
- 优化路径使用 SIMD 每次处理 4 个像素
- 标量回退处理剩余的任何像素
strength === 0或非有限值的strength会提前返回
使用此方法进行全帧调色和全局后处理。
无钳制
结果值不会被钳制到 [0, 1]。矩阵系数和强度可以将通道值推高到 1.0 以上或降低到
0.0 以下。
示例:反转整个缓冲区
import { INVERT_MATRIX, TargetChannel } from "@opentui/core"
frameBuffer.colorMatrixUniform(INVERT_MATRIX, 1.0, TargetChannel.Both)
示例:对选定单元格应用棕褐色效果
import { SEPIA_MATRIX, TargetChannel } from "@opentui/core"
// Affect only three cells at custom strengths
const cellMask = new Float32Array([
5,
2,
1.0, // full sepia at (5,2)
6,
2,
0.5, // half sepia at (6,2)
7,
2,
0.25, // subtle sepia at (7,2)
])
frameBuffer.colorMatrix(SEPIA_MATRIX, cellMask, 1.0, TargetChannel.FG)
示例:自定义饱和度矩阵
import { TargetChannel } from "@opentui/core"
function createSaturationMatrix(saturation: number): Float32Array {
const rw = 0.299
const gw = 0.587
const bw = 0.114
const inv = 1 - saturation
return new Float32Array([
rw * inv + saturation,
gw * inv,
bw * inv,
0,
rw * inv,
gw * inv + saturation,
bw * inv,
0,
rw * inv,
gw * inv,
bw * inv + saturation,
0,
0,
0,
0,
1,
])
}
const saturation = createSaturationMatrix(1.25)
frameBuffer.colorMatrixUniform(saturation, 0.8, TargetChannel.Both)