核心名词解释大全
58个渲染核心名词,每个都有:定义、一句话本质、类比解释、技术细节、常见误区
参考:月影《跟月影学可视化》图形基础篇、数学篇、视觉基础篇核心概念
阅读指南(初学者必看)
为什么你需要这份名词解释?
学习图形学时,你会遇到大量专业术语:VBO、MVP、NDC、光栅化、Early-Z……每个词看起来都很陌生。如果不理解这些术语,你会发现:
- 看技术文档时每个字都认识,连起来就不懂了
- 听技术分享时演讲者蹦出一堆缩写,完全跟不上
- 写代码时IDE的API提示里全是看不懂的参数名
- 面试官说"说说你对MVP矩阵的理解",你只会背定义
这份文档的目标:让每个术语从"天书"变成"人话"。
如何使用本文档
场景1:遇到不认识的词
- 直接按Ctrl+F搜索关键词
- 每个词都有"一句话本质",先看这个建立直觉
- 再看"类比解释"加深理解
- 最后看"技术细节"掌握精确含义
场景2:系统学习
- 按分类顺序阅读(渲染管线 → GPU架构 → WebGL/API → 性能指标 → Cocos引擎 → 高级渲染)
- 每个术语的"常见误区"一定要看,这是踩坑经验
- 看完一个分类后,尝试用自己的话复述给 imaginary friend 听
场景3:面试准备
- 重点看"一句话本质"和"技术细节"
- 准备1-2个"类比解释",面试时用类比说明你的理解深度
- 记住"常见误区",展示你对坑点的了解
文档结构
一、渲染管线术语(19个)- 最基础,必学
二、GPU架构术语(8个)- 了解性能瓶颈
三、WebGL/API术语(5个)- H5开发必备
四、性能指标术语(6个)- 优化必备
五、Cocos引擎术语(10个)- Cocos开发者重点
六、高级渲染术语(8个)- 进阶内容
如果读完还是不懂怎么办?
- 正常现象:58个术语不可能一次全记住
- 建议策略:先记住"一句话本质",建立基本认知框架
- 实践策略:在写代码时遇到不懂的词再回来查,带着问题查效率更高
- 关联学习:配合《GPU渲染管线详解.md》一起阅读,两个文档互相补充
一、渲染管线术语
1. 渲染管线 (Rendering Pipeline)
为什么需要这个概念? 渲染管线是图形学的"骨架"。不懂渲染管线,你看任何图形API文档都会迷失在函数调用中,无法理解"数据从哪来、到哪去、经历了什么变换"。
| 维度 | 内容 |
|---|---|
| 定义 | 将3D场景数据转换为2D屏幕像素的完整处理流程 |
| 一句话本质 | 图形数据的"生产线", raw data → 像素 |
| 类比解释 | 汽车工厂流水线:原材料(顶点) → 冲压(顶点着色器) → 喷漆(片元着色器) → 质检(测试) → 成品(画面) |
| 技术细节 | 现代GPU管线分为:应用阶段(CPU) → 几何阶段(GPU) → 光栅化阶段(GPU) → 像素处理阶段(GPU)。其中顶点着色器和片元着色器是可编程的,其他阶段由硬件固定实现 |
| 常见误区 | ❌ 以为所有阶段都能编程(实际只有顶点/片元着色器可编程) ❌ 以为管线顺序可以跳过(每个阶段依赖上一阶段的输出) |
自问自答
- Q:为什么叫"管线"而不是"流程"? A:因为数据像水流一样单向流动,不能回头,也不能跳过某个阶段。
- Q:如果不懂渲染管线会怎样? A:写Shader时不知道自己的代码在哪个阶段执行,调试时完全抓瞎。
2. 顶点 (Vertex)
| 维度 | 内容 |
|---|---|
| 定义 | 构成几何图形的基本点,包含位置、颜色、UV等属性 |
| 一句话本质 | 3D世界的"原子",所有模型由顶点构成 |
| 类比解释 | 乐高积木的单个凸点。无数凸点组合成各种形状 |
| 技术细节 | 一个顶点通常包含:position(vec3)、normal(vec3)、uv(vec2)、color(vec4)。在GPU中存储为连续的Float32Array。一个Sprite需要4个顶点,一个立方体需要8个顶点 |
| 常见误区 | ❌ 以为顶点就是像素(顶点是几何概念,像素是屏幕概念) ❌ 以为顶点越多越好(顶点增加会增加顶点着色器负担) |
3. 图元 (Primitive)
为什么需要这个概念? GPU的硬件电路只支持几种固定的图元类型。理解图元类型,才能知道"怎么用最少的顶点画出想要的形状"。
| 维度 | 内容 |
|---|---|
| 定义 | 顶点组合成的基本几何形状 |
| 一句话本质 | GPU能直接绘制的"最小单元" |
| 类比解释 | 乐高积木的基本连接方式:可以拼成平面(三角形)、线条(线段)、点 |
| 技术细节 | 常见图元类型:POINTS(点)、LINES(线段)、LINE_STRIP(线带)、LINE_LOOP(线环)、TRIANGLES(三角形)、TRIANGLE_STRIP(三角带)、TRIANGLE_FAN(三角扇)。WebGL中三角形是最常用的,因为任何多边形都可以分解为三角形 |
| 常见误区 | ❌ 以为GPU能直接画圆或曲线(GPU只认三角形,圆是用很多三角形近似) ❌ 用TRIANGLES画连续面(应该用TRIANGLE_STRIP减少顶点数) |
代码示例
// TRIANGLES:每3个顶点一个三角形,不共享顶点
// 2个三角形需要6个顶点
const triangles = new Float32Array([
// 三角形1
-1, -1, 1, -1, 1, 1,
// 三角形2
-1, -1, 1, 1, -1, 1,
]);
gl.drawArrays(gl.TRIANGLES, 0, 6);
// TRIANGLE_STRIP:相邻三角形共享一条边
// 2个三角形只需要4个顶点
const strip = new Float32Array([
-1, -1, // 顶点0
1, -1, // 顶点1
-1, 1, // 顶点2 → 三角形1: 0-1-2
1, 1, // 顶点3 → 三角形2: 1-2-3(共享边1-2)
]);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
自问自答
- Q:为什么GPU只支持这么几种图元? A:硬件电路需要固定功能,支持的图元类型越多电路越复杂。三角形是最通用的,任何多边形都能拆成三角形。
- Q:如果不懂图元会怎样? A:你可能会用TRIANGLES画一个长条带,用了几百个顶点,而实际上用TRIANGLE_STRIP只需要几十个。
4. 顶点着色器 (Vertex Shader)
| 维度 | 内容 |
|---|---|
| 定义 | 对输入的每个顶点执行一次的可编程着色器,主要做坐标变换 |
| 一句话本质 | "定位员":决定每个顶点在屏幕上的位置 |
| 类比解释 | 快递分拣员。拿到包裹(顶点),看地址(MVP矩阵),放到正确的货架(屏幕坐标) |
| 技术细节 | 输入:attribute变量(顶点属性)、uniform变量(全局参数)。输出:gl_Position(齐次坐标,vec4)。执行次数 = 顶点数。一个Sprite执行4次,全屏画面可能只执行几百次 |
| 常见误区 | ❌ 在顶点着色器里做复杂光照计算(应该放片元着色器) ❌ 修改gl_Position的w分量(除非你知道透视除法的影响) |
5. 片元着色器 (Fragment Shader)
为什么需要这个概念? 顶点着色器只计算了3个顶点的颜色,但三角形内部有成千上万个像素。谁来决定每个像素的颜色?片元着色器就是干这个的。它是实现"特效"的核心 —— 溶解、发光、水波纹、灰度,全部在片元着色器里实现。
| 维度 | 内容 |
|---|---|
| 定义 | 对光栅化后的每个片元(潜在像素)执行一次的可编程着色器,决定最终颜色 |
| 一句话本质 | "上色员":决定每个像素涂什么颜色 |
| 类比解释 | 十字绣的上色工人。拿到一个格子(片元),根据设计图(纹理+Shader逻辑)填色 |
| 技术细节 | 输入:varying变量(插值后的顶点属性)、uniform变量。输出:gl_FragColor(vec4,RGBA)。执行次数 = 覆盖像素数(1080P全屏约207万次!)。每多一行代码都被放大百万倍 |
| 常见误区 | ❌ 在片元着色器里做分支判断(GPU并行执行,分支导致部分核心空转) ❌ 多次texture2D采样(每次采样都从显存读数据,是性能杀手) |
代码示例
precision mediump float;
varying vec2 v_uv; // 从顶点着色器接收的UV坐标(已插值)
uniform sampler2D u_texture; // 纹理采样器
uniform float u_time; // 时间变量(用于动画)
void main() {
// 基础纹理采样
vec4 texColor = texture2D(u_texture, v_uv);
// 简单的脉冲效果:随时间变化透明度
float pulse = sin(u_time * 3.0) * 0.3 + 0.7;
texColor.a *= pulse;
gl_FragColor = texColor;
}
自问自答
- Q:为什么片元着色器执行次数比顶点着色器多这么多? A:因为一个Sprite可能覆盖几万个像素,但顶点只有4个。执行次数 = 像素数,不是顶点数。
- Q:如果不懂片元着色器会怎样? A:你无法实现任何自定义视觉效果,而且容易写出性能极差的Shader(比如全屏模糊采样25次纹理)。
6. 光栅化 (Rasterization)
| 维度 | 内容 |
|---|---|
| 定义 | 将连续的几何图形(三角形)转换为离散的像素点(片元)的过程 |
| 一句话本质 | "像素化":把矢量图形变成位图 |
| 类比解释 | 十字绣。图案是连续的线条,绣出来是一个个离散的格子。光栅化就是"把线条转成格子" |
| 技术细节 | 核心步骤:(1)扫描转换:确定三角形覆盖哪些像素;(2)片元生成:每个覆盖的像素生成一个Fragment;(3)属性插值:用重心坐标在三角形内插值顶点属性(颜色/UV/深度)。GPU用专门的硬件电路并行完成 |
| 常见误区 | ❌ 以为光栅化是软件算法(现代GPU有专门的光栅化硬件单元) ❌ 以为插值是线性插值所有属性(透视校正插值对UV和颜色不同) |
7. 逐片元操作 (Per-Fragment Operations)
为什么需要这个概念? 片元着色器算出了一个颜色,但这个片元不一定能显示在屏幕上。它可能在裁剪区域外、被其他物体挡住、或者只是Mask外不应该显示的部分。逐片元操作就是一系列"安检",只有通过所有检查的片元才能最终显示。
| 维度 | 内容 |
|---|---|
| 定义 | 对每个片元执行的一系列测试和混合操作 |
| 一句话本质 | "质检+打包":检查片元是否合格,合格就写入帧缓冲 |
| 类比解释 | 工厂质检流程:尺寸检查 → 重量检查 → 外观检查 → 合格品装箱 |
| 技术细节 | 5步测试(按顺序):裁剪测试 → Alpha测试 → 模板测试 → 深度测试 → 混合操作。任何一步失败,片元被丢弃。全部通过则写入帧缓冲。顺序是固定的,不能改变 |
| 常见误区 | ❌ 以为深度测试在最前面(实际在模板测试之后) ❌ 以为混合操作对所有物体都开启(不透明物体应该关闭混合) |
自问自答
- Q:测试顺序可以改吗? A:不能。这是GPU硬件固定的顺序,目的是尽早丢弃不合格的片元,减少无效计算。
- Q:如果不懂逐片元操作会怎样? A:你会遇到各种"莫名其妙"的渲染bug:Mask不生效、透明物体显示异常、z-fighting闪烁等。
8. 帧缓冲 (Frame Buffer)
| 维度 | 内容 |
|---|---|
| 定义 | GPU用于存储最终渲染结果的内存区域 |
| 一句话本质 | GPU的"画布",画完一帧就显示到屏幕 |
| 类比解释 | 画家的画布。画家在画布上画画(GPU写入),画完挂到墙上展示(屏幕显示) |
| 技术细节 | 帧缓冲包含多个附件:(1)颜色缓冲(Color Buffer):存储RGB颜色;(2)深度缓冲(Depth Buffer/Z-Buffer):存储深度值;(3)模板缓冲(Stencil Buffer):存储模板值。通常使用双缓冲(前缓冲+后缓冲)避免画面撕裂 |
| 常见误区 | ❌ 以为帧缓冲只有颜色(还有深度和模板) ❌ 以为帧缓冲就是屏幕(帧缓冲在显存,屏幕是物理设备) |
9. 深度缓冲 / Z-Buffer (Depth Buffer)
为什么需要这个概念? 3D场景中物体会互相遮挡。没有深度缓冲,后画的物体会覆盖先画的,不管谁在前面。深度缓冲让GPU能自动判断"哪个物体更近",正确显示遮挡关系。
| 维度 | 内容 |
|---|---|
| 定义 | 存储每个像素深度值的二维数组,用于解决遮挡关系 |
| 一句话本质 | "距离记录本":记录每个像素离相机多远 |
| 类比解释 | 画家画画时,先画远处的山,再画近处的树。深度缓冲就是"画家记住每个位置已经画了什么,新的笔画只有更近才覆盖" |
| 技术细节 | 存储格式:16位整数(~1/65536精度)、24位整数(~1/16777216精度)、32位浮点(非均匀分布)。值范围[0,1],0=近平面,1=远平面。精度问题:远处z-fighting(两个面深度值相同导致闪烁) |
| 常见误区 | ❌ 以为深度值线性分布(透视投影后深度非线性,近处精度高远处低) ❌ 透明物体也开深度写入(透明物体应该关闭depthWrite,从后往前渲染) |
逐步推导:深度测试
假设画两个重叠的Sprite:
Sprite A(在后面):深度 = 0.5
Sprite B(在前面):深度 = 0.3
画A时:
- 深度缓冲初始值 = 1.0
- 比较:0.5 < 1.0?通过!
- 写入A的颜色,更新深度缓冲 = 0.5
画B时:
- 深度缓冲当前值 = 0.5
- 比较:0.3 < 0.5?通过!(B更近)
- 写入B的颜色,更新深度缓冲 = 0.3
最终显示B的颜色(正确!)
自问自答
- Q:为什么深度值范围是[0,1]? A:这是标准化范围,便于硬件存储和比较。0表示最近(近平面),1表示最远(远平面)。
- Q:如果不懂深度缓冲会怎样? A:3D场景中物体会随机互相覆盖,出现"穿透""闪烁"等奇怪现象。透明物体也会显示异常。
10. 模板缓冲 (Stencil Buffer)
| 维度 | 内容 |
|---|---|
| 定义 | 存储每个像素模板值的二维数组,用于实现遮罩效果 |
| 一句话本质 | "遮罩层":控制哪些区域可以绘制 |
| 类比解释 | 喷漆用的镂空模板。把模板放在纸上,喷漆只喷到镂空的部分 |
| 技术细节 | 通常8位整数(0-255)。操作:keep(保持)、zero(清零)、replace(替换)、increment(加1)、decrement(减1)、invert(取反)。Mask组件用2-Pass实现:Pass1写模板形状,Pass2只绘制模板内区域 |
| 常见误区 | ❌ 以为模板缓冲和深度缓冲是一回事(功能完全不同) ❌ 忘记清除模板缓冲(每帧开始要gl.clear(gl.STENCIL_BUFFER_BIT)) |
11. 混合 / Alpha Blending
| 维度 | 内容 |
|---|---|
| 定义 | 将新绘制的颜色与帧缓冲中已有颜色按公式混合的技术 |
| 一句话本质 | "颜色叠加":半透明效果的核心 |
| 类比解释 | 两层彩色玻璃叠加。你看到的效果是两层玻璃的混合色 |
| 技术细节 | 标准公式:结果 = 源色 × 源Alpha + 目标色 × (1 - 源Alpha)。其他模式:加法混合(发光)、乘法混合(变暗)、屏幕混合(提亮)。混合在深度测试之后执行 |
| 常见误区 | ❌ 不透明物体也开混合(浪费性能,且可能产生错误颜色) ❌ 透明物体从前往后渲染(必须从后往前,否则混合结果错误) |
12. VBO (Vertex Buffer Object)
| 维度 | 内容 |
|---|---|
| 定义 | 存储在GPU显存中的顶点数据缓冲区 |
| 一句话本质 | GPU的"顶点仓库" |
| 类比解释 | 餐厅的食材仓库。所有食材(顶点数据)提前放到仓库,厨师(GPU)直接从仓库取,不需要每次从市场(CPU内存)买 |
| 技术细节 | 创建流程:gl.createBuffer() → gl.bindBuffer() → gl.bufferData()。数据存储为类型化数组(Float32Array/Uint16Array)。使用STATIC_DRAW(数据不变)、DYNAMIC_DRAW(数据偶尔变)、STREAM_DRAW(数据每帧变)提示GPU优化 |
| 常见误区 | ❌ 每帧都重新创建VBO(应该创建一次,更新用bufferSubData) ❌ 用普通Array而不是Float32Array(普通Array是JS对象,转换有开销) |
13. IBO / EBO (Index Buffer Object)
为什么需要这个概念? 一个矩形有4个顶点,但画2个三角形需要6个顶点(有2个重复)。IBO通过"索引复用顶点",让4个顶点就能画2个三角形,节省显存和带宽。
| 维度 | 内容 |
|---|---|
| 定义 | 存储顶点索引的缓冲区,告诉GPU哪些顶点组成三角形 |
| 一句话本质 | "连接表":顶点的接线图 |
| 类比解释 | 串珠子的说明书。珠子(顶点)已经摆好,说明书(IBO)告诉你哪几颗珠子串在一起 |
| 技术细节 | 索引类型:UNSIGNED_BYTE(0-255,最多256个顶点)、UNSIGNED_SHORT(0-65535,最常用)、UNSIGNED_INT(0-4294967295,WebGL2支持)。使用IBO可以减少顶点重复:4个顶点+6个索引就能画2个三角形,不用IBO需要6个顶点 |
| 常见误区 | ❌ 顶点数少就不用IBO(即使只有4个顶点,用IBO也更规范) ❌ 索引类型选错(超过65535个顶点必须用UNSIGNED_INT) |
代码示例
// 4个顶点
const vertices = new Float32Array([
-1, -1, // 0: 左下
1, -1, // 1: 右下
1, 1, // 2: 右上
-1, 1, // 3: 左上
]);
// 6个索引,组成2个三角形
const indices = new Uint16Array([
0, 1, 2, // 三角形1:左下→右下→右上
0, 2, 3, // 三角形2:左下→右上→左上
]);
// 创建VBO和IBO
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
// 用IBO绘制(注意是drawElements不是drawArrays)
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
自问自答
- Q:IBO和VBO有什么区别? A:VBO存的是顶点数据(位置、颜色等),IBO存的是索引(告诉GPU用哪几个顶点组成三角形)。
- Q:如果不懂IBO会怎样? A:3D模型的顶点数据会膨胀几倍,占用大量显存,低端手机可能因此闪退。
14. MVP矩阵 (Model-View-Projection Matrix)
| 维度 | 内容 |
|---|---|
| 定义 | 将顶点从模型空间变换到裁剪空间的三个矩阵的乘积 |
| 一句话本质 | "坐标变换三部曲":局部 → 世界 → 相机 → 屏幕 |
| 类比解释 | 快递配送:(1)从卖家仓库取货(Model) → (2)运到城市中转站(View) → (3)按地址分配到具体楼栋(Projection) |
| 技术细节 | M = 模型矩阵(节点的位移/旋转/缩放);V = 视图矩阵(相机的位置和朝向);P = 投影矩阵(透视或正交)。计算顺序:gl_Position = P × V × M × position。在Cocos中,MVP由引擎自动计算,通过uniform传给Shader |
| 常见误区 | ❌ 矩阵乘法顺序搞错(矩阵乘法不满足交换律,顺序必须是P×V×M) ❌ 在CPU端每顶点计算MVP(应该在CPU算一次MVP矩阵,GPU每个顶点做矩阵×向量) |
15. NDC (Normalized Device Coordinates)
| 维度 | 内容 |
|---|---|
| 定义 | 归一化设备坐标,范围[-1,1]的标准化坐标系 |
| 一句话本质 | "通用坐标语言":不同分辨率的屏幕都能理解的坐标 |
| 类比解释 | 百分比布局。不管屏幕多大,0%到100%都能对应。NDC就是-100%到+100% |
| 技术细节 | 顶点着色器输出gl_Position(齐次坐标),GPU自动做透视除法:NDC = gl_Position.xyz / gl_Position.w。NDC的xy范围[-1,1]对应屏幕的宽高,z范围[-1,1]对应深度缓冲的[0,1] |
| 常见误区 | ❌ 以为NDC就是屏幕像素(NDC需要经过视口变换才是像素坐标) ❌ 手动设置gl_Position时忘记w分量(w=0会导致透视除法出错) |
16. 视口变换 (Viewport Transform)
为什么需要这个概念? NDC是标准化的[-1,1],但屏幕像素是具体的[0,宽度]。视口变换就是这两者之间的"换算公式"。
| 维度 | 内容 |
|---|---|
| 定义 | 将NDC坐标转换为屏幕像素坐标的过程 |
| 一句话本质 | "坐标翻译":把[-1,1]翻译成[0,屏幕宽度] |
| 类比解释 | 汇率换算。NDC是美元(标准化),屏幕像素是人民币(实际尺寸),视口变换就是按汇率换算 |
| 技术细节 | 公式:screenX = (NDC.x + 1) × width / 2 + viewportXscreenY = (NDC.y + 1) × height / 2 + viewportY。在Cocos中,视口通常等于Canvas大小,由引擎自动设置 |
| 常见误区 | ❌ 手动计算视口变换(引擎已经做了,不需要手动算) ❌ 改变Canvas大小后忘记更新视口(会导致画面拉伸) |
逐步推导
已知:NDC范围[-1, 1],屏幕宽度width
求:NDC.x对应的屏幕像素screenX
Step 1:NDC[-1,1] → [0,1]
t = (NDC.x + 1) / 2
Step 2:[0,1] → [0, width]
screenX = t × width = (NDC.x + 1) × width / 2
验证:
- NDC.x = -1 → screenX = 0(最左边)✓
- NDC.x = 0 → screenX = width/2(中间)✓
- NDC.x = 1 → screenX = width(最右边)✓
自问自答
- Q:视口变换是谁做的? A:GPU自动做的,不需要你写代码。你只需要告诉GPU视口大小(gl.viewport)。
- Q:如果不懂视口变换会怎样? A:改变Canvas大小后画面拉伸,因为你没有更新视口设置。
17. DrawCall
| 维度 | 内容 |
|---|---|
| 定义 | CPU向GPU发送的一次绘制命令 |
| 一句话本质 | "画图指令":CPU告诉GPU画什么、怎么画 |
| 类比解释 | 打电话叫出租车。10个DrawCall = 打10次电话叫10辆车。1个DrawCall = 打1次电话叫1辆大巴载10人 |
| 技术细节 | 每次DrawCall,CPU需要设置:Shader程序、VBO/IBO、纹理、Uniform变量、混合模式、深度/模板状态。这些设置在CPU端执行,是CPU瓶颈。GPU反而可能在等CPU。目标:用最少的DrawCall画出相同的画面 |
| 常见误区 | ❌ 以为DrawCall少就一定性能好(DrawCall少但片元着色器复杂,GPU还是瓶颈) ❌ 以为DrawCall只影响CPU(DrawCall切换也会打断GPU的流水线) |
18. 合批 (Batching)
| 维度 | 内容 |
|---|---|
| 定义 | 将多个满足相同条件的渲染对象合并到一个DrawCall中绘制 |
| 一句话本质 | "拼车":相同目的地(纹理相同)、相同车型(材质相同)就拼到一辆车 |
| 类比解释 | 快递分拣。同一小区的包裹(相同纹理)用同一辆车(同一个DrawCall)送,而不是每包裹一辆车 |
| 技术细节 | 合批条件(4个必须全部满足):(1)相同纹理/图集;(2)相同材质/Shader;(3)相同混合模式;(4)相同深度/模板状态。Cocos的Batcher2D自动合批:把多个Sprite的顶点合并到一个大VBO,一次DrawCall绘制 |
| 常见误区 | ❌ 以为所有相同纹理的Sprite都能合批(中间有Mask/不同材质会打断) ❌ 以为合批只减少DrawCall(也减少CPU遍历开销和状态切换开销) |
19. 着色器程序 (Shader Program)
| 维度 | 内容 |
|---|---|
| 定义 | 顶点着色器和片元着色器链接后的可执行程序 |
| 一句话本质 | GPU的" executable":告诉GPU怎么画 |
| 类比解释 | 菜谱。顶点着色器是"备菜步骤",片元着色器是"烹饪步骤",链接后就是完整的菜谱 |
| 技术细节 | 创建流程:createShader → shaderSource → compileShader(顶点+片元分别编译)→ createProgram → attachShader → linkProgram → useProgram。编译后的Shader存储在GPU中,useProgram切换时有开销 |
| 常见误区 | ❌ 编译失败不检查(必须用getShaderParameter检查COMPILE_STATUS) ❌ 每帧都useProgram(应该尽量减少Shader切换) |
20. GLSL (OpenGL Shading Language)
为什么需要这个概念? GPU不认识JavaScript,它有自己的编程语言。GLSL就是写Shader用的语言,类似于C语言的语法。
| 维度 | 内容 |
|---|---|
| 定义 | OpenGL的着色器编程语言,WebGL使用GLSL ES版本 |
| 一句话本质 | GPU的"编程语言":用代码控制GPU怎么画 |
| 类比解释 | 厨师的专业术语。GLSL就是GPU能听懂的语言,用它可以精确控制每个像素的颜色 |
| 技术细节 | WebGL1用GLSL ES 1.0,WebGL2用GLSL ES 3.0。主要数据类型:float、vec2/3/4、mat2/3/4、sampler2D。修饰符:attribute(顶点属性)、uniform(全局常量)、varying(顶点→片元传递)。精度修饰符:highp、mediump、lowp |
| 常见误区 | ❌ 把JavaScript语法用到GLSL中(GLSL是C-like语法,有严格类型) ❌ 忽略精度修饰符(移动端必须用lowp节省性能) |
代码示例
// GLSL和JavaScript的关键区别
// 1. 必须声明类型(JS不需要)
float x = 1.0; // 正确
var x = 1.0; // 错误!GLSL没有var
// 2. 向量类型
vec2 pos = vec2(1.0, 2.0); // 二维向量
vec3 color = vec3(1.0, 0.0, 0.0); // 三维向量(RGB)
vec4 rgba = vec4(color, 1.0); // 四维向量,前3个来自color
// 3. 精度修饰符(移动端重要)
precision mediump float; // 声明默认精度
highp vec3 position; // 高精度(位置)
lowp vec4 color; // 低精度(颜色)
自问自答
- Q:GLSL和JavaScript最大的区别是什么? A:GLSL是强类型的(必须声明变量类型),且没有动态内存分配。它更像C语言。
- Q:如果不懂GLSL会怎样? A:写Shader时把JS语法套进去,导致编译失败。或者忽略精度修饰符,在移动端出现颜色断层或性能问题。
二、GPU架构术语
21. 显存 (Video Memory / VRAM)
| 维度 | 内容 |
|---|---|
| 定义 | GPU专用的内存,用于存储纹理、顶点数据、帧缓冲等 |
| 一句话本质 | GPU的"硬盘":存数据的地方 |
| 类比解释 | 画家的颜料柜。所有颜料(纹理)、画布(帧缓冲)都放在柜子里,画家(GPU)随时取用 |
| 技术细节 | 显存类型:GDDR6/GDDR6X/HBM2。带宽比CPU内存高得多(几百GB/s vs 几十GB/s)。显存容量限制:低端机可能只有1-2GB,高端显卡24GB+。纹理是显存占用大户:2048×2048 RGBA8888 = 16MB |
| 常见误区 | ❌ 以为显存越大越好(对2D游戏来说,2GB足够,关键是带宽) ❌ 不压缩纹理(未压缩纹理占用大量显存,导致低端机闪退) |
22. 纹理 (Texture)
为什么需要这个概念? 3D模型本身是"白模"(没有颜色)。纹理就是给模型"贴皮肤"的图片,让模型看起来有细节、有颜色。
| 维度 | 内容 |
|---|---|
| 定义 | 存储在GPU显存中的二维图像数据,用于给模型贴图 |
| 一句话本质 | "贴纸":给3D模型贴上的图片 |
| 类比解释 | 给石膏像上色。先做好一张彩图(纹理),然后贴到石膏像表面(UV映射) |
| 技术细节 | 纹理参数:wrapS/wrapT(边缘重复/镜像/拉伸)、minFilter/magFilter(缩小/放大过滤:NEAREST/LINEAR/MIPMAP)。纹理格式:RGBA8888(32位)、RGB565(16位)、RGBA4444(16位)。Mipmap:预生成缩小版本,提升远处纹理的采样质量和性能 |
| 常见误区 | ❌ 纹理尺寸不是2的幂次(WebGL1要求2的幂次才能重复,WebGL2无此限制) ❌ 忘记生成Mipmap(远处纹理闪烁/锯齿) |
代码示例
// 加载纹理
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// 设置纹理参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); // 水平边缘拉伸
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); // 垂直边缘拉伸
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // 缩小时线性插值
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); // 放大时线性插值
// 上传图片数据到GPU
const image = new Image();
image.onload = () => {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
};
image.src = 'sprite.png';
自问自答
- Q:纹理存在哪里? A:在GPU显存中。
texImage2D()就是把图片数据从CPU内存上传到GPU显存。 - Q:如果不懂纹理会怎样? A:Sprite显示黑屏或花屏,因为你没有正确加载或绑定纹理。
23. UV坐标 / 纹理坐标 (Texture Coordinates)
| 维度 | 内容 |
|---|---|
| 定义 | 定义顶点在纹理上的对应位置的二维坐标 |
| 一句话本质 | "地图坐标":告诉GPU模型的每个点对应纹理的哪个位置 |
| 类比解释 | 地图的经纬度。UV就是纹理上的"经纬度",(0,0)是左下角,(1,1)是右上角 |
| 技术细节 | 范围[0,1],U是水平方向,V是垂直方向。每个顶点一个UV坐标,光栅化时自动插值。UV可以超出[0,1]范围,配合wrap模式实现重复/镜像效果。Sprite的4个顶点UV:(0,0)、(1,0)、(1,1)、(0,1) |
| 常见误区 | ❌ UV坐标用像素值(必须用归一化的0-1范围) ❌ V坐标方向搞反(OpenGL/WebGL的V=0是底部,DirectX的V=0是顶部) |
24. Mipmap
为什么需要这个概念? 当一个纹理在远处显示时,它在屏幕上只占几个像素。如果直接用原始纹理采样,GPU需要从几千像素的纹理中"跳过"大部分像素,导致摩尔纹和闪烁。Mipmap预先生成缩小版本,让GPU可以直接用合适的尺寸采样。
| 维度 | 内容 |
|---|---|
| 定义 | 预生成的纹理缩小版本序列,每个级别尺寸减半 |
| 一句话本质 | "纹理的缩略图":远处用小的,近处用大的 |
| 类比解释 | 地图的不同缩放级别。看全貌用小地图,看细节用大地图。Mipmap就是预先准备好所有缩放级别 |
| 技术细节 | 级别0是原始纹理,级别1是1/2尺寸,级别2是1/4...直到1×1。总内存增加约33%。采样时GPU根据像素覆盖的纹理区域大小自动选择合适级别。过滤模式:NEAREST_MIPMAP_NEAREST(快但跳变)、LINEAR_MIPMAP_LINEAR(慢但平滑,三线性过滤) |
| 常见误区 | ❌ 以为Mipmap只是优化性能(也解决远处纹理的摩尔纹和闪烁) ❌ 所有纹理都生成Mipmap(UI/2D精灵通常不需要,反而模糊) |
自问自答
- Q:Mipmap会增加多少内存? A:总内存增加约33%。因为 1 + 1/4 + 1/16 + ... ≈ 1.33。
- Q:如果不懂Mipmap会怎样? A:3D场景中远处的纹理会闪烁、出现摩尔纹,画面质量很差。
25. 纹理过滤 (Texture Filtering)
| 维度 | 内容 |
|---|---|
| 定义 | 纹理采样时计算像素颜色的插值方法 |
| 一句话本质 | "放大缩小算法":纹理和屏幕像素不匹配时怎么采样 |
| 类比解释 | 照片放大。NEAREST是简单复制像素(马赛克),LINEAR是双线性插值(平滑模糊) |
| 技术细节 | 放大过滤(magFilter):NEAREST(快、像素风)、LINEAR(默认、平滑)。缩小过滤(minFilter):NEAREST(闪烁)、LINEAR(摩尔纹)、NEAREST_MIPMAP_NEAREST、LINEAR_MIPMAP_NEAREST、NEAREST_MIPMAP_LINEAR、LINEAR_MIPMAP_LINEAR(最佳)。2D游戏通常LINEAR/LINEAR |
| 常见误区 | ❌ 缩小用LINEAR(远处会摩尔纹,应该用Mipmap) ❌ 像素风游戏用LINEAR(应该用NEAREST保持锐利像素边缘) |
26. 纹理图集 (Texture Atlas / Sprite Sheet)
| 维度 | 内容 |
|---|---|
| 定义 | 将多张图片合并到一张大纹理中的技术 |
| 一句话本质 | "相册":把多张照片合到一页,翻一次看所有 |
| 类比解释 | 快递的集装箱。原来10个小包裹发10次(10个DrawCall),现在装到一个集装箱发1次(1个DrawCall) |
| 技术细节 | 优势:(1)减少DrawCall(相同图集自动合批);(2)减少纹理切换开销;(3)更好的Mipmap支持。注意:图集大小不能超过GPU最大纹理尺寸(低端机2048×2048)。图集之间要留padding(1-2像素)防止纹理渗透 |
| 常见误区 | ❌ 图集越大越好(超过2048低端机不支持,加载慢) ❌ 图集不留间隙(相邻图片的像素会互相渗透,出现杂边) |
27. 动态图集 (Dynamic Atlas)
| 维度 | 内容 |
|---|---|
| 定义 | 运行时自动将小纹理合并到大图集的技术 |
| 一句话本质 | "自动拼车":运行时把小包裹自动装进集装箱 |
| 类比解释 | 快递公司的智能分拣系统。包裹来了自动分类、装箱,不需要人工预先打包 |
| 技术细节 | Cocos的Dynamic Atlas Manager自动将小于256×256的散图合并到2048×2048大图集。优点:无需手动打包,运行时自动合批。缺点:额外内存开销(每张图集16MB)、频繁换图导致碎片化、大图(>256)不参与。小游戏平台慎用(内存限制严格) |
| 常见误区 | ❌ 开启动态图集就不管了(需要监控图集数量和内存) ❌ 所有纹理都依赖动态图集(大图、频繁变化的图应该手动打包) |
28. 统一缓冲区 / UBO (Uniform Buffer Object)
| 维度 | 内容 |
|---|---|
| 定义 | 存储在GPU显存中的Uniform数据缓冲区,多个Shader共享 |
| 一句话本质 | "Uniform的仓库":一次上传,多处使用 |
| 类比解释 | 公司的公告栏。贴一次公告(上传Uniform),所有员工(Shader)都能看到 |
| 技术细节 | WebGL2原生支持,WebGL1需要扩展。优势:减少Uniform上传开销(一次绑定vs逐个设置)、多个Shader共享同一组Uniform(如相机参数)。Cocos 3.8.x在WebGL2下自动使用UBO优化 |
| 常见误区 | ❌ WebGL1环境用UBO(需要检查扩展支持) ❌ UBO数据不更新(UBO内容变化需要重新上传,不是自动同步的) |
三、WebGL/API术语
29. WebGL上下文 (WebGL Context)
| 维度 | 内容 |
|---|---|
| 定义 | JavaScript访问GPU渲染能力的接口对象 |
| 一句话本质 | "GPU的遥控器":JS控制GPU的入口 |
| 类比解释 | 电视遥控器。遥控器(WebGL上下文)本身不播放画面,但它可以控制电视(GPU)播放什么 |
| 技术细节 | 创建:canvas.getContext('webgl') 或 'webgl2'。WebGL上下文是状态机:所有操作都修改当前上下文的状态(当前Shader、当前纹理、当前缓冲区等)。Cocos中通过cc.director.root.device.gl可以访问底层WebGL上下文 |
| 常见误区 | ❌ 创建多个WebGL上下文(每个上下文占用大量资源,一个页面通常只有一个) ❌ 上下文丢失不处理(浏览器可能回收GPU资源,需要监听webglcontextlost事件) |
30. WebGL扩展 (WebGL Extension)
| 维度 | 内容 |
|---|---|
| 定义 | WebGL标准之外的额外功能,通过扩展机制启用 |
| 一句话本质 | "插件":给WebGL增加额外能力 |
| 类比解释 | 浏览器的插件。基本浏览器能上网,安装插件后能播视频、去广告 |
| 技术细节 | 常用扩展:OES_texture_float(浮点纹理)、WEBGL_compressed_texture_s3tc(DXT压缩)、EXT_shader_texture_lod(Shader中手动选Mipmap级别)、OES_vertex_array_object(VAO)。WebGL2很多功能原生支持,不需要扩展。Cocos GFX层自动处理扩展检测和启用 |
| 常见误区 | ❌ 假设扩展一定存在(必须检查返回值,不存在时要有fallback) ❌ 扩展名拼写错误(区分大小写,如OES不是oes) |
31. VAO (Vertex Array Object)
| 维度 | 内容 |
|---|---|
| 定义 | 存储顶点属性配置状态的对象,可以一次性绑定所有顶点属性 |
| 一句话本质 | "顶点配置的快照":保存一次,重复使用 |
| 类比解释 | 预设的电台频道。调好后保存,下次一键切换,不需要重新调频 |
| 技术细节 | 没有VAO时:每次绘制都要重新设置vertexAttribPointer和enableVertexAttribArray。有VAO时:创建时设置一次,绘制时只需bindVertexArrayOject。WebGL1需要OES_vertex_array_object扩展,WebGL2原生支持。Cocos底层自动使用VAO优化 |
| 常见误区 | ❌ VAO存储顶点数据(VAO只存储配置,不存储数据,数据仍在VBO中) ❌ 一个VAO绑定多个VBO(一个VAO可以引用多个VBO,但通常一个模型一个VAO) |
32. FBO (Frame Buffer Object)
| 维度 | 内容 |
|---|---|
| 定义 | 离屏渲染的目标,可以将渲染结果输出到纹理而不是屏幕 |
| 一句话本质 | "离屏画布":画到纹理上,而不是屏幕上 |
| 类比解释 | 草稿纸。先在草稿纸上画(FBO),满意后再贴到正式画布上(屏幕) |
| 技术细节 | FBO可以附加:颜色附件(纹理或renderbuffer)、深度附件、模板附件。用途:RenderTexture(Cocos中相机渲染到纹理)、后处理效果(模糊、发光)、反射/阴影贴图。注意:FBO的纹理尺寸影响性能和内存 |
| 常见误区 | ❌ FBO和默认帧缓冲混用(切换有开销,尽量减少切换次数) ❌ FBO尺寸和屏幕不一致(会导致画面拉伸或模糊) |
33. 精度修饰符 (Precision Qualifier)
| 维度 | 内容 |
|---|---|
| 定义 | GLSL中指定变量计算精度的关键字 |
| 一句话本质 | "计算精度档位":高精度慢,低精度快 |
| 类比解释 | 计算器的小数位数。highp是10位小数(精确但慢),lowp是2位小数(快但不精确) |
| 技术细节 | highp(高精度,32位浮点,范围大)、mediump(中精度,16位浮点,范围±2^14)、lowp(低精度,8-10位,范围±2^8)。默认精度:precision mediump float;。移动端建议:颜色用lowp,UV用mediump,位置用highp。WebGL1中片元着色器默认没有高精度浮点 |
| 常见误区 | ❌ 所有变量都用highp(浪费性能,移动端可能不支持) ❌ 在片元着色器里用highp(WebGL1片元着色器可能不支持highp) |
四、性能指标术语
34. FPS (Frames Per Second)
为什么需要这个概念? FPS是衡量游戏流畅度的最直观指标。玩家能直接感受到卡顿,而FPS就是量化这种感受的数字。
| 维度 | 内容 |
|---|---|
| 定义 | 每秒渲染的帧数 |
| 一句话本质 | "流畅度指标":每秒换多少张画 |
| 类比解释 | 翻书动画。FPS=60就像每秒翻60页,看起来是流畅的动画。FPS=10就像每秒翻10页,明显卡顿 |
| 技术细节 | 60fps = 每帧16.67ms;30fps = 每帧33.33ms。人眼舒适下限:30fps。游戏目标:60fps。VR需要90fps+。Cocos中cc.debug.setDisplayStats(true)显示FPS。注意:FPS高不代表性能好(可能是场景简单) |
| 常见误区 | ❌ 只看FPS不看帧时间(FPS波动大时,看平均帧时间更稳定) ❌ 追求120fps不考虑耗电(移动端高帧率=高耗电+发热) |
自问自答
- Q:FPS和帧时间有什么关系? A:FPS = 1000 / 帧时间(ms)。60fps = 16.67ms/帧。帧时间比FPS更稳定,优化时应该看帧时间。
- Q:如果不懂FPS会怎样? A:你无法判断游戏是否流畅,也不知道优化目标是什么。
35. DrawCall数
| 维度 | 内容 |
|---|---|
| 定义 | 一帧中CPU向GPU发送的绘制命令次数 |
| 一句话本质 | "CPU喊话次数":喊一次GPU画一次 |
| 类比解释 | 老师点名。点10个同学(10个DrawCall)vs 点一次"全班起立"(1个DrawCall) |
| 技术细节 | 2D游戏目标:<50个DrawCall。3D游戏目标:<200个DrawCall。每个DrawCall的CPU开销约0.1-1ms(取决于CPU性能和设置复杂度)。DrawCall是2D游戏的第一优化指标。Cocos中cc.debug.setDisplayStats(true)显示DrawCall数 |
| 常见误区 | ❌ 只看DrawCall不看Overdraw(DrawCall少但同一个像素画10次,GPU还是卡) ❌ 以为DrawCall=0最好(什么都不画当然0,但没有意义) |
36. Overdraw
| 维度 | 内容 |
|---|---|
| 定义 | 同一个像素被多次绘制的现象 |
| 一句话本质 | "重复劳动":同一个位置画了又画 |
| 类比解释 | 刷墙。先刷红色,再刷蓝色盖住,再刷绿色盖住。Overdraw=3,但只看到绿色 |
| 技术细节 | 计算方式:总片元数 / 屏幕像素数。理想值=1(每个像素只画一次)。UI游戏Overdraw通常2-4x。减少方法:从前到后绘制不透明物体(Early-Z剔除)、避免大面积半透明叠加、使用遮挡剔除 |
| 常见误区 | ❌ 只关注DrawCall忽略Overdraw(Overdraw高时GPU在无效计算) ❌ 全屏半透明背景(这是Overdraw杀手,每个像素至少画2次) |
37. 帧时间 (Frame Time)
| 维度 | 内容 |
|---|---|
| 定义 | 渲染一帧所需的时间(毫秒) |
| 一句话本质 | "画一帧要多久":时间越短越流畅 |
| 类比解释 | 画一幅画的时间。画得越快,每秒能画的画越多 |
| 技术细节 | 目标:16.67ms(60fps)。>16.67ms → 掉帧。<33.33ms → 至少30fps。测量方法:Chrome DevTools Performance面板、Cocos DisplayStats。帧时间比FPS更稳定(FPS是帧时间的倒数,波动大) |
| 常见误区 | ❌ 只看平均帧时间(要看最大帧时间,卡顿往往由几帧的尖峰引起) ❌ 启动时帧时间高就优化(启动加载资源帧时间高是正常的) |
38. GPU时间 / GPU Frame Time
| 维度 | 内容 |
|---|---|
| 定义 | GPU处理一帧渲染所需的时间 |
| 一句话本质 | "GPU干活时间":GPU有多忙 |
| 类比解释 | 工厂生产线的运转时间。GPU时间高 = 生产线满负荷运转 |
| 技术细节 | 测量工具:SpectorJS、Chrome GPU Timeline、RenderDoc。细分:顶点着色器时间、片元着色器时间、纹理采样时间、带宽瓶颈。如果GPU时间 < CPU时间 → CPU瓶颈(DrawCall太多)。如果GPU时间 > CPU时间 → GPU瓶颈(Shader太复杂/Overdraw高) |
| 常见误区 | ❌ 分不清CPU瓶颈和GPU瓶颈(优化方向完全不同) ❌ 只优化CPU忽略GPU(2D游戏常见CPU瓶颈,但复杂Shader会导致GPU瓶颈) |
39. 带宽 (Bandwidth)
| 维度 | 内容 |
|---|---|
| 定义 | GPU与显存之间的数据传输速率 |
| 一句话本质 | "数据传输速度":路有多宽、车有多快 |
| 类比解释 | 高速公路的车流量。带宽高 = 高速公路宽,同时能跑很多车(传输大量数据) |
| 技术细节 | 单位:GB/s。高端显卡900+GB/s,集成显卡几十GB/s。带宽瓶颈表现:纹理采样慢、大量顶点数据传输卡顿。优化:压缩纹理(减少数据量)、Mipmap(减少采样数据)、合并纹理(减少切换) |
| 常见误区 | ❌ 只优化计算忽略带宽(Shader计算很快,但等数据从显存来会卡住) ❌ 大量小纹理(每个纹理切换都导致带宽开销,应该合并) |
五、Cocos引擎术语
40. Batcher2D
为什么需要这个概念? Cocos场景中可能有几百个Sprite。如果每个Sprite都发一个DrawCall,性能会极差。Batcher2D就是Cocos内置的"自动合批系统",帮你把能合并的Sprite自动合并。
| 维度 | 内容 |
|---|---|
| 定义 | Cocos 2D渲染系统的核心类,负责收集、合并、提交2D渲染数据 |
| 一句话本质 | "2D渲染管家":收集所有2D元素,合并后发给GPU |
| 类比解释 | 餐厅的点菜系统。顾客(Sprite)点菜,系统(Batcher2D)按菜品(纹理)分类,同一类的菜一起下单(合批),减少厨房(GPU)的工作量 |
| 技术细节 | 核心方法:walk()遍历场景树 → commitComp()判断合批条件 → flush()提交DrawCall。合批条件:相同纹理哈希、相同材质、相同深度/模板状态。每帧执行:遍历所有可见节点,收集渲染数据,自动合批,提交GPU |
| 常见误区 | ❌ 以为Batcher2D对所有节点都合批(Mask、自定义材质、Graphics会打断合批) ❌ 节点顺序不影响合批(Batcher2D按遍历顺序合批,节点顺序直接影响能否合批) |
自问自答
- Q:Batcher2D什么时候会打断合批? A:纹理不同、材质不同、混合模式不同、有Mask、使用了Graphics组件等都会打断合批。
- Q:如果不懂Batcher2D会怎样? A:你的游戏DrawCall很高但不知道为什么。实际上可能是节点顺序不对,或者中间插了Mask导致无法合批。
41. RenderPipeline
| 维度 | 内容 |
|---|---|
| 定义 | Cocos的渲染管线管理器,控制整个渲染流程 |
| 一句话本质 | "渲染总指挥":安排谁先画、谁后画 |
| 类比解释 | 电影导演。决定拍摄顺序(渲染顺序)、调用哪些演员(Shader)、用什么道具(纹理) |
| 技术细节 | Cocos 3.8.x使用可定制的RenderPipeline。默认流程:更新相机 → 收集可见物体 → 排序(按优先级/深度) → 执行RenderPass(阴影/主场景/后处理) → 提交CommandBuffer。支持自定义RenderPipeline实现特殊效果 |
| 常见误区 | ❌ 2D游戏不需要关心RenderPipeline(2D也走RenderPipeline,只是流程简单) ❌ 多相机渲染顺序随意(相机priority决定渲染顺序,影响最终画面) |
42. GFX (Graphics API Layer)
| 维度 | 内容 |
|---|---|
| 定义 | Cocos的图形API抽象层,封装WebGL/WebGL2/Metal/Vulkan |
| 一句话本质 | "翻译官":把Cocos的渲染指令翻译成不同平台的API |
| 类比解释 | 联合国翻译。各国代表(WebGL/Metal/Vulkan)说不同语言,GFX是同声传译,让Cocos代码一套跑所有平台 |
| 技术细节 | GFX抽象了:Device(设备)、Buffer(缓冲区)、Texture(纹理)、Shader(着色器)、CommandBuffer(命令缓冲)、Framebuffer(帧缓冲)。H5平台使用WebGLDevice,原生iOS使用MetalDevice。Cocos代码调用GFX API,GFX底层转换为对应平台的原生API |
| 常见误区 | ❌ 直接调用GFX API(应该使用Cocos高层API,GFX是内部实现) ❌ 以为GFX有性能损耗(GFX是薄封装,几乎没有额外开销) |
43. Material / 材质
| 维度 | 内容 |
|---|---|
| 定义 | 定义物体外观的属性集合,包括Shader、纹理、渲染状态 |
| 一句话本质 | "物体的皮肤":决定物体长什么样 |
| 类比解释 | 人的衣服。同一个人(模型),穿不同衣服(材质)看起来完全不同 |
| 技术细节 | Material包含:effectAsset(引用哪个Effect)、technique(使用哪个technique)、passes(Pass数组,每个Pass包含一个Shader程序)、properties(运行时参数,如颜色、透明度)。两个Sprite使用不同Material → 不能合批。修改Material的Uniform → 所有使用该Material的物体都受影响 |
| 常见误区 | ❌ 直接修改sharedMaterials(会影响所有使用同材质的Sprite,应该用getMaterial(0)获取实例) ❌ 每个Sprite创建独立Material(材质实例化会打断合批) |
44. Effect / 效果文件
| 维度 | 内容 |
|---|---|
| 定义 | Cocos的Shader定义文件,包含着色器代码和渲染状态配置 |
| 一句话本质 | "Shader配方书":定义怎么画、用什么参数 |
| 类比解释 | 菜谱。Effect是菜谱,Material是按菜谱做的菜,Shader是具体的烹饪步骤 |
| 技术细节 | Effect文件(.effect)包含:CCEffect块(定义techniques、passes、properties)、CCProgram块(顶点/片元着色器代码GLSL)。一个Effect可以有多个technique(如opaque/transparent),每个technique可以有多个pass(多Pass渲染)。Cocos内置Effect:sprite、label、graphics等 |
| 常见误区 | ❌ Effect和Material混淆(Effect是定义,Material是实例) ❌ 修改内置Effect(应该创建自定义Effect,避免引擎升级覆盖) |
45. RenderQueue / 渲染队列
| 维度 | 内容 |
|---|---|
| 定义 | 控制渲染对象绘制顺序的队列机制 |
| 一句话本质 | "排队系统":决定谁先画、谁后画 |
| 类比解释 | 医院叫号系统。急诊优先(不透明物体先画),普通号后叫(透明物体后画) |
| 技术细节 | Cocos中渲染队列值越小越早绘制。不透明物体:RenderQueue < 2500(从前往后,利于Early-Z)。透明物体:RenderQueue >= 2500(从后往前,利于Alpha混合)。同一队列内按其他规则排序。自定义队列:可以创建自己的RenderQueue控制特殊物体的绘制顺序 |
| 常见误区 | ❌ 透明物体放不透明队列(会导致混合错误) ❌ 以为RenderQueue是唯一排序依据(同队列内还有深度排序、材质排序等) |
46. 脏标记 (Dirty Flag)
| 维度 | 内容 |
|---|---|
| 定义 | 标记对象属性是否发生变化,只有变化时才更新 |
| 一句话本质 | "变化检测器":没变就不重算 |
| 类比解释 | 黑板擦。黑板上10行字,只有1行写错了,只擦那1行重写,不用全擦 |
| 技术细节 | Cocos中的脏标记:TransformBit(位置/旋转/缩放变化)、markForUpdateRenderData(渲染数据需要更新)。原理:属性变化时设置标记 → 渲染阶段检查标记 → 只有标记为脏才重新计算。效果:100个Sprite每帧更新 → 只更新变化的 → CPU降低50-80% |
| 常见误区 | ❌ 每帧都设置position(即使值没变也标记脏,应该判断后再设置) ❌ 手动调用markForUpdateRenderData(引擎自动管理,除非你知道在做什么) |
47. 静态合批 (Static Batching)
| 维度 | 内容 |
|---|---|
| 定义 | 对不移动、不变化的节点标记为静态,跳过每帧的遍历和更新 |
| 一句话本质 | "固定展品":摆好就不动,不用每天重新摆 |
| 类比解释 | 博物馆的展品。不会动的展品(静态节点),只需要摆一次,不用每天重新摆 |
| 技术细节 | Cocos中设置node._static = true(3.8.x内部属性)。效果:跳过Transform更新遍历、跳过渲染数据重建。适用:背景UI、固定装饰、不交互的元素。注意:静态节点不能有动态子节点,设置后子节点的变换更新会被跳过 |
| 常见误区 | ❌ 所有节点都设_static(动态节点设静态会导致不更新) ❌ _static是公开API(这是内部属性,官方不推荐直接使用) |
48. 动态合批 (Dynamic Batching)
| 维度 | 内容 |
|---|---|
| 定义 | 引擎在运行时自动将满足条件的渲染对象合并到一个DrawCall |
| 一句话本质 | "自动拼车":满足条件就自动合并 |
| 类比解释 | 拼车软件。只要目的地相同(纹理相同)、车型相同(材质相同),就自动拼到一辆车 |
| 技术细节 | Batcher2D每帧自动执行。条件:相同纹理、相同材质、相同混合模式、相同深度/模板状态、顶点数不超过65535。优点:自动,无需手动操作。缺点:每帧遍历判断有CPU开销、条件不满足时不合批。小游戏平台:动态合批正常可用,但要注意CPU开销 |
| 常见误区 | ❌ 以为动态合批是万能的(条件不满足时不会合批) ❌ 动态合批和静态合批混淆(静态合批跳过遍历,动态合批每帧遍历) |
49. Label组件
| 维度 | 内容 |
|---|---|
| 定义 | Cocos中显示文字的组件 |
| 一句话本质 | "文字渲染器":把文字变成图片显示 |
| 类比解释 | 打印机。把文字(字符串)打印(渲染)到纸上(屏幕) |
| 技术细节 | 三种类型:TTF(TrueType字体,动态生成纹理,支持任意文字但每变一次要重建)、SystemFont(系统字体,性能最好但不同平台效果不同)、BMFont(位图字体,预生成纹理,性能好但只支持固定字符集)。TTF Label的合批:相同字体、相同大小、相同颜色的Label可以合批 |
| 常见误区 | ❌ TTF Label频繁修改文字(每次修改都重建纹理,非常耗CPU) ❌ 用TTF显示大量静态文字(应该用BMFont或SystemFont) |
50. Mask组件
| 维度 | 内容 |
|---|---|
| 定义 | 实现遮罩效果的组件,只显示特定区域内的内容 |
| 一句话本质 | "镂空模板":只让特定形状的内容显示 |
| 类比解释 | 剪纸。把纸剪成形状(Mask),贴在照片上,只露出剪出的部分 |
| 技术细节 | 实现方式:模板测试(Stencil Test)。Mask节点绘制时写入模板缓冲,子节点绘制时检查模板值。性能影响:Mask打断合批(模板状态变化)、增加2个DrawCall(写模板+用模板)。建议:尽量少用Mask,能用矩形裁剪(ScrollView的裁剪)就不用Mask |
| 常见误区 | ❌ Mask嵌套太多层(每层Mask增加2个DrawCall和模板操作开销) ❌ 以为Mask只是视觉裁剪(Mask是渲染层面的,不影响节点的事件响应区域) |
六、高级渲染术语
51. LOD (Level of Detail)
| 维度 | 内容 |
|---|---|
| 定义 | 根据物体距离相机的远近,使用不同精度的模型 |
| 一句话本质 | "远近有别":远处模糊,近处清晰 |
| 类比解释 | 看风景。远处的山只看轮廓(低模),近处的花要看细节(高模) |
| 技术细节 | 通常设置3-4个级别:LOD0(最近,最高精度)、LOD1(中等距离)、LOD2(远距离,最低精度)。切换方式:按距离切换、按屏幕占比切换。注意:LOD切换要平滑过渡,否则会出现"弹出"(Pop)现象 |
| 常见误区 | ❌ 2D游戏也用LOD(2D游戏通常不需要,Sprite本身就是平面) ❌ LOD切换距离设置不合理(太近切换会看到模型变化,太远切换浪费性能) |
52. Occlusion Culling / 遮挡剔除
| 维度 | 内容 |
|---|---|
| 定义 | 不渲染被其他物体完全遮挡的物体 |
| 一句话本质 | "看不见的就不画" |
| 类比解释 | 站在墙后的人。既然被墙挡住了,就不用画这个人 |
| 技术细节 | 实现方式:软件遮挡查询(CPU计算遮挡关系)、硬件遮挡查询(GPU的OCCLUSION_QUERY)、预计算遮挡(烘焙遮挡数据)。Cocos 3.8.x对2D游戏自动做简单的屏幕裁剪(超出屏幕的不渲染),但3D遮挡剔除需要额外实现 |
| 常见误区 | ❌ 遮挡剔除没有开销(计算遮挡本身有CPU/GPU开销,需要权衡) ❌ 所有游戏都需要遮挡剔除(2D游戏通常不需要,3D大场景才需要) |
53. GPU Instancing
| 维度 | 内容 |
|---|---|
| 定义 | 一次DrawCall绘制多个相同几何的实例,每个实例可以有不同的变换和颜色 |
| 一句话本质 | "批量复制":画100个相同的树,只要1个DrawCall |
| 类比解释 | 印章。刻一个章(模型),盖100次(100个实例),每次盖在不同位置 |
| 技术细节 | WebGL2原生支持,WebGL1需要ANGLE_instanced_arrays扩展。实例数据通过attribute传递(每个实例一个值,不是每个顶点)。Cocos 3.8.x在3D渲染中支持GPU Instancing。限制:所有实例必须共享相同几何和材质,只有变换/颜色等可以不同 |
| 常见误区 | ❌ Instancing和动态合批混淆(Instancing是GPU特性,动态合批是CPU合并顶点) ❌ 以为Instancing对所有物体都适用(只有大量相同几何的物体才适合,如草、树、粒子) |
54. SRGB vs Linear
| 维度 | 内容 |
|---|---|
| 定义 | 两种不同的颜色空间,SRGB是非线性的,Linear是线性的 |
| 一句话本质 | "颜色存储格式":SRGB省空间,Linear适合计算 |
| 类比解释 | 音量的分贝刻度。人耳对低音更敏感,所以分贝是非线性的。类似地,人眼对暗部更敏感,SRGB在暗部存储更多细节 |
| 技术细节 | SRGB:存储时gamma编码(约0.45次方),显示时gamma解码(约2.2次方)。Linear:线性存储,直接参与光照计算。问题:如果在SRGB空间做光照计算,结果会偏暗/偏亮。正确流程:SRGB纹理 → 解码为Linear → 光照计算 → 编码为SRGB → 显示。Cocos自动处理颜色空间转换 |
| 常见误区 | ❌ 在线性空间存储纹理(暗部精度不足,出现色带) ❌ 在SRGB空间做Shader计算(光照结果错误) |
55. MRT (Multiple Render Targets)
| 维度 | 内容 |
|---|---|
| 定义 | 一次渲染同时输出到多个颜色缓冲 |
| 一句话本质 | "一鱼多吃":画一次,得到多张图 |
| 类比解释 | 拍照时同时拍彩色和黑白。按一次快门,得到两种照片 |
| 技术细节 | WebGL2原生支持,WebGL1不支持。用途:延迟渲染(同时输出颜色/法线/深度)、后处理(输出原图+模糊图)。限制:所有目标尺寸必须相同。Cocos 3.8.x的RenderPipeline支持MRT |
| 常见误区 | ❌ MRT目标尺寸不同(GPU要求所有目标尺寸一致) ❌ 滥用MRT(增加带宽压力,只在需要时用) |
56. Compute Shader
| 维度 | 内容 |
|---|---|
| 定义 | 在GPU上执行通用计算任务的着色器,不直接参与渲染 |
| 一句话本质 | "GPU计算器":用GPU做非图形计算 |
| 类比解释 | 用显卡挖矿。显卡本来是用来画画的,但也可以用来做数学计算(挖矿就是解数学题) |
| 技术细节 | WebGL不支持Compute Shader(需要WebGPU)。用途:粒子系统、物理模拟、图像处理、AI推理。优势:利用GPU并行计算能力,比CPU快几十到几百倍。Cocos目前主要通过原生插件支持Compute Shader |
| 常见误区 | ❌ WebGL环境用Compute Shader(WebGL不支持,必须用WebGPU或原生) ❌ 所有计算都用GPU(数据在CPU和GPU之间传输有开销,小计算在CPU更快) |
57. 后处理 (Post-Processing)
| 维度 | 内容 |
|---|---|
| 定义 | 在场景渲染完成后,对最终画面进行额外处理的效果 |
| 一句话本质 | "照片滤镜":画完后再加特效 |
| 类比解释 | 拍照后用PS加滤镜。先拍一张照片(场景渲染),然后调色、加模糊、加光晕(后处理) |
| 技术细节 | 实现方式:渲染场景到FBO纹理 → 用全屏Quad绘制该纹理 → 片元着色器处理每个像素。常见效果:Bloom(泛光)、Blur(模糊)、Tone Mapping(色调映射)、Color Grading(调色)。性能影响:至少增加1个全屏DrawCall + 片元着色器处理所有像素 |
| 常见误区 | ❌ 后处理不影响性能(全屏后处理每帧处理所有像素,是性能杀手) ❌ 所有效果都堆上去(后处理效果叠加,性能和画质都要权衡) |
58. 延迟渲染 (Deferred Rendering)
为什么需要这个概念? 传统渲染(Forward Rendering)中,每个物体都要计算光照。如果场景有100个光源,每个物体都要算100次光照,性能爆炸。延迟渲染把光照计算推迟到最后,只算屏幕上可见的像素,光源数量不再影响性能。
| 维度 | 内容 |
|---|---|
| 定义 | 将光照计算推迟到几何信息收集完成后进行的渲染技术 |
| 一句话本质 | "先存信息,后算光照":不是画一个物体算一次光照,而是全部存下来统一算 |
| 类比解释 | 装修房子。传统方式:每刷一面墙就上一次色(Forward Rendering)。延迟渲染:先刷完所有墙(存几何信息),最后统一上色(光照计算) |
| 技术细节 | G-Buffer:存储位置/法线/颜色/材质属性的多目标渲染纹理。优点:光源数量不影响性能(适合多光源场景)、光照计算在屏幕空间(只计算可见像素)。缺点:需要MRT支持、内存开销大(G-Buffer占显存)、半透明物体需要单独处理(Forward Rendering)。Cocos 3.8.x支持延迟渲染管线 |
| 常见误区 | ❌ 2D游戏用延迟渲染(2D游戏通常只有1-2个光源,Forward Rendering更快) ❌ 延迟渲染一定比Forward好(简单场景Forward更快,延迟渲染有额外开销) |
自问自答
- Q:延迟渲染为什么不适合2D游戏? A:2D游戏通常只有1-2个光源,Forward Rendering已经足够快。延迟渲染需要额外的G-Buffer内存和MRT支持,对2D来说是"杀鸡用牛刀"。
- Q:如果不懂延迟渲染会怎样? A:在3D项目中盲目使用延迟渲染,导致内存占用过高、半透明物体处理困难。
学习建议
如何高效使用本文档
第1阶段:建立框架(1-2天)
- 通读所有术语的"一句话本质"和"类比解释"
- 不需要记住技术细节,先建立直觉认知
- 目标:看到术语能知道它大概是干嘛的
第2阶段:深入理解(1周)
- 按分类逐个学习,重点看"技术细节"
- 配合《GPU渲染管线详解.md》一起阅读
- 目标:能用自己的话解释每个术语
第3阶段:实践验证(持续)
- 写代码时遇到不懂的词,回来查文档
- 重点关注"常见误区",避免踩坑
- 目标:将知识转化为实际编码能力
第4阶段:面试准备(按需)
- 重点记忆"一句话本质"和"类比解释"
- 准备2-3个"常见误区"的应对策略
- 目标:能流畅地回答技术面试问题
如果读完还是记不住怎么办?
- 正常现象:58个术语不可能一次全记住
- 建议策略:先记住你最常用的10-15个(如VBO、Shader、DrawCall、合批等)
- 记忆技巧:把术语和实际项目中的问题联系起来("上次卡顿就是因为DrawCall太多")
- 重复策略:每隔一段时间回来复习,每次都会有新收获
速查表
按分类速查
| 分类 | 名词 |
|---|---|
| 渲染管线 | 渲染管线、顶点、图元、顶点着色器、片元着色器、光栅化、逐片元操作、帧缓冲、深度缓冲、模板缓冲、混合、VBO、IBO、MVP矩阵、NDC、视口变换、DrawCall、合批、着色器程序、GLSL |
| GPU架构 | 显存、纹理、UV坐标、Mipmap、纹理过滤、纹理图集、动态图集、UBO |
| WebGL/API | WebGL上下文、WebGL扩展、VAO、FBO、精度修饰符 |
| 性能指标 | FPS、DrawCall数、Overdraw、帧时间、GPU时间、带宽 |
| Cocos引擎 | Batcher2D、RenderPipeline、GFX、Material、Effect、RenderQueue、脏标记、静态合批、动态合批、Label、Mask |
| 高级渲染 | LOD、遮挡剔除、GPU Instancing、SRGB vs Linear、MRT、Compute Shader、后处理、延迟渲染 |
关键数字记忆
| 数字 | 含义 |
|---|---|
| 4 | Sprite顶点数、顶点着色器输出gl_Position(vec4) |
| 6 | Sprite索引数(2个三角形)、IBO索引数 |
| 16.67ms | 60fps的目标帧时间 |
| 65535 | 单个DrawCall最大顶点数(uint16限制) |
| 50 | 2D游戏DrawCall目标上限 |
| 207万 | 1080P屏幕像素数 |
| 128 | WebGL1最小支持Uniform数量(vec4) |
| 2048 | 低端机最大纹理尺寸 |
| 0-1 | UV坐标范围、深度缓冲值范围 |
| -1~1 | NDC坐标范围 |
| 65535 | 单个DrawCall最大顶点数(uint16限制) |
| 50 | 2D游戏DrawCall目标上限 |
| 207万 | 1080P屏幕像素数 |
| 128 | WebGL1最小支持Uniform数量(vec4) |
| 2048 | 低端机最大纹理尺寸 |
| 0-1 | UV坐标范围、深度缓冲值范围 |
| -1~1 | NDC坐标范围 |
| ------ | ------ |
| 渲染管线 | 渲染管线、顶点、图元、顶点着色器、片元着色器、光栅化、逐片元操作、帧缓冲、深度缓冲、模板缓冲、混合、VBO、IBO、MVP矩阵、NDC、视口变换、DrawCall、合批、着色器程序、GLSL |
| GPU架构 | 显存、纹理、UV坐标、Mipmap、纹理过滤、纹理图集、动态图集、UBO |
| WebGL/API | WebGL上下文、WebGL扩展、VAO、FBO、精度修饰符 |
| 性能指标 | FPS、DrawCall数、Overdraw、帧时间、GPU时间、带宽 |
| Cocos引擎 | Batcher2D、RenderPipeline、GFX、Material、Effect、RenderQueue、脏标记、静态合批、动态合批、Label、Mask |
| 高级渲染 | LOD、遮挡剔除、GPU Instancing、SRGB vs Linear、MRT、Compute Shader、后处理、延迟渲染 |
关键数字记忆
| 数字 | 含义 |
|---|---|
| 4 | Sprite顶点数、顶点着色器输出gl_Position(vec4) |
| 6 | Sprite索引数(2个三角形)、IBO索引数 |
| 16.67ms | 60fps的目标帧时间 |
| 65535 | 单个DrawCall最大顶点数(uint16限制) |
| 50 | 2D游戏DrawCall目标上限 |
| 207万 | 1080P屏幕像素数 |
| 128 | WebGL1最小支持Uniform数量(vec4) |
| 2048 | 低端机最大纹理尺寸 |
| 0-1 | UV坐标范围、深度缓冲值范围 |
| -1~1 | NDC坐标范围 |