通过最小化着色器/状态更改来优化 WebGL 性能的指南
我正在尝试了解 WebGL 在渲染由 100K 个三角形组成的大型室内场景方面的实用性。这些三角形分布在很多物体上,场景中也有很多材质。另一方面,没有活动部件。而且材质往往相当简单,主要基于纹理贴图。有很多纹理贴图共享..例如场景中的所有椅子将共享一个公共贴图。还有一些多重纹理 - 材质中最多叠加三个纹理。
我做了一些实验和阅读,发现在渲染过程中频繁切换材质会减慢速度。例如,假设每次显示一个对象时都会设置一个新材质,则具有 200K 个三角形的场景将具有显着的性能差异,具体取决于是否有 10 个或 1000 个对象。
因此,如果性能很重要,则场景应该按材质排序,以尽量减少材质切换。我正在寻找的是关于如何考虑各种状态更改的开销的指南,以及如何获得最大的收益。例如,
gl.useProgram()
、gl.uniformMatrix4fv()
、gl.drawElements()
的相对性能成本是多少>- 我应该尝试编写 ubershaders 以最小化着色器切换吗?
- 我是否应该尝试聚合几何图形以尽量减少
gl.drawElements()
调用的数量
我意识到里程可能会因浏览器、操作系统和图形硬件而异。我也不是在寻求英雄的措施。只是那些已经有一些快速制作场景经验的人提供的一些指导。我要补充一点,虽然我过去在固定管道 OpenGL 编程方面有一些经验,但我对 WebGL/OpenGL ES 2.0 的处理方式相当陌生。
I'm trying to get an idea of the practicality of WebGL for rendering large interior scenes, consisting of 100K's of triangles. These triangles are distributed over many objects, and there are many materials in the scene. On the other hand, there are no moving parts. And the materials tend to be fairly simple, mostly based on texture maps. There is a lot of texture map sharing .. for example all the chairs in scene will share a common map. There is also some multitexturing - up to three textures overlaid in a material.
I've been doing a little experimentation and reading, and gather that frequently switching materials during a rendering pass will slow things down. For example, a scene with 200K triangles will have significant performance differences, depending on whether there are 10 or 1000 objects, assuming that each time an object is displayed a new material is set up.
So it seems that if performance is important the scene should be sorted by materials so as to minimize material switching. What I'm looking for is guidelines on how to think of the overhead of various state changes, and where do I get the biggest bang for the buck. For example,
- what are the relative performance costs of, say,
gl.useProgram()
,gl.uniformMatrix4fv()
,gl.drawElements()
- should I try to write ubershaders to minimize shader switching?
- should I try to aggregate geometry to minimize the number of
gl.drawElements()
calls
I realize that mileage may vary depending on browser, OS, and graphics hardware. And I'm also not looking for heroic measures. Just some guidelines from people who have already had some experience in making scenes fast. I'll add that while I've had some experience with fixed-pipeline OpenGL programming in the past, I'm rather new to the WebGL/OpenGL ES 2.0 way of doing things.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您读过批量、批量、批量吗?诚然,它关注的是 directX,但其推理在较小程度上也适用于 Open/WebGL:每个 API 调用都会对 CPU 产生显着的开销。建议使用所有 API 选项来共享纹理、使用实例化(如果可用)、编写复杂的着色器以避免多次绘制调用。因此,如果您可以在一次调用中将整个房子绘制为单个网格,那么这将比每个房间 1000 次调用要好。建议编写 ubershaders,但主要是因为它可以允许您删除绘制调用,而不是因为 GPU 状态切换成本高昂。
这假设了最新的硬件。对于低端平台(iPad?)或英特尔 GMA 芯片,瓶颈将在其他地方(例如软件顶点处理)。
Have you read batch, batch, batch? Admittedly, it focuses on directX, but the reasoning applies to a lesser extent to Open/WebGL also: Each API call has significant overhead on the CPU. The advice is use all the API's options to share textures, use instancing (if available), write complex shaders to avoid many draw calls. So if you can draw the whole house as a single mesh in a single call, that would be better than 1000 calls for each room. Writing ubershaders is reccomended but mostly because it may allow you to remove draw calls, not because GPU state switching is expensive.
This assumes recent hardware. For low end platforms (iPad?) or Intel GMA chips, the bottlenecks will be elsewhere (like in software vertex processing).