几何着色器本质是图元级处理器,接收完整图元并可生成/修改/剔除图元,专用于拓扑操作而非顶点变换;其性能代价高且已成可选特性,多数场景应优先选用vs、ts或cpu方案替代。

几何着色器不是“顶点着色器加强版”,它操作的是图元
几何着色器(Geometry Shader)在 OpenGL 渲染管线里干一件顶点着色器根本做不到的事:它接收的不是单个顶点,而是一个完整的图元(比如一个 GL_TRIANGLES 对应的 3 个顶点),然后可以决定——生成 0 个、1 个或多个新图元,甚至改类型(把三角形变三条线段)。这是它和 Vertex Shader 的本质区别。
常见误用是试图在 GS 里做顶点位移动画——这该由 VS 做;GS 真正该干的是「拓扑级操作」:粒子爆发、毛发挤出、线框膨胀、三角形细分、剔除整块面片等。
- 输入必须匹配绘图命令:用
glDrawArrays(GL_TRIANGLES, ...),GS 输入布局就得写layout(triangles) in;,否则链接失败或黑屏 - 输出图元类型只有三种可选:
points、line_strip、triangle_strip,不能直接输出lines或triangles - 必须显式指定最大输出顶点数:
layout(triangle_strip, max_vertices = 4) out;,超了就静默丢弃,不报错也不警告
怎么让一个三角形“长出”三个小金字塔?
这是几何着色器最典型的入门实操:输入一个三角形(3 个顶点),对每个顶点沿法向偏移,再拼成一个四棱锥(5 个顶点 → 用 triangle_strip 输出 6 个顶点,自动构成 4 个三角形面)。
关键不是“怎么算偏移”,而是结构控制:
- 输入:用
gl_in[i].gl_Position拿原始顶点位置,用gl_in[i].<var>your_normal</var>(需从 VS 传入)获取法向 - 输出:调用
EmitVertex()四次以上才能形成有效图元;最后必须跟EndPrimitive(),否则 GPU 不知道图元结束 - 别忘了设置
glPatchParameteri(GL_PATCH_VERTICES, 3)—— 这是曲面细分才需要的,GS 完全不用,加了反而干扰
为什么开了 GS 后帧率暴跌?
几何着色器是 OpenGL 管线里唯一能「凭空造顶点」的阶段,但代价极高:它串行处理每个图元,无法像 VS 那样大规模并行;且每次调用都可能触发额外内存分配与光栅化重调度。
典型性能雷区:
- 在 GS 里做复杂计算(如噪声采样、矩阵求逆)——这些该提前在 CPU 或 CS/VS 里做完
- 输出顶点数波动大(比如条件分支导致有时输出 1 个点、有时输出 20 个三角形)——破坏 GPU 流水线效率
- 用
points输出大量点再靠glPointSize放大模拟粒子——不如用point sprites+Fragment Shader更快 - OpenGL 4.6+ 中,GS 已被标记为“可选实现”,部分集成显卡(如 Intel UHD 核显旧驱动)会回退到 CPU 模拟,
glGetError()返回GL_NO_ERROR但实际卡顿
替代方案比硬上 GS 更常用
很多你以为“非 GS 不可”的效果,其实有更稳更快的路径:
- 粒子系统:用
glDrawArraysInstanced()+ 实例化属性 +Vertex Shader位移,比 GS 生成粒子快 3–5 倍 - 线框渲染:用
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)或Geometry Shader+glProvokingVertex()控制线序,但前者零开销 - 毛发/草地:用纹理数组 +
Tessellation Shader细分基底三角形,再由Vertex Shader挤出,避免 GS 的图元瓶颈 - 想动态删面片?直接在 CPU 构建索引缓冲区(
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ...)),比 GS 里if (discard)更可控
真正值得动用 GS 的场景其实很窄:需要基于邻接信息做决策(比如只渲染朝向摄像机的边)、或必须在光栅化前完成图元重组(如将线段转带宽度的四边形)。其他时候,先问自己一句:这个逻辑能不能挪到 VS 或 CPU 做?
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











