Direct3d 11 for games: Part 6

Timing your Game Loop and Animating the Quad


This lesson is less about Direct3D and more about timing your game loop.


Once crucial thing of a game is how long has elapsed since your last frame has been shown to the user. By knowing this, you know how much to update your game by. To find the time elapsed since last frame known as delta time or dt, we can use some Windows funcitons, specifically QueryPerformanceCounter and QueryPerformanceFrequency.



Before we enter the game loop we set up a few variables.


// Timing
LONGLONG startPerfCount = 0;
LONGLONG perfCounterFrequency = 0;
{
//NOTE: Get the current performance counter at this moment to act as our reference
LARGE_INTEGER perfCount;
QueryPerformanceCounter(&perfCount);
startPerfCount = perfCount.QuadPart;

//NOTE: Get the Frequency of the performance counter to be able to convert from counts to seconds
LARGE_INTEGER perfFreq;
QueryPerformanceFrequency(&perfFreq);
perfCounterFrequency = perfFreq.QuadPart;

}

//NOTE: To store the last time in
double currentTimeInSeconds = 0.0;



Next in the game loop we want to calculate delta time for the frame. To do this we take the current performance count again, and find what it is relative to the start counter, then convert it to seconds. This will now be the time since we started our game loop. Now we can then find the difference between the time now and the time from the last frame.


//NOTE: Inside game loop
float dt;
{
double previousTimeInSeconds = currentTimeInSeconds;
LARGE_INTEGER perfCount;
QueryPerformanceCounter(&perfCount);

currentTimeInSeconds = (double)(perfCount.QuadPart - startPerfCount) / (double)perfCounterFrequency;
dt = (float)(currentTimeInSeconds - previousTimeInSeconds);
}


By doing everything relative to the start performance count instead of counts since time of computer boot, we help improve the possible precision of the time when it's converted into a double value.


We now have the delta time for our frame which we can print out. If you have a 60fps monitor you should see a time around 0.0166 if vy-sync is on (the first argument in swapBuffer being 1). However it won't be exact. The reasons behind this can be quite complex: you can read more behind the intricacies of frame timing and getting smooth gameplay in the notes [1].



Here is the code we use to print out our dt value for each frame.


char buffer[256];
sprintf(buffer, "%f\n", dt);
OutputDebugStringA(buffer);


Also have to include stdio.h to use sprintf.


//NOTE: At top of file
#include <stdio.h>


Using the dt value in our code


Now that we have dt available to us we can use it to animate the position of our Quad.


We can use dt to update the position of the quad by changing the constant buffer position.


//NOTE: Store time since start of game
static float totalTime = 0;
totalTime += dt;

//...get pointer to constant buffer using Map from previous lesson
constants->pos = {cosf(totalTime)*0.25f, sinf(totalTime)*0.3f};


This code will make our quad move in a circle.


Also have to #include the Math.h header to use cosf and sinf.



Conclusion


We did it, we're now timing our frame so we can update our game correctly.


You can see the full code for this article here šŸ‘†


NOTES


[1] More articles on the intricacy's of frame timing


Fix Your Timestep


The Elusive Frame Timing


The Elusive Frame Timing: A Case Study for Smoothness Over Speedvideo):


The Elusive Frame Timing: A Case Study for Smoothness Over SpeedPDF):


Myths and Misconceptions of Frame Pacing


Fixing Time.deltaTime in Unity 2020.2 for smoother gameplay


Android - Achieve proper frame pacing


Low Latency Mode in NVIDIA Reflex SDK




PREVIOUS LESSON šŸ‘†


NEXT LESSON šŸ‘†