【发布时间】:2018-11-05 19:34:49
【问题描述】:
我正在使用 THREE 构建一个 WebGL 应用程序,并注意到 GPU 上出现了一些奇怪的时序。我目前没有可用的重现代码,但我想我会问这个问题,以防它是一个已知的浏览器怪癖或常见且可修复的东西。
场景设置
- 具有约 2,000,000 个多边形、136 个网格和 568 个 Object3D 实例的场景。
- 将 THREE.Composer 与 FXAA 和 Unreal Bloom 通道结合使用。
- 使用 THREE.OrbitControls。
- 仅当已知某些内容发生更改时才会渲染场景。例如,当用户拖动场景以使用控件移动相机或场景中的某些东西移动时,就会安排绘制。场景通常是静态的,因此我们尽量不要在这些情况下进行不必要的渲染。
问题
当场景是静态的(暂时未绘制)然后用户通过拖动更改相机位置时会出现此问题。一旦用户开始拖动,帧率就会非常不稳定——可能是 10-20 fps 或更低——持续几帧,然后平滑回到接近 60 的水平。当场景保持几秒钟然后再次拖动时,这种情况会一直发生。如果鼠标在初始卡顿后持续拖动,则帧速率保持平滑。这些帧没有呈现任何不同。
如果使用requestAnimationFrame 渲染每一帧,则不会发生这种卡顿,并且场景仍然很流畅。
这是仅在某些情况发生变化时才渲染场景时出现卡顿的性能分析器。您可以看到,在再次平滑之前出现卡顿的帧期间,GPU 花费了更多时间:
场景以 60 fps 渲染时的分析器:
有什么想法吗?为什么在拖动时突然发生这么多 GPU 工作?绘制是否会被其他渲染进程阻止?为什么在几秒钟没有渲染后会如此一致地发生?我使用最新版本的 Chrome 进行了分析,但 Firefox 中也存在口吃。
谢谢!
【问题讨论】:
-
我做过几个项目,我在不需要的时候跳过渲染,它总是在 60FPS 停止的地方重新开始,所以 Three.js 没有问题。你是如何暂停渲染的?你只是在
requestAnimationFrame循环中使用return吗?您是否要删除任何事件侦听器然后重新添加它们? -
我只在已知场景发生变化时使用
requestAnimationFrame安排绘制,因此无需在渲染函数中提前返回。如果在发生更改时已经安排了抽奖,则未安排另一场抽奖。这意味着当用户不与画布交互时,javascript 中根本没有发生任何事情。我没有尝试过让渲染循环提前返回,但我也可以尝试。 -
如果这是确切原因,我必须查看您的代码以查明,但我认为您的渲染循环中的一些简单的东西,例如:
if(!needsToRender){return null;}应该执行得很好,因为您没有添加/删除事件监听器。我理解完全阻止 JavaScript 在后台执行任何操作的愿望,但是调用一个每秒仅检查布尔值 60 次的函数是微不足道的。 -
我添加了与您提到的内容类似的内容,虽然这种情况发生的频率较低,但有时仍会出现奇怪的口吃。你说得对,添加一个空函数调用是非常轻量级的,但我在不理解 why 解决问题的情况下犹豫添加它(它似乎并没有完全解决)。这也不是页面上运行的唯一 javascript,所以如果可能的话,我宁愿不添加它。为什么有一个空的 requestAnimationFrame 调用总比没有好?当我有机会时,我会尝试制作一个重现案例,以便更容易展示问题。感谢您的帮助!
标签: javascript three.js webgl