当前位置:  开发笔记 > 人工智能 > 正文

计算游戏中的每秒帧数

如何解决《计算游戏中的每秒帧数》经验,为你挑选了6个好方法。

什么是计算游戏中每秒帧数的好算法?我想将它显示为屏幕一角的数字.如果我只看一下渲染最后一帧所花费的时间,那么数字变化太快了.

如果您的答案更新每一帧,并且在帧速率增加而不是减少时不会收敛,则奖励积分.



1> Martin Becke..:

您需要平滑的平均值,最简单的方法是获取当前答案(绘制最后一帧的时间)并将其与之前的答案相结合.

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

通过调整0.9/0.1比率,您可以更改"时间常数" - 即数字响应变化的速度.支持旧答案的较大部分给出了较慢的平滑变化,有利于新答案的很大一部分提供了更快的变化值.显然这两个因素必须加到一个!


然后为了万无一失,你可能想要像float weightRatio = 0.1; 和时间=时间*(1.0 - weightRatio)+ last_frame*weightRatio
@Petrucio:`last_frame`并不意味着(或至少*不应该*意味着)前一帧的持续时间; 它应该表示您为最后一帧计算的"时间"的值.这样,*将包括所有*前一帧,最近的帧加权最多.
原则上听起来不错并且很简单,但是实际上这种方法的平滑性几乎没有引起注意。不好。

2> KPexEA..:

这是我在很多游戏中使用的.

#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);
}


这是简单的移动平均线(SMA)

3> Wedge..:

嗯,当然

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并将时间戳设置为当前时间.



4> apandit..:

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

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



5> Peter Jankul..:

至少有两种方法可以做到:


第一个是我之前提到的其他人.我认为这是最简单和首选的方式.你只是要跟踪

cn:计算你渲染了多少帧

time_start:自你开始计算以来的时间

time_now:当前时间

在这种情况下计算fps就像评估这个公式一样简单:

FPS = cn /(time_now - time_start).


那么有一天你可能想要使用超酷的方式:

假设你有'i'帧需要考虑.我将使用这种表示法:f [0],f [1],...,f [i-1]来描述渲染帧0,帧1,...,帧(i-1)所需的时间) 分别.

Example where i = 3

|f[0]      |f[1]         |f[2]   |
+----------+-------------+-------+------> time

然后,在i帧之后的fps的数学定义将是

(1) fps[i]   = i     / (f[0] + ... + f[i-1])

和相同的公式,但只考虑i-1帧.

(2) fps[i-1] = (i-1) / (f[0] + ... + f[i-2]) 

现在的诀窍是修改公式(1)的右侧,使其包含公式(2)的右侧,并将其替换为左侧.

就像这样(如果你把它写在纸上,你应该更清楚地看到它):

fps[i] = i / (f[0] + ... + f[i-1])
       = i / ((f[0] + ... + f[i-2]) + f[i-1])
       = (i/(i-1)) / ((f[0] + ... + f[i-2])/(i-1) + f[i-1]/(i-1))
       = (i/(i-1)) / (1/fps[i-1] + f[i-1]/(i-1))
       = ...
       = (i*fps[i-1]) / (f[i-1] * fps[i-1] + i - 1)

所以根据这个公式(虽然我的数学推导技巧有点生疏),要计算新fps,你需要知道前一帧的fps,渲染最后一帧所用的持续时间以及你的帧数.渲染.



6> Petrucio..:

这对大多数人来说可能有点过头了,这就是我实施它时没有发布的原因.但它非常强大和灵活.

它存储具有最后帧时间的队列,因此它可以比仅考虑最后一帧更准确地计算平均FPS值.

它还允许你忽略一个框架,如果你正在做一些你知道会人为地搞砸那个框架时间的东西.

它还允许您在运行时更改要在队列中存储的帧数,因此您可以即时测试它对您来说最有价值.

// Number of past frames to use for FPS smooth calculation - because 
// Unity's smoothedDeltaTime, well - it kinda sucks
private int frameTimesSize = 60;
// A Queue is the perfect data structure for the smoothed FPS task;
// new values in, old values out
private Queue frameTimes;
// Not really needed, but used for faster updating then processing 
// the entire queue every frame
private float __frameTimesSum = 0;
// Flag to ignore the next frame when performing a heavy one-time operation 
// (like changing resolution)
private bool _fpsIgnoreNextFrame = false;

//=============================================================================
// Call this after doing a heavy operation that will screw up with FPS calculation
void FPSIgnoreNextFrame() {
    this._fpsIgnoreNextFrame = true;
}

//=============================================================================
// Smoothed FPS counter updating
void Update()
{
    if (this._fpsIgnoreNextFrame) {
        this._fpsIgnoreNextFrame = false;
        return;
    }

    // While looping here allows the frameTimesSize member to be changed dinamically
    while (this.frameTimes.Count >= this.frameTimesSize) {
        this.__frameTimesSum -= this.frameTimes.Dequeue();
    }
    while (this.frameTimes.Count < this.frameTimesSize) {
        this.__frameTimesSum += Time.deltaTime;
        this.frameTimes.Enqueue(Time.deltaTime);
    }
}

//=============================================================================
// Public function to get smoothed FPS values
public int GetSmoothedFPS() {
    return (int)(this.frameTimesSize / this.__frameTimesSum * Time.timeScale);
}

推荐阅读
谢谢巷议
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有