关于渲染帧率(FPS)的问题

先列举几个关于渲染帧率的文章:
1. http://ruinerlee.blog.163.com/blog/static/215611167201292990203/
2. http://blog.codingnow.com/2008/04/fps.html
3. http://blog.csdn.net/strongcoding/article/details/6252313

#include
#include
#pragma comment(lib,"winmm.lib")

int main()
{
  DWORD currentTime;
  DWORD lastTime = timeGetTime();
  DWORD frameCounter    = 0;
  DWORD frameTime    = 0;
  DWORD elapsedTime = 0;
  while(1)
  {                                                
      currentTime = timeGetTime();                
      frameTime += (currentTime - lastTime);
      elapsedTime += (currentTime - lastTime);
      lastTime = currentTime;                                                    
      if(frameTime > 16) //   1000/60 ,渲染一次需要的时间                          
      {                                            
          frameCounter++;                            
          frameTime -= 16;  //因为有可能大于16,直接置零会导致少算
      }

      if(elapsedTime >= 1000)                    
      {
          std::cout << frameCounter << std::endl;
          frameCounter = 0;
          elapsedTime -= 1000;
      }
  }
  return 0;
}

解释:

渲染帧速率,即每秒渲染的帧数。上面的程序设置固定的帧速率为60,之所以使用frameTime累积时间值,是因为电脑中的程序是CPU切换执行的,而这种切换速度是非常快的,只有累积的时间大于渲染一帧需要的时间时才会累加frameCounter。elapsedTime 变量是累积程序运行的时间,当程序运行的时间大于或者等于1000ms也就是1s的时候,打印一下FPS。

下面是2个案例:

#include "Timing.h"

#include <SDL/SDL.h>


namespace Tengine {
    FpsLimiter::FpsLimiter() {
    }

    void FpsLimiter::init(float maxFPS) {
        setMaxFPS(maxFPS);
    }

    void FpsLimiter::setMaxFPS(float maxFPS) {
        _maxFPS = maxFPS;
    }

    void FpsLimiter::begin() {
        _startTicks = SDL_GetTicks();
    }

    float FpsLimiter::end() {
        calculateFPS();

        float frameTicks = SDL_GetTicks() - _startTicks;
        // Limit the FPS to the max FPS
        if (1000.0f / _maxFPS > frameTicks) {
            SDL_Delay(1000.0f / _maxFPS - frameTicks);
        }

        return _fps;
    }

    void FpsLimiter::calculateFPS() {
        static const int NUM_SAMPLES = 10;
        static float frameTimes[NUM_SAMPLES];
        static int currentFrame = 0;

        static float prevTicks = SDL_GetTicks();

        float currentTicks;
        currentTicks = SDL_GetTicks();

        _frameTime = currentTicks - prevTicks;
        frameTimes[currentFrame % NUM_SAMPLES] = _frameTime;

        prevTicks = currentTicks;

        int count;


        currentFrame++;
        if (currentFrame < NUM_SAMPLES)
        {
            count = currentFrame;
        }
        else
        {
            count = NUM_SAMPLES;
        }

        float frameTimeAverage = 0;
        for (int i = 0; i < count; i++)
        {
            frameTimeAverage += frameTimes[i];
        }
        frameTimeAverage /= count;

        if (frameTimeAverage > 0)
        {
            _fps = 1000.0f / frameTimeAverage;
        }
        else {
            _fps = 60.0f;
        }
    }
}

另一个示例:

package com.base.engine;

import java.io.File;
import java.net.URI;
import java.util.zip.ZipFile;

public class MainComponent {



    public static final int WIDTH = 800;
    public static final int HEIGHT = 600;
    public static final String TITLE = "3D Engine";

    private static final double FRAME_CAP = 60.00;//每秒游戏刷新的次数,但是我不可能每秒画5000次。

    private boolean isRunning;
    private Game game;

    public MainComponent ()
    {
        isRunning = false;

        game = new Game();
    }

    public void start(){
        if(isRunning)
            return;

        run();
    }

    public void stop(){
        if(!isRunning)
            return;

        isRunning =false;
    }

    //要使Game在固定的时间单元内刷新一次。这样帧率对游戏的场景就没有影响了。如:我要让我的ball在固定的时间内移动一次,而不管在这固定的时间内实际画了多少在屏幕上。

    private void run(){

        isRunning = true;

        int frames = 0;
        long frameCounter = 0;

        //一帧需要的时间
        final double frameTime = 1.0 / FRAME_CAP;

        long lastTime = Time.getTime();
        double unprocessedTime = 0; 

        while(isRunning){
            boolean render  = false;

            long startTime = Time.getTime();
            long passedTime = startTime - lastTime;
            lastTime = startTime;

            unprocessedTime += passedTime / (double)Time.SECOND;
            frameCounter += passedTime;

            while(unprocessedTime > frameTime){
                render =true;

                unprocessedTime -= frameTime;

                if(Window.isCloseRequested())
                    stop();

                Time.setDelta(frameTime);

                //TODO: update game
                game.input();
                game.update();

                if(frameCounter >= Time.SECOND){//每秒钟输出一次FPS
                    System.out.println(frames);

                    frames = 0;
                    frameCounter =0;
                }
            }
            if(render){
                render();
                frames++;
            }else{
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        cleanUp();
    }

    private void render(){
        game.render();
        Window.render();
    }

    private void cleanUp(){
        Window.dispose();
    }

    public static void main(String[] args) {

        Window.createWindow(WIDTH, HEIGHT, TITLE);


        MainComponent game = new MainComponent();

        game.start();
    }
}

Time.java

package com.base.engine;

public class Time {
    public static final long SECOND = 1000000000L;

    private static double delta;

    public static long getTime(){
        return System.nanoTime();
    }

    public static double getDelta(){
        return delta;
    }

    public static void setDelta(double delta){
        Time.delta = delta;
    }
}

猜你喜欢

转载自blog.csdn.net/birdflyto206/article/details/59222079
今日推荐