WebGL图形编程实战【6】:性能优化 × 调试工具与技巧精讲
调试工具
NVIDIA Nsight Systems
NVIDIA Nsight Systems 这个工具帮助开发者深入了解应用程序在CPU、GPU 和网络通信等各个层面的运行情况,从而有效地识别性能瓶颈并进行优化
WebGL-Inspector
插件的地址在这:WebGL-Inspector chrome插件
但是在这里已经无法下载,在chrome商店里面没有,在其GitHub仓库 WebGL-Inspector 也没有找到。
然后在 百度网盘 找到一个下载地址。下载下来的crx扩展文件直接拖拽安装的时候报错了,这时可以将crx改为zip压缩文件。然后再解压,然后在chrome://extensions/里面找到刚刚解压的目录,点击加载已解压扩展程序安装即可。
调试说明:可以用这个水族馆或者拿一个webgl写的案例来试一下。打开目标网页之后,点击刚才安装的插件,如果没有弹出下面的弹框,再点击右上角绿色的UI图标就会弹出这个框了。
WebGL-Inspector 是一个用于调试和分析 WebGL 应用程序的浏览器插件,它的调试工具可以帮助开发者深入理解 WebGL 渲染管线的运行状态、资源使用情况和性能表现。以下是各个调试工具的作用和含义:
1. Trace(调用追踪)
- 作用:记录 WebGL API 的调用历史。
- 功能:
- 按时间顺序显示所有 WebGL 函数调用(如
gl.drawElements
,gl.bindBuffer
等)。 - 可以查看调用参数、返回值以及上下文状态的变更。
- 支持跳转到代码触发位置(若浏览器支持)。
- 按时间顺序显示所有 WebGL 函数调用(如
- 用途:
- 调试渲染错误时,定位具体的 WebGL 调用步骤。
- 检查冗余的 API 调用(如重复绑定纹理或缓冲区)。
- 分析代码逻辑是否符合预期。
2. TimeLine(时间线)
- 作用:可视化 WebGL 渲染性能。
- 功能:
- 显示每一帧的渲染时间、资源加载时间、GPU 耗时等。
- 标注关键事件(如
drawCall
、texture upload
等)。 - 支持逐帧分析,观察性能波动。
- 用途:
- 定位性能瓶颈(如过多的绘制调用或过大的纹理上传)。
- 优化帧率(FPS),确保渲染流畅性。
3. State(状态查看器)
- 作用:实时监控 WebGL 上下文的状态参数。
- 功能:
- 显示当前启用的 WebGL 状态(如
BLEND
、DEPTH_TEST
、CULL_FACE
等)。 - 查看状态参数(如混合函数
blendFunc
、深度测试阈值depthRange
等)。 - 对比不同时刻的状态变化。
- 显示当前启用的 WebGL 状态(如
- 用途:
- 调试渲染错误(如因状态未正确设置导致的显示异常)。
- 确认渲染管线配置是否符合预期(例如混合模式或深度测试是否开启)。
4. Texture(纹理查看器)
- 作用:管理当前 WebGL 上下文中的所有纹理。
- 功能:
- 列出所有已创建的纹理(包括尺寸、格式、过滤模式等元数据)。
- 预览纹理内容(支持放大/缩小查看像素细节)。
- 分析纹理内存占用。
- 用途:
- 检查纹理是否正确加载(如 UV 翻转、格式错误)。
- 优化纹理内存(如发现未销毁的冗余纹理)。
- 调试纹理采样问题(如过滤模式或 MIPMAP 配置错误)。
5. Buffers(缓冲区查看器)
- 作用:管理顶点缓冲区(VBO)、索引缓冲区(IBO)等。
- 功能:
- 显示缓冲区类型(
ARRAY_BUFFER
、ELEMENT_ARRAY_BUFFER
等)、大小和使用次数。 - 查看缓冲区数据的原始内容(如顶点坐标、颜色、UV 等)。
- 检查顶点属性指针(
vertexAttribPointer
)的配置。
- 显示缓冲区类型(
- 用途:
- 确认顶点数据是否正确上传。
- 调试因缓冲区绑定错误导致的渲染问题(如模型缺失或错乱)。
- 优化内存使用(如复用缓冲区或删除无效缓冲区)。
6. Programs(着色器程序查看器)
- 作用:管理 WebGL 着色器程序(Shader Program)。
- 功能:
- 列出所有已编译的着色器程序及其关联的顶点/片段着色器。
- 显示着色器源码、编译日志和错误信息。
- 查看 Uniform 和 Attribute 变量的值及类型。
- 支持编辑并重新编译着色器(部分插件支持热重载)。
- 用途:
- 调试着色器语法错误或逻辑错误。
- 检查 Uniform 变量是否传递正确(如矩阵或光照参数)。
- 优化着色器性能(如减少复杂计算或冗余变量)。
WebGL lint
WebGL lint 是一个脚本,您可以将其放入 WebGL 项目中,以检查常见的 WebGL 错误。
可以直接通过script标签引入或者通过import引入
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js" crossorigin></script>;import 'https://greggman.github.io/webgl-lint/webgl-lint.js';
就像这样,引入了webGL-lint之后我不小心将draw放在了设置着色器变量之前调用了,这个时候就会报错:uniforms "proj" have not been set
类型化数组
提升webGL效率
数据方面(数据组织)
绘制一个带有颜色的三角形,我们通常需要定义两个数组,然后再读取数据传到着色器代码当中。
- 顶点坐标xyz数组
- 颜色数组
但是在CPU和GPU在读写数据的时候,会消耗大量的时间,所以尽量减少数据的读写次数,尽量减少数据在CPU和GPU之间的传输。所以在前面我们通常在数据融合在同一个数组当中,再通过vertexAttribPointer去取偏移量。
webGL.vertexAttribPointer(aPsotion, 4, webGL.FLOAT, false, 8 * 4, 0);
webGL.vertexAttribPointer(aColor, 4, webGL.FLOAT, false, 8 * 4, 4 * 4);
绘制方面(可视化)
核心在于drawArray和drawElements(调用的次数越少、性能越高)
退化三角形:表面上看起来是在绘制三角形,但是当webGL正要绘制的时候发现提供的顶点无法绘制,webGL会检测并且删除该三角形
不同的绘制方法消耗的性能
在webGL当中绘制平面都是基于三角形来绘制的,现在假设需要绘制8个三角形,然后有三个绘制三角形的API和两个绘制方法。其中顶点坐标用Float32Array类型,index数用Uint16Array类型。
- Float32Array需要4个字节,Uint16Array需要2个字节
drawArray | drawElements | |
---|---|---|
绘制三角形API | 不需要index索引数组 | 需要index索引数组 |
TRIANGLES 三角形 | 8个三角形,每个三角形需要3个顶点 24 * 4 * 4 = 384 | 只需要九个不同的顶点以及3*8个索引位置 9 * 4 * 4 + 24 * 2 = 192 |
TRIANGLE_FAN 三角扇 | 上面需要6个点、下面也是6个点外加中间连接的两个点 (6 + 6 + 2) * 4 * 4 = 224 | 同样的需要九个顶点但是只需要14个索引位置 9 * 4 * 4 + 14 * 2 = 172 |
TRIANGLE_STRIP 三角带 | 同上 | 同上 |
总结:这是一个只包含8个三角形的小网格,而且只考虑了顶点位置,所以需要的内存相对来说还算小。
如果面对的是一个很的网格,而且还需要包括法线和纹理坐标,则使用drawElements()方法+TRIANGLE_STRIP图元的组合可以节省更多的内存。重要的是,不要毫无必要地浪费内存,但是从性能角度来看,内存并不是唯一重要的因素。从性能角度来看,三角形绘制的顺序以及项点数据的组织形式也是很重要的因素。