计算游戏每秒的帧数
什么是计算游戏中每秒帧数的好算法?我想将其显示为屏幕角落的数字。如果仅查看渲染最后一帧所花费的时间,则数字变化太快。
如果答案更新了每一帧,并且在帧速率增加或者减少时收敛不相同,则奖励积分。
解决方案
回答
我们需要一个平滑的平均数,最简单的方法是获取当前答案(绘制最后一帧的时间)并将其与上一个答案合并。
// 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问题,并在发生问题的帧结束时解决它们。