2025-07-18 22:34 CEST

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0004650Spring engineLuapublic2015-06-14 20:48
ReporterShadowfury333 
Assigned Tohokomoko 
PriorityurgentSeveritymajorReproducibilityalways
StatusclosedResolutionno change required 
Product Version98.0.1+git 
Target Version99.0Fixed in Version 
Summary0004650: Spring.SetCameraState() does not interpolate rotations correctly anymore
DescriptionWhen 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 ReproduceSet 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.
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files

-Relationships
related to 0004668resolvedjK issues with new camera mode 
+Relationships

-Notes

~0014047

msafwan (reporter)

Last edited: 2015-02-15 20:30

View 9 revisions

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.

~0014048

Shadowfury333 (reporter)

Last edited: 2015-02-15 21:10

View 2 revisions

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.

~0014090

abma (administrator)

does this bug still exist with spring develop >=98.0.1-398 ?

~0014091

Shadowfury333 (reporter)

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).

~0014092

abma (administrator)

no, last change related to camera was https://github.com/spring/spring/commit/9aa70d55d366841f5967570f615632fbc14f872f which is -387.

~0014100

Shadowfury333 (reporter)

Just checked, -398 does not fix the problem

~0014105

abma (administrator)

> Set camera to COFC

sorry, what is COFC?

~0014106

Shadowfury333 (reporter)

Combined Overhead/Free Camera. It's basically the engine's Free camera wrapped in Lua calls to be useful in regular play.

~0014153

msafwan (reporter)

Last edited: 2015-03-12 18:12

View 2 revisions

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.

~0014174

Shadowfury333 (reporter)

Last edited: 2015-03-15 21:35

View 2 revisions

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.

~0014183

msafwan (reporter)

Yea, the camera instantaneously rotate backward 360 degree like a spring.

~0014185

Anarchid (reporter)

Last edited: 2015-03-17 14:03

View 2 revisions

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.

~0014189

msafwan (reporter)

Last edited: 2015-03-18 14:16

View 2 revisions

setting CamTimeFactor=0 definitely fix all bug, but no smooth.

~0014195

jK (developer)

| 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

~0014196

Shadowfury333 (reporter)

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.

~0014197

Anarchid (reporter)

Last edited: 2015-03-18 20:57

View 2 revisions

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°.
```

~0014198

Shadowfury333 (reporter)

Last edited: 2015-03-19 02:46

View 5 revisions

*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.

~0014200

msafwan (reporter)

Last edited: 2015-03-22 03:09

View 5 revisions

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);

~0014201

msafwan (reporter)

Last edited: 2015-03-22 07:25

View 8 revisions

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.

~0014216

msafwan (reporter)

Last edited: 2015-03-23 09:25

View 10 revisions

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.

~0014217

Anarchid (reporter)

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.

~0014218

msafwan (reporter)

Last edited: 2015-03-23 13:40

View 9 revisions

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

~0014234

Shadowfury333 (reporter)

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.

~0014238

msafwan (reporter)

Last edited: 2015-03-26 12:12

View 7 revisions

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!

~0014241

jK (developer)

ever heard of math.modf ?

~0014242

msafwan (reporter)

Last edited: 2015-03-26 23:13

View 7 revisions

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.

~0014245

jK (developer)

all those if's could be replaced with a single math.modf ...
no wonder you moan such loud, when you code it extra large ...

~0014587

hokomoko (developer)

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.
+Notes

-Issue History
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
+Issue History