DX11(一)-性能计时器

05/19/2020

目的

要正确的实现动画效果,我们必须记录时间,尤其是要精确测量动画帧之间的时间间隔。当帧速率高时,帧之间的时间间隔就会很短,所以需要一个高精确度计时器。

应用

  • 平滑移动
  • 动画

说明1:高精度

例子1:

#include <window.h> //WIN32 计时器
__int64 currCounts; //高精度计时器需要精度高的:64位
QueryPerformanceCounter((LARGE_INTEGER*)&currCounts); //单位:计数,获得当前每秒的计数,又叫频率

double mSecondsPerCount = 1.0 / (double)currCounts; // 单位:秒,每次计数的时间长度

例子2:

__int64 A =0;
QueryPerformanceCounter((LARGE_INTEGER*)&A);
__int64 B =0;
QueryPerformanceCounter((LARGE_INTEGER*)&B);

double deltaTime = (B-A)* mSecondPerCount; //两个时间点间隔时间,单位:秒

实现计时器

GameTimer 类头文件

class GameTimer
{
public:
	GameTimer();
	float getTotalTime()const; //总游戏时间
	float getDeltaTime()const; //帧间隔时间

	void reset();	//在消息循环之前调用,重置
	void start();	//取消暂停时调用
	void stop();	//暂停
	void tick();	//每一帧的时候调用

private:
	double mSecondsPerCount;
	double mDeltaTime;

	__int64 mBaseTime;   	//起点
	__int64 mPausedTime;	//暂停多久(start-stop)
	__int64 mStopTime;		//暂停点
	__int64 mPrevTime;		//上一次时间
	__int64 mCurrTime;		//当前时间

	bool mIsStopped;
};

实现

计算DeltaTime:Tick函数

当渲染动画帧时,我们必须知道帧之间的时间间隔,以使我们根据逝去的时间长度来更新游戏中的物体。
Δ t = Δ t c u r r T i m e = Δ t p r e v T i m e \Delta t = \Delta t_{currTime} = \Delta t_{prevTime}

注意:至少要达到每秒30帧的频率才能等到比较平滑的动画效果

平滑:物体移动没有卡顿的效果,连贯性!

实现

void GameTimer::Tick()
{
	if(mIsStopped)
	{
		mDeltaTime = 0.0;
		return;
	}
	
	__int64 currTime;
	QueryPerformance((LARGE_INTEGER*)& currTime);
	mCurrTime = currTime;
	//Delta t
	mDeltaTime = (mCurrTime-mPrevTime)*mSecondsPerCount;

	mPrevTime = mCurrTime;
	
	//确保不是负值,DXSDK中的CDXUTTimer提到,如果处理器进入了节点模式
	//或切换到另一个处理器,mDeltaTime会变成负值
	if(mDeltaTime < 0)
	{
		mDeltaTime = 0.0;
	}
	
	
}

游戏主循环调用Tick

int D3DApp::run()  //游戏主循环
{
	// ....
	mTimer.reset(); //GameTime类

	while(/*直到窗口被关闭*/)
	{
		// ...window消息接受,处理消息

		//游戏进行时
		mTimer.tick();  							//计算DeltaTime
		if(!mAppPaused)
		{
			calculateFrameStats();					//计算每秒帧数并在窗口显示信息
			updateScene(mTimer.getDeltaTime());  	//每帧更新
			drawScene();							//每帧绘制
		}else{
			sleep(100);
		}
	}
	//... return 
}

帧的统计数值 calculateFrameStats

  • 计算每秒帧速,并计算每一帧渲染需要多少时间。FPS
  • 计算某一个时间段t中处理的总帧数。 f p s a v g = n / t fps_{avg} = n/t , 假设t=1,fps = n; 表示每秒总帧数
void D3DApp::calculateFrameStats()
{
	static int frameCount = 0; //记录每秒的总帧数,每1秒之后,需要重置
	static float timeElapsed = 0.0f;
	frameCount++; // 帧总计数
	
	//计算1s的平均值
	if((mTimer.getTotalTime() - timeElapsed) >=1.0f)
	{
		float fps = (float)frameCount; //fps = frameCount / 1sec
	
		float mspf = 1000.0f /fps; //每秒帧数
		//windows cout
		//cout << fps << mspf;
		
		//重置时间
		frameCount = 0;
		timeElapsed += 1.0; //逝去的时间,每次1秒
	}

}

reset

void GameTimer::reset()
{
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);

mBaseTime = currTime;
mPrevTime = currTime;
mStopTime = 0;
mIsStopped = false;
}

游戏时间

从应用程序开始运行时经过的时间总量,不包括暂停时间,这个叫做游戏时间。

用途

  • 计时游戏:假如玩家有300秒完成一个关卡。关卡开始时间有一个 t s t a r t t_{start} , 判断玩家是否超时。
  • 灯光移动:不考虑暂停时间,不然动画移动会瞬间移动到其他位置

实现

成员变量

  • mBaseTime:初始化为当前时间
  • mPausedTIme: 累计游戏的暂停时间
  • mStopTime:记录暂停时间

成员函数

stop

void GameTick::stop()
{
	if(!mIsStopped)
	{
		__int64 currTime;
		QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
		
		mStopTime = currTime; //记录暂停时间
		mIsStopped = true;
		
	}

}

start

void GameTimer::start()
{
	__int64 startTime;
	QueryPerformanceCounter((LARGE_INTEGER*)&startTime);

	if(mIsStopped)
	{
		/* 
							|pauseTime    |
		--------|-----------|------------ |----------------->
		BaseTime		stopTime   		startTime    	
		*/
		mPausedTime += (startTime-mStopTime); //累计暂停时间
		mPrevTime = startTime;
		mStopTime = 0;
		mIsStopped = false; //取消暂停状态
	}

}

getTotalTime

返回了自调用Reset之后经过的时间总量,其中不包括暂停时间

float GameTimer::getTotalTime()const
{
	/*	多重暂停,暂停部分是不被考虑到总时间的
						|paused Time  |
	--------|-----------|------------ |----------|----------------|---->
		BaseTime	stopTime   startTime   stopTime				currTime
	*/
	if(mIsStopped)
	{
		//               |  区别  |
		return (float)(((mStopTime-mPausedTime)-mBaseTime)*mSecondsPerCount);
	}else
	{
	/* 
						|pauseTime    |
	--------|-----------|------------ |-----------|--------------->
		BaseTime	stopTime   startTime    	currTime
	*/
	
		return (float)(((mCurrTime-mPausedTime)-mBaseTime)*mSecondsPerCount);
	}
}

Introduction to 3D Game Progrmming with DirectX11 第四章

猜你喜欢

转载自blog.csdn.net/weixin_44200074/article/details/106208132