在 OpenGL ES 中缓存三角函数是否有意义?

Does it make sense to cache trigonometric functions in OpenGL ES?

我知道在 GPU 之前做图形时三角函数缓存非常流行,但是使用一维纹理查找 table 从内部的预计算值计算 sin/cos 是否有意义OpenGL ES 着色器?如果不需要超高精度,是否可以节省时间?

这是 "it depends" 问题之一。

高精度任意 sin()cos() 特别是往往是昂贵的操作,因为它们通常不直接用于图形中,并且要获得完整的精度往往需要一定程度的细化迭代。所以就个人而言,如果纹理可以更快,我不会感到惊讶。

一些注意事项。首先,余弦用于照明的大多数用途是基于单位长度向量之间的角度,因此您不需要任意 cos() - 只需使用 dot() GPU very 效率为.

其次,值得注意的是,如果您以 mediump 精度进行计算,某些实现(尤其是移动 GPU)可能已经能够为您提供更快、更不准确的结果。这将减少以下逻辑中 sin()cos() 的任何基准成本。

剩下的问题实际上是 sin() 的成本是否优于 texture() 的成本,这可能在很大程度上取决于着色器程序的其余部分,并且目标 GPU 中的功能单元平衡。

  • 如果由于其他不相关的纹理操作,您的着色器已经由纹理性能主导,那么即使单个 texture() 调用单独比 sin() 快,添加更多纹理也会使其变慢。 =37=]
  • 如果您的着色器主要由算术(或执行 sin() 调用的任何单元)控制,则可以通过将一些负载从它转移到纹理路径来提高性能。

是的,它确实有意义,您应该缓存它。

首先,我阅读了 solidpixel 的回答(大部分是正确的),但我会与他有所不同。

所以,简而言之:你不应该在 运行 时间(特别是在 android - 如果那是你的 GLES 情况)计算 sin() 或 cos() 因为你不知道你的着色器将 运行 放在哪个 GPU 上,而且很多着色器永远不会优化它。除了使用纹理采样之外,还有更好的方法来缓存它。

如果您正在处理线性代数(大多数着色程序是简单的矢量方程求解器),那么: 你应该像他说的那样使用点积来代替 cos()sin() 的叉积。

但是,如果这不是你的情况并且你确实需要调用 sin 和 cos,那么我建议你一定要缓存它,这里有 2 种我喜欢的最佳方式:

  • texture() 确实非常昂贵,但您可以使用 textureGrad(),这是一种比常规 texture() 更快的纹理查找,因为它跳过了所有过滤,尽管它更受限制,但它是非常适合缓存 sin 和 cos。
  • 另一个更好的解决方案是根本不使用纹理:改为使用统一缓冲区,它基本上是一个浮点数组(就像纹理)但是对 GPU 是显式的,所以你不需要通过采样(这在手机上特别贵)。
  • 统一缓冲区有大小限制,因此如果您需要更精确地处理不同的角度值,您可以使用 SSBO(着色器缓冲区存储对象),它类似于统一缓冲区但可以存储更多数据。