• DirectX12初始化五——计时与动画


    计时与动画

    性能计时器

    性能计时器所用的时间单位叫做计数。QueryPerformanceCounter函数获得性能计时器测量的当前时刻值,返回64位整数

    QueryPerformanceFrequency函数获取计时器的频率 (计数/秒)

    每个计数所代表的秒数就是性能计时器频率的倒数,由此可以得出将计数转换为秒的方法

    注意:在不同的处理器上同时调用QueryPerformanceCounter可能得到不同结果,因此我们可以使用SetThreadAffinityMask函数,防止应用程序的主程序切换到其他处理器,此时调用两次QueryPerformanceCounter就能得到正确的计数差值。

    游戏计时器类,构造函数

    实现GameTimer类

    构造函数:

    GameTimer::GameTimer():mSecondsPerCount(0.0),mDeltaTime(-1.0),mBaseTime(0),mPausedTime(0),mPrevTime(0),mCurrTime(0),mStopped(false)
    {
    	__int64 countsPerSec;
    	QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); //检索性能计数器的频率(计数/秒)
    	mSecondsPerCount = 1.0 / (double)countsPerSec; //计数代表的秒数,就是性能计时器频率的倒数(秒/计数)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    帧与帧之间的时间间隔、

    渲染动画帧时,需要知道每帧之间的时间间隔,以此来根据时间的流逝对游戏对象进行更新。

    void GameTimer::Tick()
    {
    	if (mStopped)
    	{
    		mDeltaTime = 0.0;
    		return;
    	}
    	//获得本帧开始显示的时刻
    	__int64 currTime;
    	QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
    	mCurrTime = currTime;
    
    	//本帧与前一帧的时间差
    	mDeltaTime = (mCurrTime - mPrevTime) * mSecondsPerCount;
    	
    	//准备计算本帧与下一帧的时间差
    	mPrevTime = mCurrTime;
    	
    	//使时间差为非负值
    	if (mDeltaTime < 0.0)
    	{
    		mDeltaTime = 0.0;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    void GameTimer::Reset()
    {
    	__int64 currTime;
    	QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
    
    	mBaseTime = currTime;
    	mPrevTime = currTime; //把前一帧的值初始化为当前时刻,因为在第一帧动画之前没有动画,所以要在消息循环开始之前初始化此值,不然会是乱码
    	mStopTime = 0;
    	mStopped = false;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    把前一帧的值初始化为当前时刻,因为在第一帧动画之前没有动画,所以要在消息循环开始之前初始化此值,不然会是乱码

    总时间

    总时间:从应用程序执行开始,不计其中暂停的时间的总和。

    float GameTimer::TotalTime()const
    {
    	if (mStopped) //如果现在是暂停状态,那现在暂停的这段时间可以不计,然后排除之前暂停的时间即可
    	{
    		return (float)(((mStopTime - mPausedTime) - mBaseTime) * mSecondsPerCount);
    	}
    	else //不是暂停状态,那排除之前暂停的时间即可
    	{
    		return (float)(((mCurrTime - mPausedTime) - mBaseTime) * mSecondsPerCount);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    GameTimer.h

    #pragma once
    
    #ifndef GAMETIMER_H
    #define GAMETIMER_H
    
    class GameTimer
    {
    public:
    	GameTimer();//构造函数
    
    	float TotalTime()const;//用秒作为单位,返回除去暂停时间的总时间,
    	float DeltaTime()const;//用秒作为单位,返回两帧之间的时间差
    	
    	void Reset();//开始消息循环之前调用
    	void Start();//解除计时器暂停时调用
    	void Stop(); //暂停计时器时调用
    	void Tick(); //每帧调用
    
    private:
    	double mSecondsPerCount  ; //计数代表的秒数
    	double mDeltaTime; //两帧之间的时间差
    
    	__int64 mBaseTime;   //基础时刻,应用程序开始运行的时刻
    	__int64 mPausedTime; //暂停时间,应用程序暂停的时间和
    	__int64 mStopTime;   //暂停时刻,应用程序上一次暂停的时刻
    	__int64 mPrevTime;   //上一帧的时刻
    	__int64 mCurrTime;   //现在的时刻
    	
    	bool mStopped; //暂停状态标记
    
    };
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    GameTimer.cpp

    #include <Windows.h>
    #include "GameTimer.h"
    
    GameTimer::GameTimer():mSecondsPerCount(0.0),mDeltaTime(-1.0),mBaseTime(0),mPausedTime(0),mPrevTime(0),mCurrTime(0),mStopped(false)
    {
    	__int64 countsPerSec;
    	QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); //检索性能计数器的频率(计数/秒)
    	mSecondsPerCount = 1.0 / (double)countsPerSec; //计数代表的秒数,就是性能计时器频率的倒数(秒/计数)
    }
    
    void GameTimer::Tick()
    {
    	if (mStopped)
    	{
    		mDeltaTime = 0.0;
    		return;
    	}
    	//获得本帧开始显示的时刻
    	__int64 currTime;
    	QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
    	mCurrTime = currTime;
    
    	//本帧与前一帧的时间差
    	mDeltaTime = (mCurrTime - mPrevTime) * mSecondsPerCount;
    	
    	//准备计算本帧与下一帧的时间差
    	mPrevTime = mCurrTime;
    	
    	//使时间差为非负值
    	if (mDeltaTime < 0.0)
    	{
    		mDeltaTime = 0.0;
    	}
    
    }
    
    void GameTimer::Reset()
    {
    	__int64 currTime;
    	QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
    
    	mBaseTime = currTime;
    	mPrevTime = currTime; //把前一帧的值初始化为当前时刻,因为在第一帧动画之前没有动画,所以要在消息循环开始之前初始化此值,不然会是乱码
    	mStopTime = 0;
    	mStopped = false;
    
    }
    
    void GameTimer::Stop()
    {
    	//如果已经是停止状态,那就什么都不做
    	if (!mStopped)
    	{
    		__int64 currTime;
    		QueryPerformanceCounter((LARGE_INTEGER*)&currTime);//获取当前时刻时间
    
    		//保存当前时刻值为停止之间,并设置标志为true,指示计时器已停止
    		mStopTime = currTime;
    		mStopped = true;
    	}
    
    }
    
    void GameTimer::Start()
    {
    	__int64 startTime;
    	QueryPerformanceCounter((LARGE_INTEGER*)&startTime);
    
    	//如果暂停状态继续计时
    	if (mStopped)
    	{
    		mPausedTime += (startTime - mStopTime); //累加暂停时间
    	
    		mPrevTime = startTime;
    	
    		//不再是停止状态
    		mStopTime = 0;
    		mStopped  = false;
    	}
    
    }
    
    float GameTimer::TotalTime()const
    {
    	if (mStopped) //如果现在是暂停状态,那现在暂停的这段时间可以不计,然后排除之前暂停的时间即可
    	{
    		return (float)(((mStopTime - mPausedTime) - mBaseTime) * mSecondsPerCount);
    	}
    	else //不是暂停状态,那排除之前暂停的时间即可
    	{
    		return (float)(((mCurrTime - mPausedTime) - mBaseTime) * mSecondsPerCount);
    	}
    }
    float GameTimer::DeltaTime()const
    {
    	return (float)mDeltaTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
  • 相关阅读:
    如何准确且可解释地评估大模型量化效果?
    JWT详细讲解
    【机器学习书籍】机器学习(西瓜书)[书籍PDF分享]
    python渗透测试入门——基础的网络编程工具
    K8s Kubelet 垃圾回收机制
    关于《Java并发编程之线程池十八问》的补充内容
    【python基础(三)】操作列表:for循环、正确缩进、切片的使用、元组
    14届蓝桥杯青少组选拔赛C++_2022.11.27
    JVM虚拟机:通过日志学习PS+PO垃圾回收器
    Unity - Shader - Projector 高空云层底下透明阴影
  • 原文地址:https://blog.csdn.net/qq_51599283/article/details/125625058