การคำนวณเฟรมต่อวินาทีในเกม


110

อัลกอริทึมที่ดีในการคำนวณเฟรมต่อวินาทีในเกมคืออะไร? ฉันต้องการแสดงเป็นตัวเลขที่มุมของหน้าจอ ถ้าฉันดูว่าใช้เวลานานแค่ไหนในการแสดงเฟรมสุดท้ายตัวเลขจะเปลี่ยนเร็วเกินไป

คะแนนโบนัสหากคำตอบของคุณอัปเดตแต่ละเฟรมและไม่บรรจบกันแตกต่างกันเมื่ออัตราเฟรมเพิ่มขึ้นเทียบกับการลดลง

คำตอบ:


100

คุณต้องมีค่าเฉลี่ยที่เรียบวิธีที่ง่ายที่สุดคือใช้คำตอบปัจจุบัน (เวลาในการวาดเฟรมสุดท้าย) และรวมเข้ากับคำตอบก่อนหน้า

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

ด้วยการปรับอัตราส่วน 0.9 / 0.1 คุณสามารถเปลี่ยน 'ค่าคงที่ของเวลา' - นั่นคือความเร็วที่ตัวเลขตอบสนองต่อการเปลี่ยนแปลง เศษส่วนที่ใหญ่กว่าสำหรับคำตอบเก่าจะให้การเปลี่ยนแปลงที่ราบรื่นกว่าช้ากว่าเศษส่วนขนาดใหญ่ที่เป็นประโยชน์กับคำตอบใหม่จะให้ค่าที่เปลี่ยนแปลงเร็วกว่า เห็นได้ชัดว่าปัจจัยทั้งสองต้องรวมกัน!


14
จากนั้นเพื่อความโง่เขลาและเป็นระเบียบเรียบร้อยคุณอาจต้องการอะไรเช่น float weightRatio = 0.1; และเวลา = เวลา * (1.0 - weightRatio) + last_frame * weightRatio
korona

2
โดยหลักการแล้วฟังดูดีและเรียบง่าย แต่ในความเป็นจริงแล้วการปรับแนวทางนี้ให้ราบรื่นแทบจะไม่สามารถสังเกตเห็นได้ ไม่ดี.
Petrucio

1
@Petrucio หากการปรับให้เรียบต่ำเกินไปเพียงแค่หมุนค่าคงที่ของเวลา (weightRatio = 0.05, 0.02, 0.01 ... )
John Dvorak

8
@Petrucio: last_frameไม่ได้หมายถึง (หรืออย่างน้อยก็ไม่ควรหมายถึง) ระยะเวลาของเฟรมก่อนหน้า ควรหมายถึงค่าtimeที่คุณคำนวณสำหรับเฟรมสุดท้าย ด้วยวิธีนี้เฟรมก่อนหน้าทั้งหมดจะรวมเข้าด้วยกันโดยเฟรมล่าสุดจะมีน้ำหนักมากที่สุด
j_random_hacker

1
ชื่อตัวแปร "last_frame" ทำให้เข้าใจผิด "current_frame" จะมีความหมายมากกว่านี้ สิ่งสำคัญคือต้องทราบว่าตัวแปร "เวลา" ในตัวอย่างต้องเป็นแบบโกลบอล (เช่นเก็บค่าไว้ในทุกเฟรม) และควรเป็นตัวเลขทศนิยม ประกอบด้วยค่าเฉลี่ย / ค่ารวมและได้รับการอัปเดตในแต่ละเฟรม อัตราส่วนที่สูงขึ้นจะต้องใช้เวลานานขึ้นในการกำหนดตัวแปร "เวลา" ไปยังค่าหนึ่ง ๆ (หรือเบี่ยงเบนไปจากค่านั้น)
jox

52

นี่คือสิ่งที่ฉันได้ใช้ในหลาย ๆ เกม

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

ฉันชอบแนวทางนี้มาก มีเหตุผลใดที่ทำให้คุณตั้ง MAXSAMPLES เป็น 100
Zolomon

1
MAXSAMPLES นี่คือจำนวนของค่าที่ถูกเฉลี่ยเพื่อให้ได้ค่าสำหรับ fps
Cory Gross

8
เป็นค่าเฉลี่ยเคลื่อนที่อย่างง่าย (SMA)
KindDragon

สมบูรณ์แบบขอบคุณ! ฉันปรับแต่งมันในเกมของฉันเพื่อให้เห็บ func เป็นโมฆะและอีกฟังก์ชันหนึ่งจะส่งคืน FPS จากนั้นฉันสามารถเรียกใช้หนึ่งหลักในแต่ละเห็บแม้ว่าโค้ดการเรนเดอร์จะไม่แสดง FPS ก็ตาม
TheJosh

2
โปรดใช้โมดูโลไม่ใช่ if tickindex = (tickindex + 1) % MAXSAMPLES;
Felix K.

25

ดีแน่นอน

frames / sec = 1 / (sec / frame)

แต่อย่างที่คุณชี้ให้เห็นเวลาที่ใช้ในการเรนเดอร์เฟรมเดียวมีความผันแปรมากมายและจากมุมมองของ UI ที่อัปเดตค่า fps ที่อัตราเฟรมนั้นไม่สามารถใช้งานได้เลย (เว้นแต่ว่าตัวเลขจะคงที่มาก)

สิ่งที่คุณต้องการอาจเป็นค่าเฉลี่ยเคลื่อนที่หรือตัวนับ binning / การรีเซ็ตบางประเภท

ตัวอย่างเช่นคุณสามารถรักษาโครงสร้างข้อมูลคิวซึ่งจัดเวลาการแสดงผลสำหรับแต่ละเฟรม 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 และตั้งเวลาประทับเป็นเวลาปัจจุบัน


12

เพิ่มตัวนับทุกครั้งที่คุณแสดงผลหน้าจอและล้างตัวนับนั้นในช่วงเวลาหนึ่งที่คุณต้องการวัดอัตราเฟรม

ได้แก่ . ทุกๆ 3 วินาทีรับตัวนับ / 3 จากนั้นเคลียร์เคาน์เตอร์


+1 แม้ว่าสิ่งนี้จะให้ค่าใหม่เป็นช่วง ๆ เท่านั้น แต่ก็เข้าใจง่ายและไม่ต้องใช้อาร์เรย์หรือค่าที่คาดเดาและถูกต้องตามหลักวิทยาศาสตร์
opatut

10

มีอย่างน้อยสองวิธีในการดำเนินการ:


อย่างแรกคือสิ่งที่คนอื่นพูดถึงก่อนหน้าฉัน ฉันคิดว่ามันเป็นวิธีที่ง่ายที่สุดและเป็นที่ต้องการ คุณเพียงแค่ติดตาม

  • 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

จากนั้นนิยามทางคณิตศาสตร์ของ fps หลังจาก i เฟรมจะเป็น

(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 จากเฟรมก่อนหน้าระยะเวลาที่ใช้ในการแสดงผลเฟรมสุดท้ายและจำนวนเฟรมที่คุณ แสดงผล


1
+1 สำหรับวิธีที่สอง ฉันคิดว่ามันจะดีสำหรับ uber การคำนวณที่แม่นยำ: 3
zeboidlund

5

สิ่งนี้อาจจะมากเกินไปสำหรับคนส่วนใหญ่นั่นคือเหตุผลที่ฉันไม่ได้โพสต์เมื่อนำไปใช้ แต่มันแข็งแกร่งและยืดหยุ่นมาก

มันเก็บคิวด้วยเวลาเฟรมสุดท้ายดังนั้นจึงสามารถคำนวณค่า 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<float> 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);
}

2

คำตอบที่ดีที่นี่ วิธีการใช้งานนั้นขึ้นอยู่กับสิ่งที่คุณต้องการ ฉันชอบค่าเฉลี่ยที่รันด้วยตัวเอง "time = time * 0.9 + last_frame * 0.1" โดยคนข้างบน

อย่างไรก็ตามโดยส่วนตัวแล้วฉันชอบให้น้ำหนักค่าเฉลี่ยของฉันอย่างมากต่อข้อมูลใหม่ ๆ เพราะในเกมมันเป็น SPIKES ที่ยากที่สุดในการสควอชและเป็นที่สนใจของฉันมากที่สุด ดังนั้นฉันจะใช้บางอย่างมากขึ้นเช่นการแยก. 7 \ .3 จะทำให้ spike แสดงเร็วขึ้นมาก (แม้ว่าเอฟเฟกต์จะลดลงจากหน้าจอเร็วขึ้นด้วยก็ตาม ... ดูด้านล่าง)

หากโฟกัสของคุณอยู่ที่เวลา RENDERING การแยก. 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 เมื่อสิ้นสุดเฟรมที่เกิดขึ้น


ฉันชอบการtime = time * 0.9 + last_frame * 0.1คำนวณค่าเฉลี่ยที่ทำให้การแสดงผลเปลี่ยนไปอย่างราบรื่น
Fabien Quatravaux

2

ระบบที่ดีกว่าการใช้เฟรมเรตแบบเก่าจำนวนมากคือการทำสิ่งนี้:

new_fps = old_fps * 0.99 + new_fps * 0.01

วิธีนี้ใช้หน่วยความจำน้อยกว่ามากต้องใช้รหัสน้อยกว่ามากและให้ความสำคัญกับเฟรมเรตล่าสุดมากกว่าเฟรมเรตแบบเก่าในขณะที่ยังคงผลกระทบจากการเปลี่ยนแปลงเฟรมเรตอย่างกะทันหัน


1

คุณสามารถเก็บตัวนับเพิ่มได้หลังจากแสดงผลแต่ละเฟรมแล้วรีเซ็ตตัวนับเมื่อคุณอยู่ในวินาทีใหม่ (เก็บค่าก่อนหน้าเป็น # ของเฟรมที่แสดงในวินาทีสุดท้าย)


1

JavaScript:

// Set the end and start times
var start = (new Date).getTime(), end, FPS;
  /* ...
   * the loop/block your want to watch
   * ...
   */
end = (new Date).getTime();
// since the times are by millisecond, use 1000 (1000ms = 1s)
// then multiply the result by (MaxFPS / 1000)
// FPS = (1000 - (end - start)) * (MaxFPS / 1000)
FPS = Math.round((1000 - (end - start)) * (60 / 1000));

1

นี่คือตัวอย่างที่สมบูรณ์โดยใช้ Python (แต่ปรับให้เข้ากับภาษาใดก็ได้) มันใช้สมการการปรับให้เรียบในคำตอบของมาร์ตินจึงแทบไม่มีหน่วยความจำเหนือศีรษะและฉันเลือกค่าที่เหมาะกับฉัน (อย่าลังเลที่จะเล่นกับค่าคงที่เพื่อปรับให้เข้ากับกรณีการใช้งานของคุณ)

import time

SMOOTHING_FACTOR = 0.99
MAX_FPS = 10000
avg_fps = -1
last_tick = time.time()

while True:
    # <Do your rendering work here...>

    current_tick = time.time()
    # Ensure we don't get crazy large frame rates, by capping to MAX_FPS
    current_fps = 1.0 / max(current_tick - last_tick, 1.0/MAX_FPS)
    last_tick = current_tick
    if avg_fps < 0:
        avg_fps = current_fps
    else:
        avg_fps = (avg_fps * SMOOTHING_FACTOR) + (current_fps * (1-SMOOTHING_FACTOR))
    print(avg_fps)

0

ตั้งค่าตัวนับเป็นศูนย์ ทุกครั้งที่คุณวาดกรอบเพิ่มตัวนับ หลังจากแต่ละวินาทีพิมพ์ตัวนับ ฟองล้างทำซ้ำ หากคุณต้องการเครดิตเพิ่มเติมให้ใช้ตัวนับที่ทำงานอยู่และหารด้วยจำนวนวินาทีทั้งหมดสำหรับค่าเฉลี่ยที่กำลังทำงานอยู่


0

ใน (c ++ like) pseudocode ทั้งสองนี้เป็นสิ่งที่ฉันใช้ในแอปพลิเคชั่นประมวลผลภาพอุตสาหกรรมที่ต้องประมวลผลภาพจากชุดกล้องที่เรียกใช้จากภายนอก การเปลี่ยนแปลงใน "อัตราเฟรม" มีแหล่งที่มาที่แตกต่างกัน (การผลิตที่ช้าลงหรือเร็วขึ้นบนสายพาน) แต่ปัญหาก็เหมือนกัน (ฉันคิดว่าคุณมีการโทร timer.peek () แบบธรรมดาที่ให้ค่าบางอย่างเช่น nr ของ msec (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
qx.Class.define('FpsCounter', {
    extend: qx.core.Object

    ,properties: {
    }

    ,events: {
    }

    ,construct: function(){
        this.base(arguments);
        this.restart();
    }

    ,statics: {
    }

    ,members: {        
        restart: function(){
            this.__frames = [];
        }



        ,addFrame: function(){
            this.__frames.push(new Date());
        }



        ,getFps: function(averageFrames){
            debugger;
            if(!averageFrames){
                averageFrames = 2;
            }
            var time = 0;
            var l = this.__frames.length;
            var i = averageFrames;
            while(i > 0){
                if(l - i - 1 >= 0){
                    time += this.__frames[l - i] - this.__frames[l - i - 1];
                }
                i--;
            }
            var fps = averageFrames / time * 1000;
            return fps;
        }
    }

});

0

ฉันทำได้ยังไง!

boolean run = false;

int ticks = 0;

long tickstart;

int fps;

public void loop()
{
if(this.ticks==0)
{
this.tickstart = System.currentTimeMillis();
}
this.ticks++;
this.fps = (int)this.ticks / (System.currentTimeMillis()-this.tickstart);
}

ในคำพูดนาฬิกาเห็บจะติดตามเห็บ หากเป็นครั้งแรกให้ใช้เวลาปัจจุบันและใส่ไว้ใน 'tickstart' หลังจากขีดแรกจะทำให้ตัวแปร 'fps' เท่ากับจำนวนขีดของนาฬิกาขีดที่หารด้วยเวลาลบเวลาของขีดแรก

Fps เป็นจำนวนเต็มดังนั้น "(int)"


1
จะไม่แนะนำสำหรับทุกคน การหารจำนวนเห็บทั้งหมดด้วยจำนวนวินาทีทั้งหมดทำให้แนวทาง FPS เป็นเหมือนขีด จำกัด ทางคณิตศาสตร์ซึ่งโดยทั่วไปจะตั้งค่า 2-3 ค่าหลังจากผ่านไปนานและแสดงผลลัพธ์ที่ไม่ถูกต้อง
Kartik Chugh

0

นี่คือวิธีที่ฉันทำ (ใน Java):

private static long ONE_SECOND = 1000000L * 1000L; //1 second is 1000ms which is 1000000ns

LinkedList<Long> frames = new LinkedList<>(); //List of frames within 1 second

public int calcFPS(){
    long time = System.nanoTime(); //Current time in nano seconds
    frames.add(time); //Add this frame to the list
    while(true){
        long f = frames.getFirst(); //Look at the first element in frames
        if(time - f > ONE_SECOND){ //If it was more than 1 second ago
            frames.remove(); //Remove it from the list of frames
        } else break;
        /*If it was within 1 second we know that all other frames in the list
         * are also within 1 second
        */
    }
    return frames.size(); //Return the size of the list
}

0

ใน typescript ฉันใช้อัลกอริทึมนี้เพื่อคำนวณค่าเฉลี่ย framerate และ frametime:

let getTime = () => {
    return new Date().getTime();
} 

let frames: any[] = [];
let previousTime = getTime();
let framerate:number = 0;
let frametime:number = 0;

let updateStats = (samples:number=60) => {
    samples = Math.max(samples, 1) >> 0;

    if (frames.length === samples) {
        let currentTime: number = getTime() - previousTime;

        frametime = currentTime / samples;
        framerate = 1000 * samples / currentTime;

        previousTime = getTime();

        frames = [];
    }

    frames.push(1);
}

การใช้งาน:

statsUpdate();

// Print
stats.innerHTML = Math.round(framerate) + ' FPS ' + frametime.toFixed(2) + ' ms';

เคล็ดลับ: หากตัวอย่างเป็น 1 ผลลัพธ์จะเป็นเฟรมเรทและเฟรมไทม์แบบเรียลไทม์


0

นี่เป็นไปตามคำตอบของ KPexEA และให้ค่าเฉลี่ยเคลื่อนที่อย่างง่าย ผูกและแปลงเป็น TypeScript เพื่อให้คัดลอกและวางได้ง่าย:

การประกาศตัวแปร:

fpsObject = {
  maxSamples: 100,
  tickIndex: 0,
  tickSum: 0,
  tickList: []
}

ฟังก์ชัน:

calculateFps(currentFps: number): number {
  this.fpsObject.tickSum -= this.fpsObject.tickList[this.fpsObject.tickIndex] || 0
  this.fpsObject.tickSum += currentFps
  this.fpsObject.tickList[this.fpsObject.tickIndex] = currentFps
  if (++this.fpsObject.tickIndex === this.fpsObject.maxSamples) this.fpsObject.tickIndex = 0
  const smoothedFps = this.fpsObject.tickSum / this.fpsObject.maxSamples
  return Math.floor(smoothedFps)
}

การใช้งาน (อาจแตกต่างกันไปในแอปของคุณ):

this.fps = this.calculateFps(this.ticker.FPS)

-1

จัดเก็บเวลาเริ่มต้นและเพิ่มตัวนับเฟรมของคุณหนึ่งครั้งต่อลูป? ทุกๆสองสามวินาทีคุณสามารถพิมพ์ framecount / (ตอนนี้ - เวลาเริ่มต้น) จากนั้นกำหนดค่าเริ่มต้นใหม่ได้

แก้ไข: โอ๊ะโอ double-ninja'ed

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.