渲染管线
一、整体架构:从3D数据到屏幕的"旅程"
WebGL 的渲染管线(Render Pipeline)是将 3D 场景中的几何数据和像素信息转换为 2D 屏幕图像的一系列有序处理阶段。基于 OpenGL ES 2.0/3.0 标准,采用流水线架构,各阶段依次处理数据,部分阶段可以通过着色器(Shader)自定义逻辑。
数据流向:CPU 准备数据 → 顶点着色器变换 → 图元装配与裁剪 → 光栅化生成像素 → 片元着色器计算颜色 → 帧缓冲处理显示。
1. 顶点数据输入(CPU)
作用:将应用程序定义的顶点数据(如位置、颜色、法线、纹理坐标等)传递给 GPU。
数据来源:顶点数据通常存储在缓冲区对象(Buffer Object)中(通过
gl.createBuffer创建),并通过gl.vertexAttribPointer绑定到顶点属性(Vertex Attributes)。关键操作:
应用程序通过 JavaScript 定义顶点数组(如
Float32Array),并将其上传到 GPU 内存。每个顶点属性(如位置
aPosition、颜色aColor)对应缓冲区中的一段数据,通过步长(Stride)和偏移(Offset)描述其布局。
2. 顶点着色器
作用:对每个顶点进行独立计算,完成坐标变换、颜色计算等自定义逻辑。
核心功能:
坐标变换:将顶点从模型空间(Model Space)转换到裁剪空间(Clip Space),通过模型-视图-投影矩阵(MVP Matrix)实现。公式:
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(aPosition, 1.0);自定义计算:可计算顶点颜色、法线、纹理坐标,或传递数据到片元着色器(如通过
varying变量)。
特性:
顶点着色器是 WebGL 渲染管线中必须的阶段。
每个顶点独立处理,适合并行计算(GPU 擅长)。
3. 图元装配
作用:将顶点数据组合成图元(Primitive)(如点、线、三角形),并准备进行光栅化。
关键操作:
根据绘制命令(如
gl.drawArrays(gl.TRIANGLES, ...))确定图元类型。执行裁剪(Clipping):将超出视锥体(View Frustum)的图元部分切除,仅保留可见区域。
执行透视除法(Perspective Division):将裁剪空间坐标转换为标准化设备坐标(NDC,范围 [-1, 1]),得到屏幕空间坐标。
4. 光栅化
作用:将图元(如三角形)转换为片元(Fragment)(即屏幕上的像素候选点),并计算每个片元的属性(如颜色、深度)。
关键操作:
确定覆盖区域:计算图元在屏幕上的覆盖范围,生成对应的片元。
属性插值:根据顶点属性(如颜色、纹理坐标)在三角形内的位置,通过重心坐标插值计算每个片元的属性值(如
varying变量)。深度计算:计算每个片元的深度值(Z 值),用于后续深度测试。
5. 片元着色器
作用:对每个片元进行计算,确定其最终颜色(或丢弃该片元)。
核心功能:
颜色计算:基于插值的属性(如纹理坐标)采样纹理(
texture2D),或结合光照模型(如 Phong)计算颜色。丢弃片元:通过
discard语句跳过某些片元(如透明物体的不可见部分)。
特性:
片元着色器也是 WebGL 渲染管线中必须的阶段。
每个片元独立处理,但需注意相邻片元的计算可能影响性能(避免分支和复杂循环)。
6. 片元测试与写入
作用:对片元进行一系列测试,决定是否将其写入帧缓冲(Frame Buffer)。
常见测试:
深度测试(Depth Test):比较当前片元的深度值与深度缓冲区中对应位置的值,仅当当前片元更近(深度值更小)时保留(需启用
gl.enable(gl.DEPTH_TEST))。模板测试(Stencil Test):根据模板缓冲区的掩码和比较规则决定是否保留片元(需启用
gl.enable(gl.STENCIL_TEST))。混合(Blending):若启用(
gl.enable(gl.BLEND)),将当前片元颜色与颜色缓冲区中的原有颜色按混合因子(如gl.blendFunc)混合(用于透明效果)。
7. 帧缓冲写入(Frame Buffer Write)
作用:将通过所有测试的片元颜色、深度、模板等信息写入帧缓冲。
帧缓冲类型:
默认帧缓冲:对应屏幕的显示缓冲区(由浏览器创建)。
离屏帧缓冲(FBO, Frame Buffer Object):开发者创建的离屏缓冲区,用于离屏渲染(如纹理生成、后期处理)。
核心阶段作用:
顶点着色器:处理坐标变换和顶点属性传递;
片元着色器:处理像素级颜色计算;
光栅化:连接几何图形与像素的桥梁;
深度测试 / 混合:解决遮挡和透明效果。