![da568686453529ae586327d78c03ef4d.png](https://i-blog.csdnimg.cn/blog_migrate/0b256a6e051560872d6998ab6c77e56a.png)
![a17b5702bfa4ab558a974f8f36c98848.png](https://i-blog.csdnimg.cn/blog_migrate/ab91242f98271302e86f4a9bf1401cd7.jpeg)
![5984d89d335a56789d7020042f18ed0f.png](https://i-blog.csdnimg.cn/blog_migrate/0218f10c02d0d5b5436a3123c1b3b85a.png)
虽然在虚幻5里写各种效果很方便,有很多轮子和框架,但是如果想要自己写一些底层的效果或则算法往往意味着要对引擎底层进行大改,所以搭建一套自己的图形环境也是很有必要的。
DX的各种接口还是比较难以记忆的,通过这系列文章也可以对DX12的知识进行一些梳理和笔记,过于底层的效果或算法我会在这个自己搭建的框架里实现,这对于理解底层掌握原理还是很有必要的,不然在虚幻里使用更上层的封装接口会一头雾水。
我这里也不打算写基础的教程,这方面资料已经很多了,我主要记录一些杂乱的,书里没有讲清楚的部分。
![4410d8225c99bb1b9e3641620981c411.png](https://i-blog.csdnimg.cn/blog_migrate/b90d05f6bdb403f70638a3172f607f60.png)
我使用的是windows10,VS2019,DX12的环境。首先建一个空的C++控制台应用程序:
![4829a7f0933bed920df4a632fb5cdd4e.png](https://i-blog.csdnimg.cn/blog_migrate/93908a271e7e07f49e365c9a5c277e68.jpeg)
![3840a5ffad64a1bb3faabdde6cabe3ee.png](https://i-blog.csdnimg.cn/blog_migrate/862ff85dc0a091f74716bc652d0e2a06.png)
【1】GameTimer和fps统计
![3840a5ffad64a1bb3faabdde6cabe3ee.png](https://i-blog.csdnimg.cn/blog_migrate/862ff85dc0a091f74716bc652d0e2a06.png)
计时器对于渲染器非常重要,各种移动,模拟计算,动态图形效果都需要计时器。在一切开始之前先尝试一下基础的Win32编程,做一个高精度计时器。
要做一个计时器和fps统计器我们主要会用到Windos的几个接口:
QueryPerformanceFrequency(...),是操作系统的性能统计频率,也就是每秒钟统计多少次。
QueryPerformanceCounter(...),是系统性能统计计数器,表示统计了多少次。
QueryPerformanceCounter除以QueryPerformanceFrequency会得到系统运行的时间秒数。这两个接口受硬件支持。如果硬件不支持会返回false
下面我用sleep函数模拟一下程序执行的时间消耗。
#include <windows.h>
#include <iostream>
using namespace std;
__int64 mCurrTime;
__int64 mPrevTime;
double mSecondsPerCount;
double mDeltaTime;
int main()
{
__int64 countsPerSecFreq;
QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSecFreq);
mSecondsPerCount = 1.0 / (double)countsPerSecFreq;
while (true)
{
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
mCurrTime = currTime;
Sleep(100);
// Time difference between this frame and the previous.
mDeltaTime = (mCurrTime - mPrevTime) * mSecondsPerCount;
// Prepare for next frame.
mPrevTime = mCurrTime;
cout << (double)mCurrTime / mSecondsPerCount << endl;
}
return 0;
}
![3514cd3417a216af7a085f5a4ad91feb.png](https://i-blog.csdnimg.cn/blog_migrate/aa4b5495795cbb3ab8a58b20d90e5c3f.jpeg)
如果把上一帧的时间减去当前的时间,就可以得到高精度的时间差:
![0c4695e1bdf1b30b52326cc7a02535bb.png](https://i-blog.csdnimg.cn/blog_migrate/0d628c6fd788a75bd32b811661391318.jpeg)
QueryPerformanceCounter除以QueryPerformanceFrequency是得到系统运行的时间秒数。但是如果我们想得到应用程序运行的时间,我们可以先在程序运行之初把时间记录下来,作为BaseTime,然后再在运行期拿到当前时间,用当前的时间减去BaseTime再除以QueryPerformanceFrequency就可以得到当前应用程序的时间。
![7bc9f066a3a03617558b6eaa74116c85.png](https://i-blog.csdnimg.cn/blog_migrate/851c6b06cb121f56fb3acbcdcb9d1fea.jpeg)
完整代码如下:
#include <windows.h>
#include <iostream>
using namespace std;
__int64 mCurrTime;
__int64 mPrevTime;
double mSecondsPerCount;
double mDeltaTime;
int main()
{
__int64 countsPerSecFreq;
QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSecFreq);
mSecondsPerCount = 1.0 / (double)countsPerSecFreq;
__int64 BaseTime;
QueryPerformanceCounter((LARGE_INTEGER*)&BaseTime);
while (true)
{
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
mCurrTime = currTime;
Sleep(1);
// Time difference between this frame and the previous.
mDeltaTime = (mCurrTime - mPrevTime) * mSecondsPerCount;
// Prepare for next frame.
mPrevTime = mCurrTime;
float TotleTime = (mCurrTime - BaseTime) * mSecondsPerCount;
cout << TotleTime << endl;
}
return 0;
}
我们把上述代码封装一下,就可以得到龙书示例代码的GameTimer
GameTimer.h
#pragma once
class GameTimer
{
public:
GameTimer();
float TotalTime()const; // in seconds
float DeltaTime()const; // in seconds
void Reset(); // Call before message loop.
void Start(); // Call when unpaused.
void Stop(); // Call when paused.
void Tick(); // Call every frame.
private:
double mSecondsPerCount;
double mDeltaTime;
__int64 mBaseTime;
__int64 mPausedTime;
__int64 mStopTime;
__int64 mPrevTime;
__int64 mCurrTime;
bool mStopped;
};
GameTimer.cpp