计算游戏每秒的帧数

时间:2020-03-05 18:59:57  来源:igfitidea点击:

什么是计算游戏中每秒帧数的好算法?我想将其显示为屏幕角落的数字。如果仅查看渲染最后一帧所花费的时间,则数字变化太快。

如果答案更新了每一帧,并且在帧速率增加或者减少时收敛不相同,则奖励积分。

解决方案

回答

我们需要一个平滑的平均数,最简单的方法是获取当前答案(绘制最后一帧的时间)并将其与上一个答案合并。

// eg.
float smoothing = 0.9; // larger=more smoothing
measurement = (measurement * smoothing) + (current * (1.0-smoothing))

通过调整0.9 / 0.1的比率,我们可以更改"时间常数",即数字对变化的响应速度。赞成旧答案的较大部分给出较慢的平滑变化,赞成新答案的较大部分给出较快的变化值。显然,这两个因素必须加在一起!

回答

每次渲染屏幕时都要增加一个计数器,并在要测量帧率的某个时间间隔内清除该计数器。

IE。每3秒钟,获取计数器/ 3,然后清除计数器。

回答

将计数器设置为零。每次绘制一帧,计数器都会递增。每秒打印一次计数器。泡沫,冲洗,重复。如果我们想要额外的积分,请保持一个计数器,然后除以总秒数即可得出平均值。

回答

我们可以保留一个计数器,在渲染完每一帧后将其递增,然后在新的秒数时将计数器重置(将先前的值存储为渲染的帧的最后一秒)

回答

存储开始时间并在每个循环中增加一次帧计数器?每隔几秒钟,我们可以只打印framecount /(现在开始时间),然后重新初始化它们。

编辑:哎呀。双重忍者

回答

好吧,当然

frames / sec = 1 / (sec / frame)

但是,正如我们所指出的,渲染单个帧所需的时间有很多差异,并且从UI角度看,根本无法以帧速率更新fps值(除非该数目非常稳定)。

我们想要的可能是移动平均线或者某种装仓/重置计数器。

例如,我们可以维护一个队列数据结构,该结构保存最后30帧,60帧,100帧或者我们拥有的所有帧的渲染时间(我们甚至可以对其进行设计,以便在运行时调整限制)。要确定合适的fps近似值,我们可以从队列中所有渲染时间确定平均fps:

fps = # of rendering times in queue / total rendering time

完成渲染新帧后,我们将获得一个新的渲染时间,并为一个旧的渲染时间出队。或者,我们只能在渲染时间的总和超过某个预设值(例如1秒)时才出队。我们可以维护"最后fps值"和最后一次更新的时间戳,以便我们可以根据需要触发何时更新fps数字。尽管如果我们使用一致的格式移动平均值,则在每帧上打印"瞬时平均" fps可能没问题。

另一种方法是设置一个重置计数器。保持精确的(毫秒)时间戳,帧计数器和fps值。完成渲染框架后,增加计数器。当计数器达到预设限制(例如100帧)或者自时间戳记以来的时间已超过某个预设值(例如1秒)时,请计算fps:

fps = # frames / (current time - start time)

然后将计数器重置为0,并将时间戳设置为当前时间。

回答

这就是我在许多游戏中使用的。

#define MAXSAMPLES 100
int tickindex=0;
int ticksum=0;
int ticklist[MAXSAMPLES];

/* need to zero out the ticklist array before starting */
/* average will ramp up until the buffer is full */
/* returns average ticks per frame over the MAXSAMPLES last frames */

double CalcAverageTick(int newtick)
{
    ticksum-=ticklist[tickindex];  /* subtract value falling off */
    ticksum+=newtick;              /* add new value */
    ticklist[tickindex]=newtick;   /* save new value so it can be subtracted later */
    if(++tickindex==MAXSAMPLES)    /* inc buffer index */
        tickindex=0;

    /* return average */
    return((double)ticksum/MAXSAMPLES);
}

回答

在伪代码(类似于c ++)中,这两个是我在工业图像处理应用程序中使用的应用程序,这些应用程序必须处理来自一组外部触发相机的图像。 "帧速率"的变化具有不同的来源(皮带上的生产速度变慢或者变快),但问题是相同的。 (我假设我们有一个简单的timer.peek()调用,从应用程序启动或者上次调用以来,我们得到的像是msec的nr(nsec?)。

解决方案1:快速但不每帧更新

do while (1)
{
    ProcessImage(frame)
    if (frame.framenumber%poll_interval==0)
    {
        new_time=timer.peek()
        framerate=poll_interval/(new_time - last_time)
        last_time=new_time
    }
}

解决方案2:每帧更新一次,需要更多的内存和CPU

do while (1)
{
   ProcessImage(frame)
   new_time=timer.peek()
   delta=new_time - last_time
   last_time = new_time
   total_time += delta
   delta_history.push(delta)
   framerate= delta_history.length() / total_time
   while (delta_history.length() > avg_interval)
   {
      oldest_delta = delta_history.pop()
      total_time -= oldest_delta
   }
}

回答

好答案在这里。实施的方式取决于所需的功能。我更喜欢上面那个家伙自己的"时间=时间* 0.9 + last_frame * 0.1"的运行平均值。

但是我个人更倾向于将平均水平加权到新数据上,因为在游戏中,最难以压榨也是最受关注的就是SPIKES。因此,我将使用更像.7 \ .3的分割将使尖峰的显示速度更快(尽管其效果也会更快地从屏幕上掉落。如下所示)

如果我们专注于渲染时间,那么.9.1拆分效果很好,因为b / c往往更平滑。尽管对于游戏/ AI /物理峰值而言,更需要关注的是尖峰,因为尖峰通常会使游戏显得不稳定(假设我们不低于20 fps,这通常比低帧频更糟糕)

因此,我要做的也是添加如下内容:

#define ONE_OVER_FPS (1.0f/60.0f)
static float g_SpikeGuardBreakpoint = 3.0f * ONE_OVER_FPS;
if(time > g_SpikeGuardBreakpoint)
    DoInternalBreakpoint()

(以我们认为不可接受的峰值幅度填充3.0f)
这样一来,我们就可以找到FPS问题,并在发生问题的帧结束时解决它们。