Cocos Creator Shader 入门 (1) —— 什么是 Shader?

271 阅读5分钟

💡 本系列文章收录于个人专栏 ShaderMyHead:juejin.cn/column/7505…

一、Shader 简介

Shader(着色器)是一段运行在 GPU 上的程序,开发者通过编写程序,可以在图形渲染的过程中实现高度自定义的图形效果(如光照、材质、后处理等),因此 Shader 是游戏开发中必备的一项重要技能。

示例图(一个使用 Shader 实现的溶解效果):

May-20-2025 10-42-07.gif

二、为何需要 Shader?

因为 Shader 是利用 GPU 来执行渲染图像的程序,比起走 CPU 绘制图像的形式,GPU 渲染图形的效率会高得多。

对于一帧图像来说,它会由非常多的像素点构成,每个像素点的位置、颜色都需要经过计算处理并绘制到屏幕上。

CPU 的计算能力自然是非常强大的,如果仅有少数的像素需要进行计算,CPU 可以非常快速地得到结果。但问题在于一个图像需要计算的像素数量实在太庞大了,而 CPU 的核心数量较少,导致绘制完一帧图像的总时长会非常高。

而 GPU 专为大规模并行计算设计,其包含数千个小型计算核心(如 NVIDIA RTX4090 具备 16,384 个 CUDA 核心),尤其适合处理高度重复、可并行的任务(如顶点变换、片元着色)。

英伟达的专家曾通过机器串行/并行喷射绘画的展示,来科普 GPU 高效绘图的能力:

首先以串行喷射的绘画,来模拟 CPU 绘图的形式:

111111111111.gif

接着是以万箭齐发喷射的绘画,来模拟 GPU 绘图的形式:

22222.gif

因此在图像处理领域,擅长与 GPU 打交道的 Shader 是一门必备的技能。

三、如何编写 Shader?

3.1 GLSL

GLSL(OpenGL Shading Language) 是当下最主流的 Shader 编程语言,它基于 OpenGL ES / WebGL 标准。

下方是一段简单的 GLSL 代码示例:

in vec2 a_position;
in vec4 a_color;

out vec4 v_color;

void main() {
   v_color = a_color;
   gl_Position = vec4(a_position, 0.0, 1.0);
}

Cocos Creator 也是使用的 GLSL 来开发 Shader,我们会在下篇文章学习 GLSL 语法。

3.2 其它 Shader 开发语言(仅做了解)

除了 GLSL,还可以使用如下语言来开发 Shader:

  • HLSL (High-Level Shading Language)
    微软 DirectX 的 Shader 语言,需通过工具转换为 GLSL 来跨平台。
  • MSL (Metal Shading Language)
    苹果 Metal 的 Shader 语言。
  • WGSL (WebGPU Shading Language)
    下一代的跨平台 WebGPU Shader 语言,未来可能成为 Web 标准,截止本文发布时还处于草案阶段,兼容性较差(特别是移动端)。

四、渲染管线

渲染管线(Rendering Pipeline)是图形渲染的核心流程,它描述了从 数据 到最终 屏幕像素图像 的完整处理过程,而 Shader 程序用于控制渲染管线中的特定阶段,因此理解渲染管线阶段和协作机制,是掌握 Shader 编程、性能优化和高级渲染效果的基础。

4.1 渲染管线的核心阶段

一个经典的渲染管线会按顺序依次执行如下几个阶段:

1. 应用阶段(Application Stage)

  • 输入:2D Sprite 数据,或者 3D 模型、纹理、材质、灯光等数据。

  • 处理

    • CPU 准备数据(如模型矩阵、摄像机参数)。
    • 调用图形 API,将数据提交给 GPU。

2. 顶点处理阶段(Vertex Processing)

  • 输入:顶点数据(Vertex Data)。

  • 处理:通过顶点着色器(Vertex Shader) 计算和设置每个顶点的位置、尺寸等属性。

3. 图元装配(Primitive Assembly)

  • 输入:顶点数据。

  • 处理

    • 将顶点组装成基本图元(点、线、三角形)。
    • 执行裁剪(Clipping):剔除屏幕外的图元。

4. [可选] 几何着色器处理(Geometry Shading)

  • 输入:图元数据。

  • 处理:接收完整的图元(如一个三角形、一条线段),可以修改、丢弃或生成新的图元。

5. 光栅化(Rasterization)

  • 输入:图元(如三角形)。

  • 处理

    • 将连续的几何图形离散化为片元(Fragment) ,即像素候选。
    • 计算每个片元的位置、深度、插值后的属性(如 UV、颜色)。

💡 进一步了解片元 image.png

  • 片元是光栅化阶段的产物
    当几何图形(如三角形)被光栅化时,它会被分割成许多小单元,每个单元对应一个携带了信息的候选像素,即片元。
  • 片元携带的信息
    包括颜色、深度(Z值)、纹理坐标、模板值等。
  • 片元 ≠ 最终像素
    片元只是潜在的像素 (所以才叫候选像素),后续可能被丢弃(如被遮挡)或被修改(如混合半透明颜色)。

6. 片元处理阶段(Fragment Processing)

  • 输入:光栅化后的片元数据。

  • 处理:通过片元着色器(Fragment Shader) 计算每个片元的颜色(纹理采样、光照计算等)。

7. 测试与混合(Testing & Blending)

  • 输入:片元颜色和深度信息。

  • 处理

    • 执行深度测试(Depth Test)、模板测试(Stencil Test)。
    • 将通过测试的片元进行混合(Blending):与帧缓冲区中已有的颜色按混合方程(如 alpha 混合)合成。
    • 写入帧缓冲区(Frame Buffer)。

8. 输出到屏幕

  • 处理:帧缓冲区的像素数据最终显示在屏幕上。

4.2 Shader 在渲染管线中的作用

上述的渲染管线流程中,顶点处理阶段和片元处理阶段都需要 Shader 的参与:

  • 在顶点处理阶段,使用 Vertex Shader(顶点着色器) 对顶点进行处理;
  • 在几何着色器处理阶段,使用 Geometry Shader(几何着色器) 对已组装的图元进行进一步增/删处理(进而生成新图元),留意此阶段并非渲染管线必经阶段,且移动端对几何着色器的支持有限
  • 在片元处理阶段,使用 Fragment Shader(片元着色器) 对片元数据进行处理。

我们可以将渲染管线流程简化为:

数据 → Vertex Shader(顶点着色器)→ 图元装配 → [可选] Geometry Shader(几何着色器)→ 光栅化 → Fragment Shader(片元着色器)→ 测试与混合

该流程示意图如下(蓝色模块表示可通过 GLSL 编程的 Shader 处理模块):

6.jpg

在下篇文章,我们会在 Cocos Creator 中,通过 Shader 来将一个节点染色。