天天看點

關于渲染幀率(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    = ;
  DWORD frameTime    = ;
  DWORD elapsedTime = ;
  while()
  {                                                
      currentTime = timeGetTime();                
      frameTime += (currentTime - lastTime);
      elapsedTime += (currentTime - lastTime);
      lastTime = currentTime;                                                    
      if(frameTime > ) //   1000/60 ,渲染一次需要的時間                          
      {                                            
          frameCounter++;                            
          frameTime -= ;  //因為有可能大于16,直接置零會導緻少算
      }

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

解釋:

渲染幀速率,即每秒渲染的幀數。上面的程式設定固定的幀速率為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 ( / _maxFPS > frameTicks) {
            SDL_Delay( / _maxFPS - frameTicks);
        }

        return _fps;
    }

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

        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 = ;
        for (int i = ; i < count; i++)
        {
            frameTimeAverage += frameTimes[i];
        }
        frameTimeAverage /= count;

        if (frameTimeAverage > )
        {
            _fps =  / frameTimeAverage;
        }
        else {
            _fps = ;
        }
    }
}
           

另一個示例:

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 = ;
    public static final int HEIGHT = ;
    public static final String TITLE = "3D Engine";

    private static final double FRAME_CAP = ;//每秒遊戲重新整理的次數,但是我不可能每秒畫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 = ;
        long frameCounter = ;

        //一幀需要的時間
        final double frameTime =  / FRAME_CAP;

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

        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 = ;
                    frameCounter =;
                }
            }
            if(render){
                render();
                frames++;
            }else{
                try {
                    Thread.sleep();
                } 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 = L;

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

繼續閱讀