在 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(着色器缓冲区存储对象),它类似于统一缓冲区但可以存储更多数据。
我知道在 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(着色器缓冲区存储对象),它类似于统一缓冲区但可以存储更多数据。