顶点着色器

📅 发布时间:2026/7/5 11:06:36 👁️ 浏览次数:
顶点着色器
顶点着色器Vertex Shader是图形渲染管线Graphics Pipeline中第一个可编程阶段专门负责处理三维模型的顶点数据如位置、法线、纹理坐标、颜色等是实现 3D 图形变换平移、旋转、缩放、投影的核心。可以把顶点着色器理解为给每个顶点 “做数据加工” 的小程序。输入模型的原始顶点数据如本地坐标、顶点颜色处理将顶点从 “模型空间” 转换到 “屏幕空间”核心是坐标变换输出处理后的顶点数据传递给后续的光栅化阶段。核心作用坐标空间变换最核心模型空间 → 世界空间让模型放到场景中世界空间 → 观察空间模拟相机视角观察空间 → 裁剪空间投影把 3D 转 2D顶点属性处理修改顶点颜色、传递纹理坐标、计算顶点光照基础漫反射 / 高光数据传递将处理后的顶点数据如法线、纹理坐标输出到片元着色器。GLSL 顶点着色器示例下面是一个基础且完整的顶点着色器示例OpenGL ES 3.0/GLSL 300 ES包含核心的坐标变换逻辑// 版本声明必须放在第一行匹配渲染环境 #version 300 es // 1. 输入从CPU传递过来的顶点属性attribute变量 // 顶点位置模型空间的原始坐标vec3表示3维向量x,y,z in vec3 a_Position; // 顶点颜色可选每个顶点的颜色 in vec3 a_Color; // 顶点纹理坐标可选用于贴纹理 in vec2 a_TexCoord; // 2. 统一变量uniform所有顶点共享的数据从CPU传入 // 模型-视图-投影矩阵MVP矩阵核心变换矩阵 uniform mat4 u_MVPMatrix; // 3. 输出传递给片元着色器的变量out变量 out vec3 v_Color; // 传递顶点颜色 out vec2 v_TexCoord; // 传递纹理坐标 // 4. 主函数顶点着色器的入口每个顶点执行一次 void main() { // 核心将顶点位置从模型空间转换到裁剪空间必须赋值给gl_Position gl_Position u_MVPMatrix * vec4(a_Position, 1.0); // 注vec4是4维向量w分量设为1.0表示顶点是“点”而非方向 // 传递顶点颜色到片元着色器 v_Color a_Color; // 传递纹理坐标到片元着色器 v_TexCoord a_TexCoord; }关键代码解释版本声明#version 300 es表示使用 OpenGL ES 3.0 的 GLSL 版本不同版本语法略有差异如 ES 2.0 用attributeES 3.0 用in输入变量in/attributea_Position顶点的原始坐标如立方体的 8 个顶点坐标a_Color/a_TexCoord可选的顶点属性根据需求定义统一变量uniformu_MVPMatrixMVP 矩阵模型矩阵 × 视图矩阵 × 投影矩阵由 CPU 计算后传入所有顶点共用uniform 变量不会因顶点不同而变化适合传递全局数据如相机位置、光源颜色输出变量out/varying以v_开头的变量会传递到片元着色器光栅化阶段会自动插值比如两个顶点之间的像素颜色gl_Position顶点着色器的必输变量表示顶点在裁剪空间的坐标类型必须是vec4若未赋值渲染会出错。MVP 矩阵坐标变换核心新手无需手动推导矩阵只需理解作用矩阵作用模型矩阵M将顶点从 “模型空间” 转到 “世界空间”移动 / 旋转 / 缩放模型视图矩阵V将顶点从 “世界空间” 转到 “观察空间”模拟相机视角投影矩阵P将顶点从 “观察空间” 转到 “裁剪空间”透视投影 / 正交投影运行环境与使用流程前置条件掌握基础的 OpenGL/OpenGL ES 渲染流程了解顶点缓冲对象VBO、顶点数组对象VAO的使用用于传递顶点数据使用步骤① 编写顶点着色器源码编译并链接成着色器程序② 向着色器传入顶点数据VBO/VAO③ 计算 MVP 矩阵通过glUniformMatrix4fv传入u_MVPMatrix④ 调用glDrawArrays/glDrawElements绘制GPU 会为每个顶点执行一次顶点着色器。顶点着色器性能优化顶点着色器的性能瓶颈主要来自计算量过大、数据传输效率低、GPU 指令浪费三个方面。优化的核心思路是减少每顶点计算量提升数据处理效率让 GPU 更 “省力”。减少每顶点的计算量最核心顶点着色器每个顶点执行一次模型顶点数越多比如几十万顶点的复杂模型计算量放大越明显。优先砍掉非必要计算或把计算转移到 CPU。1. 把复杂计算从 GPU顶点着色器转移到 CPU原理CPU 计算一次的数据如 MVP 矩阵、常量变换无需让 GPU 每个顶点重复算典型场景❌ 错误做法在顶点着色器里计算模型矩阵×视图矩阵×投影矩阵每个顶点都算一次✅ 正确做法CPU 提前计算好 MVP 矩阵以uniform变量传入所有顶点共用 1 次计算结果。2. 避免在顶点着色器内做复杂数学运算禁用开方sqrt、三角函数sin/cos/tan、对数log、除法尽量用乘法替代如1.0/2.0提前算成0.5替代方案CPU 预计算结果以uniform传入或用查找表LUT采样。3. 简化光照计算顶点着色器中仅做基础漫反射Phong 光照的顶点版本复杂光照如 PBR、高光放到片元着色器或用光照贴图替代避免逐顶点计算多光源优先用 “光源数量上限 CPU 筛选”只传影响当前模型的光源。优化数据传输与存储减少 GPU 数据读取开销顶点数据位置、法线、纹理坐标需要从 CPU 传到 GPU数据量越大、格式越复杂传输 / 读取开销越高。1. 使用紧凑的顶点数据格式优先用低精度、匹配需求的数据类型表格场景推荐类型避免类型节省内存顶点位置屏幕空间vec2/halfvec3/float50%法线 / 纹理坐标half半精度float单精度50%顶点颜色uvec48 位vec4浮点75%注意需确认 GPU 支持half半精度浮点数移动端大部分支持。2. 合并顶点属性减少顶点缓冲对象 VBO 数量把多个顶点属性如位置、法线、纹理坐标打包到同一个 VBO而非多个 VBO原理减少 GPU 切换 VBO 的开销提升数据读取的连续性。3. 启用顶点缓冲对象VBO/ 顶点数组对象VAO禁用每次绘制都重新上传顶点数据启用将顶点数据缓存到 GPU 显存VBO并通过 VAO 记录顶点格式仅上传一次重复使用。利用 GPU 特性减少指令数1. 避免分支 / 循环新手重点顶点着色器的分支if/else、循环for/while会打断 GPU 的并行执行导致性能下降替代方案用数学运算替代分支或 CPU 提前处理分支逻辑。2. 复用计算结果减少重复指令对多次使用的计算结果用临时变量存储避免重复计算。3. 使用内置函数 / 硬件加速指令GLSL 内置函数如normalize、dot、cross是 GPU 硬件加速的比手动实现更高效示例用normalize(a_Normal)替代手动计算a_Normal / length(a_Normal)。进阶优化模型层面简化模型顶点数对远距离模型用低模LOD 技术减少顶点总数从根源降低顶点着色器的执行次数顶点缓存Vertex Cache优化优化模型的顶点索引顺序让 GPU 能复用已处理的顶点数据3D 建模软件可导出优化后的索引实例化渲染Instanced Rendering绘制大量重复模型如树木、敌人时用glDrawArraysInstanced仅上传 1 份顶点数据通过instancesID区分不同实例减少数据传输和顶点着色器重复执行。总结顶点着色器是逐顶点执行的可编程阶段核心任务是完成顶点坐标的空间变换输出gl_PositionMVP 矩阵是顶点着色器实现 3D 变换的关键由 CPU 计算后以 uniform 变量传入顶点着色器的输入in是顶点属性输出out会传递给片元着色器是连接 3D 数据和 2D 渲染的核心环节。