Why Your Framerate Affects Jumping

 The information that follows was posted by Coriolis in the Quake3World General Discussion forum threads Why your framerate affects jumping! and The DEFINITIVE fps physics post. The posts explain how your FPS affects the 'jump' physics of Quake3 . Note that these do not apply when you are using the new 125HZ modification released 18.09.2000 and incorporated into OSP and Q3COMP. Any 1.27g or above server that has 125 Hz enabled server side is also not subject to the FPS physics issue. By default however 1.27g is set to disable 125 Hz server side. Thankyou to Coriolis for giving us permission to include this information. =)

 Coriolis Mutant Posts: 2417 Registered: Dec 1999 posted 04-26-2001 07:46 AM                Warning: Long / mathematical post, with pictures. Well, I dived into the source code to see why your frame rate would affect how high / far you can jump. I will define "wu" as quake3 world units. From the source code, I got the following constants: Gravity = 800 wu / s2 Run velocity = 320 wu / s Jump velocity = 270 wu / s Quake3 has to model your velocity as a piecewise linear approximation to the actual curve, due to limited knowledge. Specifically, it doesn't know if you are going to hit a wall / missile / other player, or if you are going to use air acceleration to change directions. This means it cannot precalculate your entire path and just move you along it; it has to see what direction you are currently going and move you along that direction for a single time step. The time step (in seconds) is approximately 1 / frame rate. Time step is always less than 0.066 seconds. I also found that, if g_syncronousClients is 0, the server uses the client's frame rate to get the time step for predicting the client's movement! This is probably to ensure consistency between client and server. It is crucial for frame-rate dependent jumps to work. Recall from physics that gravity is an acceleration. It works on your z velocity vector. Quake3 uses the average vertical velocity over a time step, accounting for the change in velocity between the start and the end of the time step due to gravity. There is no cap on vertical velocity that I could see; air is frictionless, so you have no terminal velocity. Anyway, I simulated this using floating point arithmetic. The result is depicted in the following picture: Black = ideal trajectory Red = 120 fps Green = 100 fps Yellow = 85 fps Blue = 80 fps Purple = 60 fps Cyan = 40 fps White = 15 fps As you can see, each trajector follows the ideal curve almost exactly. This is not quite what I expected. Then I realized that space in the quake3 world is discrete rather than continuous, so I repeated the experiment, this time clamping to integer values. Using the same settings, I got these results: So, the framerate dependency comes from two factors: 1) Approximating the actual continuous function with a piecewise linear function. 2) Round-off error. There is no way around either of these factors. The only thing you can do is make the time step a constant, but that would complicate the client-side rendering. Okay, I stop typing now. Edit: Made the second picture actually the second picture. [This message has been edited by Coriolis (edited 04-26-2001).]

 Coriolis Wise Guy Posts: 4159 Registered: Dec 1999 posted 08-21-2001 10:55 PM                WARNING: EXTREMELY long post with only 1 smiley -- but it's worth it, as I answer pretty much every physics / FPS question in quake 3. Earlier this evening, Ctrl told me that he was dissatisfied with my previous explanation of why your fps affects jumping. So, I did some more research. Specifically, I wrote a mod to measure your jumping. Here are the key points that I discovered: (1) The final velocity vectors are clamped to integers every time the player movement code is called. This gets called once per frame for fast clients, but never less than 20 times per second. (2) This conversion is done by the equation (int)x, where "x" is a floating point value. (3) The integer conversion done by the Q3 vm *IS NOT ANSI COMPLIENT*. ANSI C specifies that integer conversion is done by ignoring the fraction. The Q3 vm does it by rounding to the nearest integer. This third point explains exactly why DLL's have slower speeds and jump heights than QVM's. In a QVM, the rounding is to nearest integer, so errors will tend to cancel out. In a DLL, rounding is always towards 0, so errors always reduce your speed and will always accumulate. The rounding error in a DLL always acts as extra friction. I expect you can get around this problem in DLL's by rewriting the "SnapVector" macro to emulate the QVM's rounding method. Now, back to the jumps. In theory, the rounding errors should cancel out over the number of frames in a typical jump. This assumes that the fraction can be any value with equal probability. However, in practice, this is not the case. Each frame tends to be the same time as the previous one. The change in velocity is the acceleration times the frame time. Acceleration is due to gravity, and is therefore constant. Frame time is also nearly constant, so the change in velocity is also nearly constant in each frame. Since velocity always starts as an integer, and the change is always nearly the same, under a constant fps rounding has nearly the same error each frame. With a constant frame rate, Q3's rounding errors will tend to accumulate. For some frame rates, this will always round down; for others, it will always round up. Based on this, the ideal frame rate for jumping distance is the highest one your computer can maintain that gets a fraction remainder near 0.5, but always greater than 0.5. Q3's gravity is 800, so you want the fractional part of 800/fps to be greater than 0.5. To protect against frame rate fluctuations, you'd also want nearby frame rates to have fractions greater than 0.5. Lastly, you want there to be as many frames as possible, so that the most possible positive error gets accumulated. This chart gives (1) fps, (2) remainder of 800 / fps, (3) number of frames in 0.675 seconds, (4) maximum positive accumulated error in 0.675 seconds. The table was generated for all frame rates from 20 to 200 fps. code: 23 0.78 15 3.26 26 0.77 17 3.92 27 0.63 18 6.67 28 0.57 18 7.71 29 0.59 19 7.86 30 0.67 20 6.67 31 0.81 20 3.87 34 0.53 22 10.35 35 0.86 23 3.29 37 0.62 24 9.08 39 0.51 26 12.67 41 0.51 27 13.17 43 0.60 29 11.47 45 0.78 30 6.67 48 0.67 32 10.67 51 0.69 34 10.67 54 0.81 36 6.67 55 0.55 37 16.82 58 0.79 39 8.07 59 0.56 39 17.19 62 0.90 41 3.97 63 0.70 42 12.67 67 0.94 45 2.69 68 0.76 45 10.59 69 0.59 46 18.67 73 0.96 49 2.01 74 0.81 49 9.27 75 0.67 50 16.67 76 0.53 51 24.16 81 0.88 54 6.67 82 0.76 55 13.41 83 0.64 56 20.24 84 0.52 56 26.67 89 0.99 60 0.67 90 0.89 60 6.67 91 0.79 61 12.74 92 0.70 62 18.87 93 0.60 62 24.67 94 0.51 63 30.83 101 0.92 68 5.39 102 0.84 68 10.67 103 0.77 69 16.08 104 0.69 70 21.54 105 0.62 70 26.67 106 0.55 71 32.15 115 0.96 77 3.35 116 0.90 78 8.07 117 0.84 78 12.67 118 0.78 79 17.41 119 0.72 80 22.18 120 0.67 81 27.00 121 0.61 81 31.46 122 0.56 82 36.30 123 0.50 83 41.16 134 0.97 90 2.69 135 0.93 91 6.74 136 0.88 91 10.71 137 0.84 92 14.77 138 0.80 93 18.87 139 0.76 93 22.75 140 0.71 94 26.86 141 0.67 95 30.99 142 0.63 95 34.79 143 0.59 96 38.94 144 0.56 97 43.11 145 0.52 97 46.83 161 0.97 108 3.35 162 0.94 109 6.73 163 0.91 110 10.12 164 0.88 110 13.41 165 0.85 111 16.82 166 0.82 112 20.24 167 0.79 112 23.47 168 0.76 113 26.90 169 0.73 114 30.36 170 0.71 114 33.53 171 0.68 115 36.99 172 0.65 116 40.47 173 0.62 116 43.58 174 0.60 117 47.07 175 0.57 118 50.57 176 0.55 118 53.64 177 0.52 119 57.15 The C++ code to generate the above table is code: #include int main(int argc, char* argv[]) { for( int i=20; i<300; i++ ) { double f = 800.0 / i; int ipart = (int)f; double fpart = f - ipart; if( fpart > 0.5f ) { printf( "%3d %.2f %3d %6.2f\n", i, fpart, (int)(i * .675), (1.0-fpart) * (int)(i*.675) ); } } return 0; } Matching our conditions with the table, we predict that the best frame rates would be about 29, 41, 83, 92, 120, 140, and 170. Notice that these numbers are very near the values that people have found experimentally. This match between theory and experience lends credence to the model used. .......... Coriolis Wise Guy Posts: 4159 Registered: Dec 1999 posted 08-25-2001 11:04 PM                I've done some more thinking :O Q3 measures frame time in an integer number of milliseconds. This means that there are only certain frame rates that it can hit... specifically, frame rates of 1000 / N, where N is an integer number of milliseconds. Given this, you can find viable frame rates by varying N. So, the possible frame rates are: 200 166-167 142-143 125 111-112 100 90-91 83-84 76-77 71-72 66-67 62-63 58-59 55-56 52-53 50 47-48 45-46 43-44 41-42 40 38-39 37-38 35-36 34-35 33-34 32-33 31-32 30-31 29-30 28-29 27-28 26-27 25-26 25 24-25 23-24 22-23 21-22 20-21 20 The lines with multiple numbers are ones that do not evenly divide 1000, so for example you cannot exactly hit 142 or 143 fps but must toggle between them. So, when testing values for com_maxfps, these are the only numbers it really makes sense to try: 200 166 142 125 111 100 90 83 76 71 66 62 58 55 52 50 47 45 43 40-41 37-38 20-35