TGFX - 腾讯开源的轻量级 2D 渲染引擎

TGFX - 腾讯开源的轻量级 2D 渲染引擎

  • 首页
  • 下载
  • 文档
  • 案例
  • CN
  • GitHub
  • 论坛交流
  • Languages iconCN
    • EN

›图层系统

快速开始

  • TGFX 简介
  • 平台与后端支持
  • 环境准备与编译
  • Hello2D 示例

API 参考与概述

    绘图基础

    • Canvas Overview
    • Paint Overview
    • Path Overview
    • BlendMode Overview
    • Picture 录制与回放

    几何与变换

    • 几何与变换

    图像与像素

    • Image
    • Bitmap 与像素操作
    • 图像编解码
    • 视频与外部纹理

    文本渲染

    • 文本与字体

    着色与效果

    • 着色与效果

    图层系统

    • 图层系统

    进阶主题

    • 自定义 Shader
    • 色彩管理

架构设计

  • 渲染管线
  • GPU 硬件抽象层
  • 图层渲染系统
  • 缓存系统
  • 文字图集渲染
  • GPU Hairline 极细描边
  • 广色域渲染
  • SIMD 加速

API 文档

  • API 文档

图层系统

一、为什么需要图层系统

Canvas API 是命令式的:调用 drawRect,立刻画一个矩形;下一帧如果还想要这个矩形,必须再调用一次。这没有任何问题——直到你需要处理以下场景:

  • 持久化对象:一个按钮存在于整个会话中,不需要每帧重新描述它
  • 局部更新:只有一个图标在动,其他内容静止,不应该全量重绘
  • 交互:点击测试、坐标转换、子元素查找
  • 复杂效果:背景模糊、遮罩、阴影样式需要"知道自己在哪个位置"

命令式 API 在这些场景下会让调用方承担大量状态管理的负担。图层系统的出发点就是解决这个问题:提供一个声明式的场景描述层,你只需告诉系统"场景是什么",渲染系统自动决定"怎么画、画哪部分"。

你的代码描述的是:
  root
   ├─ 背景图层(ImageLayer)
   ├─ 卡片容器(Layer)
   │   ├─ 阴影形状(ShapeLayer)
   │   └─ 内容(TextLayer)
   └─ 按钮(ShapeLayer)

DisplayList 负责:
  - 遍历树结构
  - 计算哪些图层发生了变化
  - 只重绘变化的部分
  - 处理遮罩、效果、混合模式

二、Layer 树结构与类型

Layer 类型总览

类型职责
Layer纯容器,自身不绘制内容,用于组织层次
ImageLayer渲染一张图片
ShapeLayer渲染矢量形状,支持多填充 / 多描边叠加
SolidLayer纯色矩形,最轻量
TextLayer文字排版与渲染
MeshLayer自定义顶点网格
VectorLayer类 AE Shape Layer 的矢量动画系统(见第七节)

DisplayList 使用流程

auto displayList = std::make_shared<DisplayList>();
auto root = displayList->root();

// 背景
auto bg = SolidLayer::Make();
bg->setColor(Color::FromRGBA(240, 240, 245, 255));
root->addChild(bg);

// 卡片
auto card = ShapeLayer::Make();
Path path;
path.addRoundRect(Rect::MakeXYWH(20, 20, 360, 200), 16, 16);
card->setShape(Shape::MakeFrom(std::move(path)));
card->setFillStyles({ShapeStyle::Make(Color::White())});
root->addChild(card);

// 渲染
displayList->render(surface);

父子关系 API

parent->addChild(child);
parent->addChildAt(child, 0);          // 插入到最底层
parent->replaceChild(oldChild, newChild);
child->removeFromParent();
parent->setChildren({a, b, c});         // 批量替换所有子层

child->setName("avatar");
auto found = parent->getChildByName("avatar");

三、核心属性

图层的位置、透明度、可见性通过以下属性控制。变换有三套方案,它们操作的是同一个底层字段 matrix3D,最后一次调用生效:

setPosition(仅修改平移分量)
setMatrix(用 2D 仿射矩阵替换整个 matrix3D)
setMatrix3D(直接替换整个 matrix3D)

透明度与混合模式

layer->setAlpha(0.8f);                    // 80% opacity
layer->setBlendMode(BlendMode::Multiply); // multiply blend
layer->setVisible(false);                 // hidden, not rendered

alpha 的行为取决于 allowsGroupOpacity 属性(默认 false)。默认情况下,alpha 分别应用到图层自身和各子层上;当设置 allowsGroupOpacity(true) 后,图层及其子层先渲染到离屏纹理,再整体应用 alpha——产生"组合透明度"效果。

GroupOpacity 对比

变换

三种变换对比

// 只需要移动位置
layer->setPosition(Point::Make(100, 200));

// 需要旋转或缩放
Matrix m = Matrix::MakeRotate(45, cx, cy);
layer->setMatrix(m);

// 需要 3D 变换
Matrix3D m3d = Matrix3D::MakeRotate({0, 1, 0}, 30);  // rotate 30 degrees around Y axis
layer->setMatrix3D(m3d);

裁剪区域(scrollRect)

// 只显示图层内 (10,10)~(310,210) 区域,常用于滚动容器
layer->setScrollRect(Rect::MakeXYWH(10, 10, 300, 200));

ScrollRect 裁剪效果


四、ShapeLayer 多样式

Canvas API 每次绘制只能用一个 Paint,想给同一个形状叠加「渐变填充 + 纯色描边 + 外发光」需要画三次,还得处理遮挡顺序。ShapeLayer 解决了这个问题——它支持 fills 列表和 strokes 列表,多个样式按顺序叠加,类似 Figma 里对一个形状加多个填充层:

auto shapeLayer = ShapeLayer::Make();
shapeLayer->setShape(Shape::MakeFrom(path));

// bottom gradient fill
auto fill1 = ShapeStyle::Make(gradientShader);
// top semi-transparent overlay
auto fill2 = ShapeStyle::Make(Color::FromRGBA(255, 255, 255, 40), BlendMode::Screen);
shapeLayer->setFillStyles({fill1, fill2});

// inside stroke (does not affect outer bounds)
auto stroke = ShapeStyle::Make(Color::FromRGBA(0, 0, 0, 60));
shapeLayer->setLineWidth(2.0f);
shapeLayer->setStrokeAlign(StrokeAlign::Inside);
shapeLayer->addStrokeStyle(stroke);

StrokeAlign:描边位置控制

StrokeAlign 三种模式

模式效果适用场景
Center(默认)描边以路径为中心,内外各一半通用
Inside描边全在路径内侧,不影响外边界边界贴合布局、设计稿"内描边"
Outside描边全在路径外侧,不缩小内容区域发光效果、外边框

五、TextLayer 排版

auto text = TextLayer::Make();
text->setText("Hello\nTGFX");
text->setFont(Font(typeface, 28));
text->setTextColor(Color::Black());
text->setTextAlign(TextAlign::Center);

// 设置排版区域
text->setLayoutWidth(200);
text->setLayoutHeight(100);
text->setAutoWrap(true);   // 超出 width 自动换行

autoWrap = true + layoutWidth 配合使用,超出宽度时自动折行;layoutHeight 控制最大高度,超出部分裁剪(不会自动缩小字号)。


六、遮罩与图层效果

遮罩(mask)

让一个图层的形状控制另一个图层的可见范围:

auto maskLayer = ShapeLayer::Make();
// ... 设置遮罩形状 ...

auto content = ImageLayer::Make();
content->setImage(photo);
content->setMask(maskLayer);
content->setMaskType(LayerMaskType::Alpha);

三种 maskType 的行为差别很大,选错了效果就不对:

遮罩类型对比

maskType控制方式典型用途
Alpha遮罩层的 alpha 通道控制可见性渐变消隐、边缘羽化
Luminance遮罩层的亮度控制可见性照片级光照蒙版
Contour遮罩层的轮廓做硬边裁切圆角头像、形状裁切

实践建议:头像圆角裁切用 Contour;需要渐渐消失的边缘用 Alpha;Luminance 是高级玩法,大多数场景用不到。

LayerFilter vs LayerStyle

这两个都能给图层添加视觉效果,但机制完全不同:

LayerFilter vs LayerStyle

LayerFilter(滤镜):把图层内容绘制到离屏纹理,滤镜处理后替换原内容。

LayerStyle(样式):在图层内容的上方或下方额外叠加视觉元素,不改变原内容。

// LayerFilter:整个图层变模糊
auto blurFilter = BlurFilter::Make(8.0f, 8.0f);
layer->setFilters({blurFilter});

// LayerStyle:在图层下方绘制阴影,原内容不变
auto shadow = DropShadowStyle::Make(10, 10, 15, 15, Color::FromRGBA(150, 150, 170, 255));
layer->setLayerStyles({shadow});

LayerFilter 可用类型:

类型工厂方法
模糊BlurFilter::Make(blurX, blurY, tileMode)
投影阴影DropShadowFilter::Make(dx, dy, blurX, blurY, color, shadowOnly)
内阴影InnerShadowFilter::Make(dx, dy, blurX, blurY, color, shadowOnly)
颜色矩阵ColorMatrixFilter::Make(matrix)
混合叠加BlendFilter::Make(color, mode)

LayerFilter 是 LayerProperty(可变属性),可以在渲染后动态修改参数而无需重建:

// 动态修改模糊半径,自动触发重绘
blurFilter->setBlurrinessX(20.0f);

选型原则:需要改变图层内容本身的效果 → LayerFilter;需要在图层外围添加视觉装饰 → LayerStyle。


七、VectorLayer:类 AE 矢量动画系统

Canvas + ShapeLayer 可以画静态矢量图形,但对于"星形伸缩动画"、"路径描绘动画"、"重复元素动画"这类在 After Effects 里常见的矢量动画,用 ShapeLayer 的 fills/strokes 列表表达起来非常繁琐,而且每帧都要重新构建形状。

VectorLayer 提供了一套可动画的矢量元素系统,对应 AE 的 Shape Layer。元素树从几何描述到最终渲染分四个层次:

几何元素(形状/路径/文字)
       ↓
  修饰器(TrimPath / RoundCorner / MergePath / Repeater)
       ↓
  样式(FillStyle / StrokeStyle)
       ↓
  分组(VectorGroup,带独立变换)

VectorLayer 四层处理流程

几何元素

// 矩形
auto rect = Rectangle::Make();
rect->setSize(Size::Make(200, 100));
rect->setRoundness(12.0f);  // 圆角

// 椭圆
auto ellipse = Ellipse::Make();
ellipse->setSize(Size::Make(100, 100));

// 多角星 / 多边形
auto star = Polystar::Make();
star->setPoints(5);
star->setOuterRadius(80.0f);
star->setInnerRadius(32.0f);  // 0 = 多边形,> 0 = 星形

// 任意路径
auto shapePath = ShapePath::Make();
shapePath->setPath(myPath);

修饰器

修饰器作用于同一 VectorGroup 内在它之前定义的所有几何元素:

// 路径裁剪动画:end 从 0 到 1,路径逐渐出现
auto trim = TrimPath::Make();
trim->setStart(0.0f);
trim->setEnd(animProgress);  // 0 ~ 1,由动画驱动
trim->setTrimType(TrimPathType::Separate);  // 每条路径单独裁剪

// 圆角化
auto roundCorner = RoundCorner::Make();
roundCorner->setRadius(8.0f);

// 重复器:把前面的元素复制 N 次,每份应用递增变换
auto repeater = Repeater::Make();
repeater->setCopies(6);
repeater->setRotation(60.0f);  // rotate 60 degrees per copy

样式

// 渐变填充
auto gradientSource = Gradient::MakeLinear(
    Point::Make(0, 0), Point::Make(200, 0),
    {Color::Blue(), Color::Purple()}, {});
auto fill = FillStyle::Make(gradientSource);
fill->setOpacity(0.9f);
fill->setFillRule(FillRule::EvenOdd);

// 虚线描边
auto stroke = StrokeStyle::Make(SolidColor::Make(Color::White()));
stroke->setStrokeWidth(3.0f);
stroke->setDashOffset(0.0f);
stroke->setDashes({12.0f, 6.0f});

VectorGroup 与变换

auto group = VectorGroup::Make();
group->setAnchor(Point::Make(100, 50));
group->setPosition(Point::Make(200, 150));
group->setRotation(45.0f);
group->setScale({1.2f, 1.2f});
group->setElements({rect, fill, trim});

auto vLayer = VectorLayer::Make();
vLayer->setContents({group});
root->addChild(vLayer);

完整示例:路径描绘动画

auto vLayer = VectorLayer::Make();

// 圆形路径
auto ellipse = Ellipse::Make();
ellipse->setSize(Size::Make(200, 200));

// 描边
auto stroke = StrokeStyle::Make(SolidColor::Make(Color::White()));
stroke->setStrokeWidth(4.0f);

// 路径裁剪(end 由外部动画驱动)
auto trim = TrimPath::Make();
trim->setStart(0.0f);
trim->setEnd(progress);  // 0 → 1

vLayer->setContents({ellipse, stroke, trim});

// 下一帧更新 progress,VectorLayer 自动重绘变化部分
trim->setEnd(progress + 0.016f);

路径描绘动画序列帧


八、点击测试与坐标转换

// 精确点击测试(true = 按路径形状,false = 按 bounds 快速判断)
bool hit = layer->hitTestPoint(touchX, touchY, true);

// 获取某坐标下所有图层(从顶到底)
auto layers = displayList->root()->getLayersUnderPoint(x, y);

// 坐标转换(root 为全局坐标系)
Point local  = layer->globalToLocal(Point::Make(globalX, globalY));
Point global = layer->localToGlobal(Point::Make(localX, localY));

九、3D 图层

默认情况下,即使子图层有 3D 变换,父图层渲染时仍然按文档顺序叠加,不按 3D 深度排序。两张卡片旋转时,后加入的永远在最上面,而不是按真实的 3D 位置决定前后关系。

在父容器开启 preserve3D,建立三维渲染上下文后,子图层会按实际 Z 深度排序合成:

auto container = Layer::Make();
container->setPreserve3D(true);  // 建立 3D 渲染上下文

auto card1 = ImageLayer::Make();
card1->setMatrix3D(Matrix3D::MakeTranslate(0, 0, 50));   // Z=50,离观察者更近

auto card2 = ImageLayer::Make();
card2->setMatrix3D(Matrix3D::MakeTranslate(0, 0, -50));  // Z=-50,离观察者更远

container->addChild(card2);  // 文档顺序在前
container->addChild(card1);  // 文档顺序在后,但 Z 更大,渲染时覆盖 card2

卡片翻转动画:

float angle = animProgress * M_PI;  // 0 → π
card->setMatrix3D(Matrix3D::MakeRotate({0, 1, 0}, angle));

// 翻转过半时切换正反面
front->setVisible(angle < M_PI / 2);
back->setVisible(angle >= M_PI / 2);

限制条件:开启了 layerStyles、filters 或 mask 的图层无法参与 3D 合成——这些功能需要独立的离屏纹理,与 3D 深度排序在架构上不兼容。


选型速查

场景推荐
一次性绘制,不需要持久化Canvas API
持久化对象、交互、增量更新Layer 系统
AE 数据驱动的矢量动画VectorLayer
静态矢量形状 + 多填充叠加ShapeLayer
描边需要贴合内边界StrokeAlign::Inside
背景毛玻璃BackgroundBlurStyle
软边缘遮罩maskType = Alpha
硬边形状裁切maskType = Contour
动态调整效果参数LayerFilter(LayerProperty,可变)
3D 卡片翻转preserve3D + matrix3D
← 着色与效果自定义 Shader(RuntimeEffect) →
  • 一、为什么需要图层系统
  • 二、Layer 树结构与类型
    • Layer 类型总览
    • DisplayList 使用流程
    • 父子关系 API
  • 三、核心属性
    • 透明度与混合模式
    • 变换
    • 裁剪区域(scrollRect)
  • 四、ShapeLayer 多样式
    • StrokeAlign:描边位置控制
  • 五、TextLayer 排版
  • 六、遮罩与图层效果
    • 遮罩(mask)
    • LayerFilter vs LayerStyle
  • 七、VectorLayer:类 AE 矢量动画系统
    • 几何元素
    • 修饰器
    • 样式
    • VectorGroup 与变换
  • 八、点击测试与坐标转换
  • 九、3D 图层
  • 选型速查
公司地址:广东省深圳市南山区海天二路33号腾讯滨海大厦Copyright © 2018 - 2026 Tencent. All Rights Reserved.联系电话:0755-86013388隐私政策