Hi there,
I'm pretty new to DirectX, Direct2D and C#-Development in General (not to Development in itself) so excuse me if there are any oblivious flaws.
The attached tags should give an rough overview about the Environment I'm using (or at least I hope so ).
My SharpDX-Application is using DirectX10 combined with Direct2D in a SwapChain. I'm mostly drawing 2D UI-Stuff in Direct2D (the Application isn't a Game in itself but a Helper enabling Steam In-Home-Streaming for the Windows Desktop) however I might implement a few DirectX effects later on if I find time or patience to do so. Well let 's say I've just finished the first Prototype for my Animation Class so everything is in a pretty early stage. Sorry for the long introduction I'll show you my code that is important in getting accurate answers concerning my questions next
This is my RenderLoop and the most important methods build around it:
public virtual void Initialize() { }
public virtual void LoadContent(){ }
public virtual void UnloadContent() { }
public virtual void RunOnceBeforeRender() { }
public virtual void RunOnceAfterRender() { }
public virtual void Update(int fps, int cpu, double frameTime) { }
public virtual void Draw(int fps, int cpu, double frameTime) { }
public virtual void BeginFrame() {
Application.FPS.Frame();
Application.CPU.Frame();
Application.Timer.Frame(); // <- RenderTime gets updated here
}
public virtual void EndFrame() {
swapChain.Present(1, PresentFlags.None);
}
public virtual void Run()
{
Initialize();
LoadContent();
//Reminder - http://gafferongames.com/game-physics/fix-your-timestep/
RenderLoop.Run(renderForm, () =>
{
if(bRunOnceBeforeRender == false) { RunOnceBeforeRender(); bRunOnceBeforeRender = true; }
BeginFrame(); // <- Update FrameTime
if(!renderForm.isResizing && renderForm.hasSizeChanged) HandleResize();
Update(Application.FPS.Value, Application.CPU.Value, Application.Timer.FrameTime);
Draw(Application.FPS.Value, Application.CPU.Value, Application.Timer.FrameTime);
EndFrame();
if(bRunOnceAfterRender == false) { RunOnceAfterRender(); bRunOnceAfterRender = true; }
});
UnloadContent();
Dispose();
}
public virtual void Dispose()
{
Utilities.Dispose(ref backBuffer);
Utilities.Dispose(ref renderView);
Utilities.Dispose(ref d2dRenderTarget);
Utilities.Dispose(ref surface);
}
I limit the FPS to 60 (VSYNC enabled) via
swapChain.Present(1, PresentFlags.None);
in EndFrame()
(double) RenderTime (= Time in MS the last Frame took to Render) gets updated at the start of each next frame here BeginFrame():
public virtual void BeginFrame() {
...
...
Application.Timer.Frame(); // <- RenderTime gets updated here
}
The Frame() method that stores the time since the last frame got drawn looks like this:
public void Frame()
{
_StopWatch.Stop();
FrameTime = (double)_StopWatch.ElapsedTicks/(Stopwatch.Frequency/1000);
LastUpdated = Stopwatch.GetTimestamp();
//if(FrameTime > 250) FrameTime = 250; // Set Maximum Frametime to 250ms
_StopWatch.Restart();
}
As you can see I'm using StopWatch due to the QueryPerformanceCounter/QueryPerformanceFrequency implementation for a High Resolution Timer.
Here comes my first question:
FrameTime = (double)_StopWatch.ElapsedTicks/(Stopwatch.Frequency/1000);
Is the calculation / storage of the FrameTime ok like this?
Could it be optimized in terms of speed or reliability (both in terms of reliability and performance)?
What I'm planning to add is limiting the maximum FrameTime to 250ms just in case I get ridiculus amounts of Frameskips.
Now lets move onto the topic of Animating stuff with the above Environment (Target FPS of 60, Time since last frame stored as double).
Like I said in my Introduction above I've written my first Prototype of my Animation class called PropertyAnimation since it 's aimed at animating any Numeric Property of any Object.
It 's not yet finished as in the Draw()/Render()/Update() Methods are still missing but the rest is already there for which the most important part for me is the calculation of the single steps with the targeted FPS and aimed animation time. The single step itself is returned with the method GetStep().
public object GetStep() {
double step;
step = (_to-_from)/(_durationS*_FPS);
return step;
}
using all of the above this is what I'm logging with my Application with a sample Animation Testcase with the following Code:
public class TestObject
{
public int width = 100;
public int height = 100;
}
if(Log.IsDebugEnabled) {
Log.Debug("Average FPS: " + FPS.AVG.ToString());
Log.Debug("Min FPS: " + FPS.Min.ToString());
Log.Debug("Max FPS: " + FPS.Max.ToString());
Log.Debug("Last FPS Value: " + FPS.Value.ToString());
Log.Debug("Last FrameTime is "+Timer.FrameTime.ToString());
TestObject myTest = new TestObject();
//animateMyTest.SetValue((int)400);
string msg = "\n\n=== Test Animation Data ===\n";
double toValue = 500;
long timeInMS = 2000;
int _FPS = 60;
PropertyAnimation animateMyTest = new PropertyAnimation(myTest, "width", toValue, timeInMS, 60);
double _frameTime = Timer.FrameTime;
double animationStep = (double)animateMyTest.GetStep();
double correctedStep = animationStep * ((_frameTime/1000)*_FPS);
msg += "\n Animate From => " + animateMyTest.GetValue().ToString();
msg += "\n Animate To => " + toValue.ToString();
msg += "\n Within MS => " + timeInMS.ToString();
msg += "\n Target FPS => " +_FPS.ToString();
msg += "\n Animation Step => " + animationStep.ToString();
msg += "\n Step FPS-Corrected => " + correctedStep.ToString();
msg += "\n\n===========================";
msg = msg.Replace ("\n", System.Environment.NewLine);
Log.Debug(msg);
}
... which is giving me the following Debug Output:
2014-07-30 02:56:42,753 [DEBUG] Average FPS: 55
2014-07-30 02:56:42,753 [DEBUG] Min FPS: 28
2014-07-30 02:56:42,753 [DEBUG] Max FPS: 60
2014-07-30 02:56:42,753 [DEBUG] Last FPS Value: 60
2014-07-30 02:56:42,753 [DEBUG] Last FrameTime is 16,766265060241
2014-07-30 02:56:42,753 [DEBUG]
=== Test Animation Data ===
Animate From => 100
Animate To => 500
Within MS => 2000
Target FPS => 60
Animation Step => 3,33333333333333
Step FPS-Corrected => 3,35325301204819
===========================
Here comes the second question:
To me, as a beginner in Frame-Dependent Developing with DirectX/D2D and similiar everything looks ok. However I'm wondering if I understood the principles of the FPS-Correction of the Animations with the Frame correctly (that 's called Interpolation right?). As in -
if my interpolation / correction calculation is correct, efficient and reliable enough to be called at each frame:
//GetStep() = (_to-_from)/(_durationS*_FPS);
double _frameTime = Timer.FrameTime;
double animationStep = (double)animateMyTest.GetStep();
double correctedStep = animationStep * ((_frameTime/1000)*_FPS);
Wow, ok I hope i didn't forget some important stuff, and my questions make sense for them to get answered. Like I said sorry if I'm grasping something wrong I just started C# 5 days ago and this is what I've come up with up to now. Cool that you took the time to read my thread - I'm welcoming any constructive feedback and of course absolutely anything that can provide towards solving my questions. Sorry if the post itself is rather long - I tried to be as specific as I could.
Cheers!
Simon
I've attached the PropertyAnimation class just in case any questions arise towards any specific functions.