推荐:使用 NSDT场景设计器 快速搭建 3D场景。

随着使用 WebGL 构建的体验不断涌现,以及 WebVR/AR 领域的所有改进,拥有高效的调试工具变得至关重要。 无论你是刚刚起步还是已经是使用 WebGL 开发 3D 应用程序的经验丰富的开发人员,都可能知道工具对于生产力的重要性。

在寻找此类工具时,你可能会看到 Patrick Cozzi 的博客文章,其中重点介绍了最常见的工具。 遗憾的是,由于缺少 WebGL2 功能或扩展,例如绘制缓冲区、3D 纹理等,其中许多工具不再与你的项目兼容。

作为 BabylonJS 的核心贡献者,在引擎级别工作,我每天都需要查看整个框架的创建过程,包括来自 WebGL 状态(深度、模板、混合等)的所有可用信息以及 命令列表及其参数。 为了优化引擎,我还需要有关内存、绘制调用和图元的信息和统计信息。 这些愿望是我开发 SpectorJS 的一大动力。 由于我们热爱 WebGL 社区,我们决定将其作为一个开源项目,与所有现有的 WebGL 3D 引擎兼容。

在本教程结束时,你将能够轻松捕获和检查在你最喜欢的应用程序中呈现的任何 WebGL 帧。

1、安装SpectorJS

为了节省时间,该工具可直接作为浏览器扩展使用:ChromeFirefox ,后续将支持更多浏览器。

也可以将库嵌入你的应用程序或侧面加载扩展。 更多信息可以在 Github 上找到。

2、SpectorJS基本用法

安装后,现在可以使用 WebGL 导航到任何网站,例如 Babylon JS playground,你会注意到扩展图标在工具栏中变为红色。

这会突出显示页面中具有 3D 上下文的画布或其嵌入的 IFrame。 按工具栏按钮重新加载页面,图标变为绿色,因为 Spector 现在已准备好捕捉。 在刷新期间,Spector 会注入额外的调试代码,用于收集状态和命令信息以及其他统计信息。

注意:我们默认不启用它,以免干扰任何 WebGL 程序,除非明确要求。

单击此绿色按钮将显示一个弹出窗口,帮助你捕获帧。

按照屏幕上的说明单击红色圆圈将触发捕获。 如果选中了某个画布,你还可以在此菜单中逐帧暂停或播放渲染的画布。 捕获完成后,将显示一个结果面板,其中包含你可能需要的所有信息。

菜单底部有助于捕获页面加载期间在文档中出现的第一个画布上发生的情况。 你可以轻松选择要捕获的命令数量,以及指定是否要捕获瞬态上下文(在第一个画布中创建的上下文,即使它不是 DOM 的一部分)。

注意:有几个原因可能会阻止你捕获上下文,一个可能的主要原因是如果场景是完全静态的,则不会渲染任何内容。 如果发生这种情况,按下拍摄按钮后移动相机应该足以开始捕捉。
注意:由于收集信息的成本非常高,因此捕获可能需要很长时间,你可能需要按等待...几次,当浏览器通知你页面无响应时。 不幸的是,我们无法解决这个问题,因为捕获需要在你的代码执行期间同步发生。 如果没有同步捕获,你的其余代码将继续对外部事件做出反应,并对捕获产生潜在的副作用。

3、SpectorJS捕获视图

在屏幕的左侧显示了在创建框架期间发生的所有不同的视觉状态变化。 它们与目标帧缓冲区信息一起显示。 这有助于在故障排除会话期间快速了解框架的构建方式。 选择其中一张图片会自动选择与其关联的命令。 视觉捕获处理所有可能的可渲染输出,例如立方体纹理、3D 纹理、绘制缓冲区、渲染目标纹理、渲染缓冲区等。

中央面板是命令面板。 它显示在帧期间在捕获的上下文上执行的命令列表。 这些按时间顺序显示。 颜色代码用于突出显示问题并识别绘图调用:

  • 橙色背景:选定的命令。
  • 蓝色背景:绘制调用或清除命令。
  • 绿色命令名称:有效命令(将状态更改为新值)。
  • 橙色命令名称:冗余命令(意味着应用的值与当前的值相同,这对优化 WebGL 应用程序很有用)
  • 红色命令名称:弃用的 WebGL 命令。

选择一个命令会在右侧显示其所有详细信息,包括命令名称、参数和 JavaScript 调用堆栈。 如果选择了绘制调用,则该调用涉及的各种状态都是可用的。 这通常是一个相当长的信息列表,因为捕获包含状态、附件、程序、着色器、属性、VAO、制服、UBO、变换反馈及其附加属性的详尽列表。 在此面板中,还可以从程序信息中获取着色器源代码,方法是点击打开链接:

这将打开着色器代码的美化视图,有助于确保定义和代码本身符合预期:

注意:如果引擎出现问题,某些信息可能为空。 例如,未绑定的纹理可能会导致采样器的统一信息为空。 这通常是一个有趣的警告,并且正在进行更多分析以帮助更好地突出此类用例。

每次捕获都可以使用一些其他视图。

  • 初始状态和结束状态

打开捕获后,顶部命令栏会包含指向捕获的初始和最终状态的链接。 这有助于查看捕获之前和结束时的上下文,例如,有助于处理帧之间发生的问题。

  • 上下文和框架信息

WebGL 应用程序中通常存在与画布或上下文设置相关的问题。 为确保当前设置正确,信息面板会显示所有可查询的信息。 这还包含有关捕获帧的统计信息,例如内存信息、每个命令的调用次数和绘制的图元信息。

  • 分享捕获

由于我们经常在项目上与他人协作或使用多个平台,因此能够保存和共享捕获至关重要。 为此,你只需导航到菜单中的“捕获”链接,所有会话的捕获都存储在该链接中。 单击软盘图标下载捕获的 JSON 文件。

要打开并查看此文件,请将其拖放到扩展弹出窗口或捕获列表专用区域。 此功能可以节省大量解决客户或跨平台问题的时间。

  • 如何比较捕获

由于比任何人都更需要它,因此必须在更换引擎后比较捕获。 目前正在开发完整的捕获比较,但与此同时,捕获至少可以放在浏览器的不同选项卡中,从而更容易检查差异。

选中弹出菜单中的框会强制下一个捕获在新选项卡中打开:

5、自定义数据

显示自定义信息是快速识别材质与其着色器之间或网格与其缓冲区之间关系的好方法。 通过将名为 __SPECTOR_Metadata 的特殊字段添加到任何 WebGLObject,可以将自定义数据添加到捕获中。 设置字段后,任何依赖此对象的命令都会在属性面板中显示相关元数据。

var cubeVerticesColorBuffer = gl.createBuffer();
cubeVerticesColorBuffer.__SPECTOR_Metadata = { 
	name: "cubeVerticesColorBuffer" 
};

这使自定义名称 cubeVerticesColorBuffer在使用缓冲区的捕获元数据中可见。

6、扩展控制

另一个有趣的特性是能够通过代码驱动扩展。 启用扩展后,你可以从浏览器的开发工具甚至你的代码中调用spector的以下 API:

  • captureNextFrame(obj: HTMLCanvasElement | RenderingContext) :调用以开始捕获特定画布或上下文的下一帧。
  • startCapture(obj: HTMLCanvasElement | RenderingContext, commandCount: number) :在特定画布或上下文上开始捕获。 一旦达到指定为参数的命令数或 10 秒后,捕获将停止。
  • stopCapture(): ICapture : 停止当前捕获并以 JSON 格式返回结果。 如果已显示 UI,则显示结果。 如果捕获尚未完成或未找到任何命令,则返回 undefined。
  • setMarker(marker: string) :添加在捕获中显示的标记,帮助您分析结果。
  • clearMarker() :从任何后续调用的捕获中清除当前标记。

为此,窗口上提供了“spector”对象。

例如,这对于捕获阴影贴图的创建非常有帮助。 这也可用于根据用户交互触发捕获或在代码中设置标记以更好地分析捕获。

可以在你的代码中安全地引入以下示例:

if (spector) {
    spector.setMarker("Shadow map creation");
}
[your shadow creation code]
if (spector) {
    spector.clearMarker();
}

7、使用独立版本的SpectorJS

如果你更喜欢在你自己的应用程序中使用这个库,你可以在 npm 上找到它。


原文链接:Debugging WebGL with SpectorJS

BimAnt翻译整理,转载请标明出处