time - 着色器时间统一 -clock_gettime 被截断

标签 time glsl clock mantissa

使用clock_gettime将此函数获取时间作为 double :

// return current time in milliseconds
static double time_get_ms(void)
{
    struct timespec res;

#ifdef ANDROID
    clock_gettime(CLOCK_REALTIME_HR, &res);
#else
    clock_gettime(CLOCK_REALTIME, &res);
#endif
    return (double)(1000.0*res.tv_sec + res.tv_nsec/1e6);
}

将其发送到着色器需要转换为浮点型。尾数溢出并在前往着色器的途中被截断。

示例:

作为 double = 1330579093642.441895

作为 float = 1330579111936.000000

由于截断,浮点值在很长一段时间内停留在单个数字。

似乎即使 res.tv_sec 中的秒值对于 float 来说也太大了,它在通往 GPU 的途中也会被截断。

尝试测量应用程序启动以来的时间,但我很快就遇到了同样的问题。

那么将运行时间值输入着色器的最佳方法是什么? Linux 世界中跨平台的东西(例如 IOS、Android、Linux)。

最佳答案

尾数中的 32 位浮点精度已用完。着色器将无法更好地处理这种精度不足的问题,因为除非您使用支持 double 的 GL 4.x,否则着色器也只能处理 32 位 float 。

如果您运行应用程序的时间太长,以至于毫秒溢出浮点精度(这将需要 ~107 毫秒,或大约 2.7 小时左右),那么您必须找到一种方法优雅地处理这种情况。具体如何执行取决于您的着色器使用此时间值的具体用途。

大多数着色器不需要以毫秒为单位的实际时间。绝大多数需要时间(或类似时间)的着色器进程都是循环的。在这种情况下,您可以简单地向它们传递一个值,说明它们在特定周期中的进度。该值在[0, 1)范围内,循环开始时为0,中间为0.5,结束时为1。

如果您的着色器进程无法参数化,如果它确实需要绝对时间,那么您的下一个赌注是传递两个浮点参数。基本上,您需要保留溢出位。这将使涉及 GPU 时间的所有数学运算变得复杂,因为您必须使用两个值并知道如何将它们嫁接到一起来进行时间更新。同样,如何执行此操作取决于您在着色器中执行的操作。

或者,如果您的硬件支持 GL 3.x+,您也可以以 32 位无符号整数发送时间。这将为您提供更多的精度,因此可以更长时间地解决问题。如果您发送的时间为十分之一毫秒,那么您应该能够在溢出之前获得大约 5 天左右的时间。同样,这将使所有 GPU 数学变得复杂,因为您不能只进行整数到浮点的转换。

关于time - 着色器时间统一 -clock_gettime 被截断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9511233/

相关文章:

c++ - 如何在 C++ 中以毫秒为单位输出时间?

python - Pygame - 使用 Time 打印秒数

java - 为什么 toMillis() 函数在 Java 中返回 -1

ruby-on-rails - time_select 表单助手将新时间对象解释为 UTC 而不是配置的时区

java - 字符串到 HH :mm:ss time and finding the difference between 2 times

java - Joda Time 资源未找到错误

android - GLSL ES 3.0 - 在顶点和 fragment 着色器中统一,以及最大顶点/fragment 统一向量

android - 如何在 Android 上加速着色器加载/编译