WebGPU 大三角形覆盖裁剪空间
原作者:webgpufundamentals Contributors
原文链接:https://webgpufundamentals.org/webgpu/lessons/webgpu-large-triangle-to-cover-clip-space.html
本文是对 WebGPUFundamentals 中一篇短文的编译与解读,重点在于一个小而实用的 技巧 / 模式——用单个大三角形代替两个三角形来覆盖整个裁剪空间。该技巧属于轻度优化,但能简化代码并避免一些 GPU 光栅化开销。
正文
经常需要绘制一个全屏、全覆盖画布或全纹理的四边形(quad),换句话说,一个覆盖整个裁剪空间的矩形。
最直接的方法是使用两个三角形组成一个四边形:
对应的顶点数据如下:
// 左下三角形
-1, -1,
1, -1,
-1, 1,
// 右上三角形
-1, 1,
1, -1,
1, 1,
无论你是在顶点着色器中传入这些数据,还是将其硬编码到着色器里,这都是一种常见需求。我们在之前的文章中已经多次使用过,例如导入纹理时生成 mipmap 一文。
这种方法有效且易于理解。
但对于这个特定场景,有一个捷径:我们可以用一个足够大的单个三角形,使其完全覆盖裁剪空间区域。一个简单的示例如下:
只用 3 个顶点代替 6 个:
-1, 3,
3, -1,
-1, -1,
由于 GPU 会将该三角形裁剪到裁剪空间内,最终得到的结果与使用两个三角形组成的四边形完全相同,但我们少打了一些顶点。
除此之外,GPU 通常以 2x2 像素块为单位绘制像素。这有多方面原因,其中之一是为了提高效率。因此,当我们绘制两个三角形时,在两个三角形相交的边缘处,GPU 需要做额外工作——它本希望处理一个 2x2 的像素块,但不得不只绘制每个三角形实际需要覆盖的那 1 或 2 个像素。
使用单个大三角形就可以避免这种额外开销。
实际上,这种额外开销非常小。对于一个全屏四边形来说,它可能只占 60Hz 帧时间不到 0.5%。它不是零开销,但也不太可能成为你的应用流畅与否的决定性因素。
尽管如此,输入 3 个顶点比输入 6 个更简单,即使性能提升微乎其微,在合适的场景下使用这种模式依然让人感觉良好。凡是需要绘制全裁剪空间四边形的场合都可以采用,例如生成 mipmap、绘制天空盒、后处理、制作 ShaderToy 等。
3 个核心优化要点
-
减少顶点数量
使用单个大三角形(3 个顶点)代替两个三角形(6 个顶点)覆盖整个裁剪空间,减少顶点数据传输量和着色器处理开销。 -
避免 2x2 像素块边缘开销
GPU 光栅化时以 2x2 像素块为单位处理。两个三角形的共享边会产生额外的像素剔除工作;单一大三角形消除了这条内部共享边,从而避免了这部分开销。 -
简化代码与维护
三顶点方案代码更简洁,适用于全屏四边形、后处理、天空盒、mipmap 生成等高频场景,降低出错概率并提升可读性。
GLSL / WebGL 专业术语检查
虽然本文针对 WebGPU(其着色语言为 WGSL),但其中涉及的图形学术语与 GLSL / WebGL 中含义一致。以下为关键术语对照:
| 英文术语 | 中文翻译 | 说明 |
|---|---|---|
| Clip Space | 裁剪空间 | 顶点着色器输出后,GPU 进行裁剪的坐标空间,范围通常为 [-1, 1](WebGPU 中为 0~1 深度等)。 |
| Vertex Shader | 顶点着色器 | 处理顶点数据的可编程着色器阶段。WebGL 中使用 GLSL,WebGPU 中使用 WGSL。 |
| Mipmaps | 多级渐远纹理 / Mipmap | 预先生成的一系列逐级缩小的纹理,用于加速采样和减少闪烁。 |
| Quad | 四边形 | 通常指覆盖屏幕的矩形,由两个三角形组成(也可优化为单个大三角形)。 |
| 2x2 Pixel Quad | 2x2 像素块 / 像素四边形 | GPU 光栅化时的基本像素处理单元,也用于计算屏幕空间导数(如 dFdx / dFdy)。 |
| Post Processing | 后处理 | 在场景渲染完成后对图像进行的屏幕空间处理。 |
| Skybox | 天空盒 | 环境映射的一种,用于模拟远景天空。 |
这些术语在 WebGL / OpenGL / Vulkan 等图形 API 中均有对应概念,翻译时保持一致性即可。
