Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411275 Posts in 69323 Topics- by 58380 Members - Latest Member: bob1029

March 28, 2024, 08:28:54 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Why deltas fluctuate and how to fix them - A rendering thought experiment
Pages: 1 2 [3]
Print
Author Topic: Why deltas fluctuate and how to fix them - A rendering thought experiment  (Read 7326 times)
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #40 on: April 10, 2013, 04:19:18 PM »

You have to build sportive scenarios in order to evaluate your engine since "feels smooth to me" isn't enough.

Help us understand what you mean when you say sportive. The dictionary definition doesn't seem to make sense for the way you're using it. In what way are you evaluating your engine other than "feels smooth to me"?
Logged

J-Snake
Level 10
*****


A fool with a tool is still a fool.


View Profile WWW
« Reply #41 on: April 10, 2013, 04:34:31 PM »

By "sportive games" I mean games where sudden changes of actions do matter.

My TrapThem is a good example. An input frame can already decide whether you stop or move over the next whole grid-cell. If you release the directional keys in an accidental catch-up frame after reaching a grid-cell, this frame is registered and you will walk to the next grid-cell despite you should stop. In my game a catch-up can steal 8% of the time-window in the movement-cycle.

All the talk basicly boils down to this, if you have catch-ups when there shouldn't be any then your solution isn't as ideal as mine regarding my specs. However your solution can cover a wider range of requirements, it is only that I don't consider them as important as strictly keeping my specs.
Logged

Independent game developer with an elaborate focus on interesting gameplay, rewarding depth of play and technical quality.<br /><br />Trap Them: http://store.steampowered.com/app/375930
Geti
Level 10
*****



View Profile WWW
« Reply #42 on: April 10, 2013, 10:32:03 PM »

Oh man, J-Snake threads are the best.

@OP: your solution is as ideal and simple as I've seen, though a quick google shows you might have been spamming this around a little Smiley

I don't have much more to add* other than delta fluctuation most of the time being a non-issue as most people have said. That doesn't mean it's not worth implementing, because if you've got a frame independent renderer it may as well work as well as possible (including degrading gracefully).

*(I'm holding off from smacking J-Snake. We all know he hasn't shipped anything and his game's full of bugs anyway.)
Logged

FrankForce
Level 2
**


This tepid water is tasteless.


View Profile WWW
« Reply #43 on: April 11, 2013, 12:06:31 PM »

@OP: your solution is as ideal and simple as I've seen, though a quick google shows you might have been spamming this around a little Smiley

Yeah, thanks! Sorry for the spam but I think this is worth sharing but I need to practice my blogging skills. At a certain point I realized that writing articles are a waste of time if I can't get anyone to read them. I would like to write more often about things that come up during development. Also, as an independent developer I need to use all my resources get noticed.

I agree that it may be subtle but I wouldn't call it a non-issue, it is always present unless corrected for. For years I put so much work into my engine trying to eliminate the stutter but there was always some present no matter what I did. I finally took the time to really dig into it to find this last piece of the puzzle and its under 10 lines of code...

Code:
// this buffer keeps track of the extra bits of time
static float deltaBuffer = 0;

// add in whatever time we currently have saved in the buffer
delta += deltaBuffer;

// calculate how many frames will have passed on the next vsync
const int refreshRate = GetMonitorRefreshRate();
int frameCount = (int)(delta * refreshRate + 1);

// if less then a full frame, increase delta to cover the extra
if (frameCount <= 0) frameCount = 1;

// save off the delta, we will need it later to update the buffer
const float oldDelta = delta;

// recalculate delta to be an even frame rate multiple
delta = frameCount / (float)refreshRate;

// update delta buffer so we keep the same time on average
deltaBuffer = oldDelta - delta;
Logged
Crimsontide
Level 5
*****


View Profile
« Reply #44 on: April 12, 2013, 03:05:45 AM »

Let's observe it more closely: Whenever you press a key it is alway at least the duration of a frame so it will register (so delay is no problem)(analog-like inputs can act differently but it still doesn't make a plus on both sides(delays or catch-ups). But whenever you release a key it is nearly an instant moment. Now assume a game is accidently in two very fast update-frames in a row (like it would happen in TrapThem when I would use a catch-up loop). It practically means that the catch-up frame will take your input when you release it in that unfortunate moment. That is not what you wanted. TrapThem is a grid-based game, you cannot stop between the grid-cells. It would mean that at times you are more prone to go one grid-cell further than you should. The time it takes to reach the next grid-cell are 12 frames. In my solution you will always have them. In a solution with catch-ups you would take one frame away at times. And it is something you will feel. I tested all this and the difference is significant. I think people should thoroughly think the mechanical details through when they aim at sportive quality.

Alright, sure, I see where you're coming from. I think I have an alternate solution that gives the best of both worlds: Suppose you have a separate thread for input, which runs independently of your simulation and rendering thread(s). It's able to accept input at 60Hz or more, regardless of your render thread blocking on vsync or other such things. Each input event is given a timestamp when it comes in, and is queued up to be processed by the simulation thread. The simulation reads the timestamps of inputs as it processes them, and uses that to distinguish inputs that changed between two frames, even if it's catching up and processing both of those frames at once. It seems to me like this would allow your simulation to run at a constant speed, allow the renderer to miss a frame here and there if it can't keep up, and keep the high input resolution you desire.

Being able to implement this depends somewhat on capabilities of hardware, OS, development environment, and system APIs, but it should be doable just about anywhere if you either have preemptive multithreading or an input API that gives you timestamps.

Its a good idea, but can you really do it under windows?  The standard message queue doesn't have time stamps for messages.  Perhaps raw input does?  Not sure.  But the main thread in Windows holds the message queue (putting it on another thread is near impossible) which runs all your windowing code (since you want to keep the window on the same thread as the message queue thats running it), which in turn means most of your rendering code is again on the main thread.

As great idea as it is, I can't see it being easy to implement without OS support (and trivial with).

I really wish a gamer-orientated OS (or perhaps a mode for current OS's) was available that focused on latency and consistency and not just max fps or highest throughput.  Its seems silly that in many games it takes longer to get my input from my mouse to my screen 3 inches away than it takes to get the multiplayer data from another guy across the world.
Logged
J-Snake
Level 10
*****


A fool with a tool is still a fool.


View Profile WWW
« Reply #45 on: April 12, 2013, 05:01:47 AM »

It sounds like a good idea on the first sight but if you want the input to be as close to the actual frame as possible there cannot be a better solution than the native sequential one. You poll for the input right before you update your logic, you cannot get any closer to it regardless what os you are using.

On pc you have already few frames of latency, I don't want to add any more to it. The quality of play in a sportive/competitive game will thank you for that.
Logged

Independent game developer with an elaborate focus on interesting gameplay, rewarding depth of play and technical quality.<br /><br />Trap Them: http://store.steampowered.com/app/375930
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #46 on: April 12, 2013, 08:24:43 AM »

Its a good idea, but can you really do it under windows?  The standard message queue doesn't have time stamps for messages.  Perhaps raw input does?  Not sure.  But the main thread in Windows holds the message queue (putting it on another thread is near impossible) which runs all your windowing code (since you want to keep the window on the same thread as the message queue thats running it), which in turn means most of your rendering code is again on the main thread.

Does it? You might have to pull some trickery to get it to work, but it should be possible to keep rendering code out of the main thread. Still working on my prototype, but I haven't run into any brick walls yet.

It sounds like a good idea on the first sight but if you want the input to be as close to the actual frame as possible there cannot be a better solution than the native sequential one. You poll for the input right before you update your logic, you cannot get any closer to it regardless what os you are using.

Hmm, yes and no. I think we're in agreement about the importance of precise input capture, but I don't think it matters for it to be as close as possible to the exact time you update your game logic. You want it to be as close as possible to reduce overall latency, but the amount of latency introduced by what I described could be as little as a CPU cycle or two (mere nanoseconds). Doing it this way makes it so that spikes in latency don't affect the mechanics of your game.

Close your eyes at any point during a game (or heck, just blink, since that's on the scale of the intervals we're talking about), and you can still play the game blind for at least a fraction of a second based on what you already know. However, if a spike in display latency affects game logic by slowing down the timing for a few frames, this is no longer true; by waiting to read input until you actually get a chance to update your game logic, you're discarding the player's only way of conveying their intention to the game, and reinterpreting it in a way that can't be predicted. Ensuring the minimum amount of latency between input, logic, and display is always important, but having input capture wait on the other two makes it imprecise by its very nature.
Logged

J-Snake
Level 10
*****


A fool with a tool is still a fool.


View Profile WWW
« Reply #47 on: April 12, 2013, 09:16:36 AM »

When a game delays a frame/s, you can consider it a small pause. You want to go on after a pause with the actual input, not with the previously buffered one. For some games it might be ok when they are often in a monotonous flow. Certainly not good for games where sudden changes of actions do matter.
Logged

Independent game developer with an elaborate focus on interesting gameplay, rewarding depth of play and technical quality.<br /><br />Trap Them: http://store.steampowered.com/app/375930
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #48 on: April 12, 2013, 10:12:32 AM »

When a game delays a frame/s, you can consider it a small pause. You want to go on after a pause with the actual input, not with the previously buffered one.

If you're seriously convinced it's a better experience to pause for a frame rather than skip rendering one frame, there's nothing else I can argue, other than to advise you to try your game on an underpowered or overloaded computer and see what a problem it is to have it stuttering all over the place. I'll tell you right now that you're creating a subpar experience for your future players, but you're free to ignore that and find that out firsthand. Maybe you'll be lucky and they won't notice, but I'd be surprised if you could find a single person on this planet who found pausing to be a better experience than dropping a frame every once in a while.

Still planning on finishing my input test app and posting in this thread once it's working. I'll have it running on both Mac and Windows to see if there's a significant advantage afforded by one API or another.
Logged

rosholger
Level 1
*



View Profile
« Reply #49 on: April 12, 2013, 10:23:44 AM »

For once i can actually see what j-snake means, and in a very few games i actually believe pausing for one frame is better than dropping a frame, i play a game called bike race on my phone and a lot of times i lose because it uses the input from a few frames before for to long.
But i would say that this only applies to very very few games, in most games its a lot better to skip rendering a frame or two
Logged
Crimsontide
Level 5
*****


View Profile
« Reply #50 on: April 12, 2013, 01:13:50 PM »

Does it? You might have to pull some trickery to get it to work, but it should be possible to keep rendering code out of the main thread. Still working on my prototype, but I haven't run into any brick walls yet.

In my experience it was surprisingly difficult.  Granted I was using D3D9 and it was a while ago, so perhaps things are a little better.

TBH though I think I'd keep all windowing/rendering code on the main thread.  Use a query to track how many frames in flight and frame times, and put all other code in other threads.  Not impossible, but certainly not pretty...
Logged
J-Snake
Level 10
*****


A fool with a tool is still a fool.


View Profile WWW
« Reply #51 on: April 12, 2013, 02:10:01 PM »

If you're seriously convinced it's a better experience to pause for a frame rather than skip rendering one frame, there's nothing else I can argue,
I am not sure what you mean since in my solution I use the closest possible input to the actual frame. It is your solution that is lagging behind, already by concept. We are talking about fixed-timestep. Every now and again a frame is delayed if your monitor runs with a higher refresh rate than the intended frame-rate, regardless how you manage your input. May be somewhere here is the error of reasoning you have?
« Last Edit: April 12, 2013, 02:18:59 PM by J-Snake » Logged

Independent game developer with an elaborate focus on interesting gameplay, rewarding depth of play and technical quality.<br /><br />Trap Them: http://store.steampowered.com/app/375930
Geti
Level 10
*****



View Profile WWW
« Reply #52 on: April 13, 2013, 01:48:05 AM »

You want to go on after a pause with the actual input, not with the previously buffered one. For some games it might be ok when they are often in a monotonous flow. Certainly not good for games where sudden changes of actions do matter.
Continuously poll input on a separate thread to your game logic.
Fwiw, we used buffered input in KAG, which is a multiplayer competitive game, and get no complaints from anyone about input delay, perceived, theoretical or otherwise.

This is getting very thoroughly off topic though.
Logged

kidchameleon
Level 1
*



View Profile WWW
« Reply #53 on: April 29, 2013, 02:28:58 PM »

Thanks for that, I'm going to try implement this tomorrow.
Logged
Pages: 1 2 [3]
Print
Jump to:  

Theme orange-lt created by panic