View Issue Details [ Jump to Notes ] | [ Issue History ] [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
---|---|---|---|---|---|---|---|---|---|
0004650 | Spring engine | Lua | public | 2015-01-19 06:06 | 2015-06-14 20:48 | ||||
Reporter | Shadowfury333 | ||||||||
Assigned To | hokomoko | ||||||||
Priority | urgent | Severity | major | Reproducibility | always | ||||
Status | closed | Resolution | no change required | ||||||
Product Version | 98.0.1+git | ||||||||
Target Version | 99.0 | Fixed in Version | |||||||
Summary | 0004650: Spring.SetCameraState() does not interpolate rotations correctly anymore | ||||||||
Description | When using Spring 98.0.1-265 or later, and possibly as far back as the major camera rewrite, calling Spring.SetCameraState() with anything set for rx, ry, or rz, after a previous SetCameraState() call with those parameters set, will cause those values to begin interpolating at the point they would have ended had the previous interpolation completed first. In earlier engines, the interpolation would start at the current angle and continue from there. | ||||||||
Steps To Reproduce | Set camera to COFC in a game that has it, then hold alt or ctrl and any arrow key. It helps if Settings/Camera Controls/Smoothness and Settings/Camera Controls/Rotation Speed are high. It also occurs with the Zero-K COFC when "Tilt Camera While Zooming" is on, as this uses the same SetCameraState() calls. | ||||||||
Tags | No tags attached. | ||||||||
Checked infolog.txt for Errors | |||||||||
Attached Files |
|
![]() |
|
msafwan (reporter) 2015-02-15 20:12 Last edited: 2015-02-15 20:30 |
When COFC calls SetCameraState() for 2nd time or 3rd time, or n-th time, COFC expect the Smoothness to start from current camera State and not calculated from (n-1)-th State. Because the smoothing motion take 1-5 second to actually finish while COFC will sending 2nd or 3rd SetCameraState() in within several GameFrame() to change the trajectory of the smoothing motion. |
Shadowfury333 (reporter) 2015-02-15 20:28 Last edited: 2015-02-15 21:10 |
To clarify the above, the expectation is that rotation starts from the current camera direction/position/rotation as it is on that frame, rather than the parameters given to the (n-1)'th State. This only manifests as an issue if the current "SetCameraState" call has not finished interpolating. |
abma (administrator) 2015-02-26 19:45 |
does this bug still exist with spring develop >=98.0.1-398 ? |
Shadowfury333 (reporter) 2015-02-26 20:25 |
I'll check in about 10 hours. I'm guessing something changed in -398, because IIRC the error was stil in -396 (I.e. 2 versions prior). |
abma (administrator) 2015-02-26 21:02 |
no, last change related to camera was https://github.com/spring/spring/commit/9aa70d55d366841f5967570f615632fbc14f872f which is -387. |
Shadowfury333 (reporter) 2015-03-01 02:21 |
Just checked, -398 does not fix the problem |
abma (administrator) 2015-03-02 18:50 |
> Set camera to COFC sorry, what is COFC? |
Shadowfury333 (reporter) 2015-03-02 19:06 |
Combined Overhead/Free Camera. It's basically the engine's Free camera wrapped in Lua calls to be useful in regular play. |
msafwan (reporter) 2015-03-12 18:12 Last edited: 2015-03-12 18:12 |
I have re-done some test, it appears that the actually cause for weird behaviour is because Spring completely ignore SetCameraState() if previous SetCameraState() wasn't finish. |
Shadowfury333 (reporter) 2015-03-15 21:34 Last edited: 2015-03-15 21:35 |
When trying to construct a lua-level workaround, I found another issue. When camState ry (rotation about y axis) is transitioning from 2*PI to 0, it takes the long way. To reproduce, rotate the camera (use COFC, use ctrl+arrow keys) across due south. The camera will always rotate a full circle to arrive at its destination, rather than travelling a few degrees. |
msafwan (reporter) 2015-03-17 09:21 |
Yea, the camera instantaneously rotate backward 360 degree like a spring. |
Anarchid (reporter) 2015-03-17 14:02 Last edited: 2015-03-17 14:03 |
Most of diagnostics here are probably wrong. I'm not sure interpolation now starts from endpoint of previous interpolation. I've double checked the code, and even compiled a version modified so that i was 100% sure the new ipo started from an interpolated position and not an endpoint. I'm also pretty sure that new interpolations are *not* ignored before a preexisting ipo is completed. I've built a version modified so that would be the case, and the behaviour was completely different. My own suspicion now is with the change of camera interpolation to work on euler rotations instead of direction vectors. That also explains the rotation singularity above because the code still uses mix() to interpolate from 359 degrees to 0 and mix() doesn't know that degrees end after 359. However, selectively reverting that change didn't make the bug go away. Perhaps i somehow mis-merged the revert (git refused to do it cleanly), or this is just adding another failed hypothesis to the pile above... This issue is nasty because it's not possible to cleanly bisect it. A lot of commits around the suspected breakage point compile to even more broken builds, e.g. ones where camera is constantly stuck on ground and cannot be unstucked by any force known to man up to and including SetCameraState. |
msafwan (reporter) 2015-03-18 14:16 Last edited: 2015-03-18 14:16 |
setting CamTimeFactor=0 definitely fix all bug, but no smooth. |
jK (developer) 2015-03-18 19:05 |
| When trying to construct a lua-level workaround, I found another issue. When camState ry (rotation about y axis) is transitioning from 2*PI to 0, it takes the long way. To reproduce, rotate the camera (use COFC, use ctrl+arrow keys) across due south. The camera will always rotate a full circle to arrive at its destination, rather than travelling a few degrees. -> bug in your code, the engine gives you the possibility to access both rotations always limiting it to the short one would be a reduction in features |
Shadowfury333 (reporter) 2015-03-18 20:17 |
First off, that's not "my code". That rotation singularity occurs regardless of whether I have my workaround in there. All it needs is: local cs = Spring.GetCameraState() cs.ry = cs.ry + delta Spring.SetCameraState(cs, time) That's it. That seems to be the most straightforward way to rotate the camera based on user input, and it's how things have worked for years, and now it is broken when going below 0 or above 2*PI. If this isn't supposed to work anymore, we need to know what to do instead. Regardless, that's a secondary bug, one I mentioned because it might help pinpoint the problem. |
Anarchid (reporter) 2015-03-18 20:57 Last edited: 2015-03-18 20:57 |
Apparently the 'lua code bug' is described as follows: ``` When setting camera state with nonzero smoothness, Lua code should pay attention whether the interpolation would happen to cross zero degrees on any axis. If in such a case the short interpolation path is desired, the target rotation should be inverted. E.g. when setting a camera state to 359° rotation along y-axis while previous state is 1° along y-axis, lua coders desiring a short path interpolation are expected to pass "-1°" as target rotation intead of 359°. ``` |
Shadowfury333 (reporter) 2015-03-18 22:00 Last edited: 2015-03-19 02:46 |
*Bangs head repeatedly on desk* You'd think because I read the engine forums that breaking changes like this would be something I'd hear about. Also, jK, this isn't choosing, it's guessing. SetCameraState uses the shortest path except when going above 2*pi or below 0. So now everyone who uses Free Camera has to make sure they have some method in their code to catch that case and every edge case around it (and has to both know to do this and know how), then hope that the domain remains [0,2*pi) and never becomes, say, [-pi,pi). Alternatively, SetCameraState could always take the shortest path (as it did before this massive camera change), and if someone wants to take the long way, they can fairly easily split that into multiple <180° rotations. The only time this would happen is for cinematics, so micromanaging camera position is already going to be happening there. That way there is an actual choice. Regardless, that's not the issue this report is about. |
msafwan (reporter) 2015-03-22 03:04 Last edited: 2015-03-22 03:09 |
After several days of trying, I managed to compile spring on windows and added some echo here: https://github.com/spring/spring/blob/develop/rts/Game/Camera.cpp#L262 turn out there might be some "race condition" issues or unintended sequence of event that changes the camera rotation correctly but then reset it back Here is echo of rot.x when telling COFC to rotate camera: 2.678960 <-changes 2.683947 <-reset 2.678952 <-changes 2.683947 <-reset 2.678943 <-changes 2.683947 <-reset 2.678935 <-changes 2.683947 <-reset 2.678926 <-changes 2.683947 <-reset 2.678917 <-changes 2.683947 <-reset 2.678909 <-changes 2.683947 <-reset 2.678900 <-changes 2.683947 <-reset 2.678892 <-changes 2.683947 <-reset echo code: char myCharPointer[20]; sprintf(myCharPointer, "%f", rot.x); LOG(myCharPointer); |
msafwan (reporter) 2015-03-22 07:18 Last edited: 2015-03-22 07:25 |
An update on test: it turn out to be very severe bug! regardless of the value of this variable: https://github.com/spring/spring/blob/develop/rts/Game/Camera.cpp#L263 the engine actually Fail to render the rotation to the screen. A test in COFC such as, holding "Right Arrow + Left Ctrl", will make the camera move in an orbit but the screen didn't rotate*. This indicate positional effects working but the rotational effect stuck. *this is at least true in my tweaked Spring. |
msafwan (reporter) 2015-03-23 09:06 Last edited: 2015-03-23 09:25 |
I found out the cause.... Its the interpolation formula not independent of framerate, a design problem. Its run every draw frame, and the equation decay in strength as time passes, if the framerate is low, then your angle changes is low, if your framerate is high then your angle change is almost perfect, but I have no idea what's "perfect" delta-time anyway.... This equation: deltaAngle = (diffFromTarget)*(1.0 - fractionOfTimePassed^ 4) it look like this: (Amount of changes) ^ |>>>>>> |......>>>>>> |............>> |..............> |...............> |-----------------> (fractionOfTimePassed) if your interpolation frame only happen at 2 or 5 places out of 10000million points, then your angle change is always incomplete. |
Anarchid (reporter) 2015-03-23 09:58 |
xponen: This is the interpolation code from before it stuttered: https://github.com/spring/spring/blob/3773cdbcf4a0399f6d23ebe36de459b3da83a8d0/rts/Game/CameraHandler.cpp#L147 Your hypothesis is disproven. |
msafwan (reporter) 2015-03-23 13:27 Last edited: 2015-03-23 13:40 |
Okay, you are right. changing SetFov() to "forward" did fixed the rotation bug I experienced, but I don't think Spring will ever be as smooth as 91 ever. So I'm abandoning attempt to debug/fix smooth. It might be too hard to do! I'm thinking COFC need to use FreeCam's native smooth function. This involve setting FreeCam's vx,vy,vz (velocity) and this allow FreeCam to simulate acceleration & deacceleration of camera position, which really look like smooth. Its going to be challenging to calculate correct velocity & camera motion, but will work better than 91 if done right, hopefully |
Shadowfury333 (reporter) 2015-03-25 05:25 |
NB: The SmoothCam widget (camera_smoothCam.lua) masks the due south singularity but seems to worsen (or at least prevent working around) the other interpolation issues. |
msafwan (reporter) 2015-03-26 12:00 Last edited: 2015-03-26 12:12 |
Yay, I found the duplicate camera call in engine which cause the jitter, here is the first call: https://github.com/spring/spring/blob/develop/rts/Game/Game.cpp#L1116 here is second call https://github.com/spring/spring/blob/develop/rts/Game/Game.cpp#L1218 I commented the 2nd call and my Spring no longer jitter when COFC is operating, but minor complication: the map is oriented sideways/wrongly, this core Spring dev [LCC]jk could fix IMO. the duplicate also broke COFC hotkey (eg: if press arrow key, COFC tell camera to move but the Engine camera want to turn because both is using same key). Removing it fix it. For the south singularity, here is my algo for fixing it: https://github.com/xponen/Zero-K/blob/fix_COFC_interpolation/LuaUI/Widgets/COFCtools/Interpolate.lua#L37-L88 hopefully [LCC]jk can use as reference! |
jK (developer) 2015-03-26 17:09 |
ever heard of math.modf ? |
msafwan (reporter) 2015-03-26 22:43 Last edited: 2015-03-26 23:13 |
math.modf or not, doesn't matter, the code have to decide to rotate left or right, decision is "if/else" not equations. Also, no way to simplify a 1 liner any further, I wrote: "currentAngle = currentAngle + / - fullCircle" can't be any shorter it look messy because I repeat it 3x, 1 for each angle. |
jK (developer) 2015-03-27 08:37 |
all those if's could be replaced with a single math.modf ... no wonder you moan such loud, when you code it extra large ... |
hokomoko (developer) 2015-06-14 20:48 |
There are two issues here: 1) FreeController.cpp contains its own interpolation so it doesn't play well with CameraHandler's one. 2) Rotating using the shortest angle is not a good idea because it's limiting. Since there's working lua code and after talking to the reporter I'm closing this. Spring may benefit from having a "dummy controller" that will play more nicely with lua than the free controller. If there's demand I'll implement this after 99.0. |
![]() |
|||
Date Modified | Username | Field | Change |
---|---|---|---|
2015-01-19 06:06 | Shadowfury333 | New Issue | |
2015-01-19 20:07 | abma | Target Version | => 99.0 |
2015-02-11 10:21 | abma | Relationship added | related to 0004668 |
2015-02-15 20:12 | msafwan | Note Added: 0014047 | |
2015-02-15 20:13 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:14 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:15 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:17 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:20 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:21 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:26 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 20:28 | Shadowfury333 | Note Added: 0014048 | |
2015-02-15 20:30 | msafwan | Note Edited: 0014047 | View Revisions |
2015-02-15 21:10 | Shadowfury333 | Note Edited: 0014048 | View Revisions |
2015-02-26 19:45 | abma | Note Added: 0014090 | |
2015-02-26 19:45 | abma | Status | new => feedback |
2015-02-26 20:25 | Shadowfury333 | Note Added: 0014091 | |
2015-02-26 20:25 | Shadowfury333 | Status | feedback => new |
2015-02-26 21:02 | abma | Note Added: 0014092 | |
2015-03-01 02:21 | Shadowfury333 | Note Added: 0014100 | |
2015-03-02 18:50 | abma | Note Added: 0014105 | |
2015-03-02 19:06 | Shadowfury333 | Note Added: 0014106 | |
2015-03-12 18:12 | msafwan | Note Added: 0014153 | |
2015-03-12 18:12 | msafwan | Note Edited: 0014153 | View Revisions |
2015-03-15 21:34 | Shadowfury333 | Note Added: 0014174 | |
2015-03-15 21:35 | Shadowfury333 | Note Edited: 0014174 | View Revisions |
2015-03-17 09:21 | msafwan | Note Added: 0014183 | |
2015-03-17 14:02 | Anarchid | Note Added: 0014185 | |
2015-03-17 14:03 | Anarchid | Note Edited: 0014185 | View Revisions |
2015-03-18 14:16 | msafwan | Note Added: 0014189 | |
2015-03-18 14:16 | msafwan | Note Edited: 0014189 | View Revisions |
2015-03-18 19:05 | jK | Note Added: 0014195 | |
2015-03-18 20:17 | Shadowfury333 | Note Added: 0014196 | |
2015-03-18 20:57 | Anarchid | Note Added: 0014197 | |
2015-03-18 20:57 | Anarchid | Note Edited: 0014197 | View Revisions |
2015-03-18 22:00 | Shadowfury333 | Note Added: 0014198 | |
2015-03-18 22:01 | Shadowfury333 | Note Edited: 0014198 | View Revisions |
2015-03-19 02:43 | Shadowfury333 | Note Edited: 0014198 | View Revisions |
2015-03-19 02:44 | Shadowfury333 | Note Edited: 0014198 | View Revisions |
2015-03-19 02:46 | Shadowfury333 | Note Edited: 0014198 | View Revisions |
2015-03-22 03:04 | msafwan | Note Added: 0014200 | |
2015-03-22 03:04 | msafwan | Note Edited: 0014200 | View Revisions |
2015-03-22 03:06 | msafwan | Note Edited: 0014200 | View Revisions |
2015-03-22 03:07 | msafwan | Note Edited: 0014200 | View Revisions |
2015-03-22 03:09 | msafwan | Note Edited: 0014200 | View Revisions |
2015-03-22 07:18 | msafwan | Note Added: 0014201 | |
2015-03-22 07:19 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-22 07:20 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-22 07:21 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-22 07:22 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-22 07:22 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-22 07:24 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-22 07:25 | msafwan | Note Edited: 0014201 | View Revisions |
2015-03-23 09:06 | msafwan | Note Added: 0014216 | |
2015-03-23 09:06 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:07 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:14 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:19 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:19 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:20 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:24 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:25 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:25 | msafwan | Note Edited: 0014216 | View Revisions |
2015-03-23 09:58 | Anarchid | Note Added: 0014217 | |
2015-03-23 13:27 | msafwan | Note Added: 0014218 | |
2015-03-23 13:31 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:32 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:33 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:34 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:35 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:35 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:40 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-23 13:40 | msafwan | Note Edited: 0014218 | View Revisions |
2015-03-25 05:25 | Shadowfury333 | Note Added: 0014234 | |
2015-03-26 12:00 | msafwan | Note Added: 0014238 | |
2015-03-26 12:01 | msafwan | Note Edited: 0014238 | View Revisions |
2015-03-26 12:07 | msafwan | Note Edited: 0014238 | View Revisions |
2015-03-26 12:07 | msafwan | Note Edited: 0014238 | View Revisions |
2015-03-26 12:08 | msafwan | Note Edited: 0014238 | View Revisions |
2015-03-26 12:10 | msafwan | Note Edited: 0014238 | View Revisions |
2015-03-26 12:12 | msafwan | Note Edited: 0014238 | View Revisions |
2015-03-26 17:09 | jK | Note Added: 0014241 | |
2015-03-26 22:43 | msafwan | Note Added: 0014242 | |
2015-03-26 22:45 | msafwan | Note Edited: 0014242 | View Revisions |
2015-03-26 22:56 | msafwan | Note Edited: 0014242 | View Revisions |
2015-03-26 23:07 | msafwan | Note Edited: 0014242 | View Revisions |
2015-03-26 23:11 | msafwan | Note Edited: 0014242 | View Revisions |
2015-03-26 23:12 | msafwan | Note Edited: 0014242 | View Revisions |
2015-03-26 23:13 | msafwan | Note Edited: 0014242 | View Revisions |
2015-03-27 08:37 | jK | Note Added: 0014245 | |
2015-06-14 20:48 | hokomoko | Note Added: 0014587 | |
2015-06-14 20:48 | hokomoko | Status | new => closed |
2015-06-14 20:48 | hokomoko | Assigned To | => hokomoko |
2015-06-14 20:48 | hokomoko | Resolution | open => no change required |