godot
godot copied to clipboard
[3.x] 2D Fixed Timestep Interpolation
Adds support to canvas items, canvas lights, canvas light occluders and Camera2D.
Notes
- No support yet for scene side
get_global_transform_interpolated()
, probably leave for another PR - No explicit support yet for particles, especially global particles (this may be for a later PR)
- On / off per node is handled by the same
InterpolationMode
as 3D - In order to sensibly interpolate detect sprite flips there is some extra interpolation code in
TransformInterpolator
- Switch off by default in GUI
Controls
-
reset_physics_interpolation()
support as in 3D - Adds
canvas_item_transform_physics_interpolation()
to allow origin shifting techniques - Slightly moves part of the 3D interpolation code to
iteration_prepare()
for consistency with 2D. I think this should be okay, but if there are any regressions it's easy to move back. - Compatible with hierarchical culling - hierarchical culling uses combined AABB of previous and current ticks
Hi - for me the FTI for 2D is the single most expected feature in the 3.x release management cycle.
It looks however that it is waiting for the 2D hierarchy culling (https://github.com/godotengine/godot/pull/68738) to be sorted out and all the visibility gymnastics with related VisibilityEnabler2D optimizations, which in turn was tentatively merged in the last beta then reverted, so I believe there are genuine issues with need more attention.
What I don't quite understand is why FTI for 2D is depending on that hierarchy culling / visibility stuff. The latter for me is only in the performance optimisation domain, while FTI for 2D is in the functional domain. FTI shall work no matter how far we optimize or not canvas visbility. Could someone sched some light on this dependency? @lawnjelly ?
This is just a thumbs up of an incredible work & feature (FTI for 2D) that @lawnjelly has put in place and which needs to go through the usual code maturation process and be included in 3.6 betas before the stable release. The visibility stuff comes in the way of that process and I confess I don't quite see the reason for it.
Could you please clarify what's the current plan of action to move forward with this feature?
Thanks.
The latter for me is only in the performance optimisation domain, while FTI for 2D is in the functional domain.
Efficient 2D interpolation is highly linked with culling. It wouldn't be good to merge something then have to rewrite it / wait months for re-review to work with different culling methods.
Could you please clarify what's the current plan of action to move forward with this feature?
Wait for review. @clayjohn has already mostly reviewed hierarchical culling but just has to check the latest changes, then we will get to interpolation. Progress on features for 3.x is slow currently as there are only a few maintainers familiar with these parts of the engine, and most are working on 4.x. Normally I would review PRs in these areas, but I can't review my own. :slightly_smiling_face:
If you want to help, then downloading and testing the artifacts for #76252 and this PR will be hugely beneficial (although I've just seen they have expired, which isn't helpful lol). Having someone independently checking for regressions, and checking it works in their projects, or reporting any problems (so I can fix, or change approach slightly as required), makes it far easier for maintainers to confidently approve PRs.
You can also test my feature fork which is specifically designed for previewing all this stuff, and has many of the 3.6 features I'm working on before we get them into core: https://github.com/godot-plus/godot-plus (It's actually due a new release, but my dev PC blew up last week, so waiting until I have new machine!)
Will need a rebase now hierarchical culling is merged, I'll do this when up and running again (but is still possible to look through now).
It's a while since I wrote but one area I would like to improve (likely in a later PR) is the culling. At the moment this merges the previous and current AABB from each two adjacent ticks, with the anticipation that in most circumstances, the interpolated AABB will be between the two. However there may be exceptions with some rotations (particularly where pivots are involved), where the AABB moves outside the merged AABB, so I'm intending to look into this.
If possible I would like to avoid recalculating the AABB on every frame - which would always be correct, but stress the calculations of the AABB and the hierarchical culling unnecessarily. Consider that running at e.g. 30tps and 300fps, we would be doing 10x as many of these calculations as necessary.
I tested this PR locally with https://github.com/Calinou/platshoot/tree/physics-interpolation-test. The basic functionality works well, but I noticed a few issues – see the videos below.
- Camera2D smoothing is much slower with physics interpolation enabled. I'm rendering the game at 120 FPS, and it seems to be roughly 6 times slower when the game's physics tick rate is 20 Hz. This hints at camera smoothing using the wrong delta.
- Particles that use global coordinates move around erratically if the player also moves, such as the jetpack particles when holding Shift.
- Particles suddenly snap into position when firing a bullet, which doesn't occur when interpolation is disabled. This may be a scripting error on my end, but I don't get any warnings despite the interpolatino warnings being enabled (not sure if it's possible for this case to be detected).
Physics FPS is set to 20 in the project (lower values cause frequent player tunneling with the tiles).
No interpolation
https://github.com/godotengine/godot/assets/180032/2a5bcf93-7daa-41ad-b0d2-c7505404ab40
With interpolation
https://github.com/godotengine/godot/assets/180032/95868eab-b9d0-4bbd-befe-6347aebcbc72
Camera2D smoothing is much slower with physics interpolation enabled. I'm rendering the game at 120 FPS, and it seems to be roughly 6 times slower when the game's physics tick rate is 20 Hz. This hints at camera smoothing using the wrong delta.
I'll take a look, I didn't explicitly test the camera smoothing.
Particles that use global coordinates move around erratically if the player also moves, such as the jetpack particles when holding Shift.
This is kind of expected, I spent quite a bit of time on the 3D interpolation rewriting the global particles (more than half the time I spent developing). I haven't touched the global 2D particles at all yet, working on the principle of having something working would be better than nothing at all to get users started. For global particles each particle needs to be interpolated individually if tick based, and a framework needs to be added to support this. (This is also incidentally the reason why I've been taking a while adding interpolation to 4.x, because particles is a bag of worms, and the implementation was in flux in master at the time).
I'll have a look at the 2D particles and see if they can be fixed up in a similar manner to 3D, but it might make sense for a second PR (I'll make this clear in the PR description that particles are not yet converted).
By the way, I ported another project if you need more ways to test it: https://github.com/Calinou/escape-space/tree/physics-interpolation-test
I had a little look at the issue with the camera smoothing being slower with interpolation switched on. The reason is that in the "platshoot" demo project above, the camera process mode is set to idle
, and with interpolation, get_camera_transform()
(which rather confusingly also does the smoothing) is only being called on physics ticks, because this drives the system of recording the previous and current transforms required for interpolation.
I'm not currently sure whether it makes any sense to try and apply / support smoothing per frame with interpolation on. At best you would get some kind of double smoothed "blancmange". It is doable with some rather more complex logic, but I'm not sure it makes any sense. :thinking:
I suspect the best way of fixing this (at least until we get further feedback / some ideas how this might be useable) is to just emulate the physics process mode when interpolation is switched on. We could add e.g. a WARN_PRINT_ONCE
that it is acting in physics process mode.
Smoothing at idle when using interpolation would also likely cause stutters, because of the same reason in 3D we recommend get_global_transform_interpolated()
for manual smoothing - the target will likely only be moving once per tick.
Actually the way Camera2D
currently does smoothing in get_camera_transform()
seems like a bug waiting to happen. Presumably if you are smoothing, and you call it multiple times from gdscript during a frame / tick, you will get a different result each time, and it will throw off the regular smoothing. :confused:
UPDATE:
Ok I've now changed it to use the physics delta for updating the smoothing when interpolation is active (so the rate of smoothing should be the same as in PROCESS_MODE_PHYSICS
). There is also a WARN_PRINT_ONCE
if this override has to be used (when TOOLS_ENABLED
), to alert the user that their selected PROCESS_MODE_IDLE
will be overridden.
@lawnjelly TMI :-)
As far as I understand, what @Calinou did is enabling the FTI setting in existing projects “as is” to use FTI, which resulted in slower camera updates and particle issues.
If I get it correctly, your analysis highlights that the default Camera2D process mode is CAMERA2D_PROCESS_IDLE, which is no good for FTI, so it shall be changed to CAMERA2D_PROCESS_PHYSICS, which is not the default for Camera2D, in order to make the camera updates work as expected with FTI. So what you did is:
- Verified that with CAMERA2D_PROCESS_PHYSICS the Camera2D updates are OK for the said projects
- Consequently, introduced changes to force the CAMERA2D_PROCESS_PHYSICS when FTI is on
- Added a warning that the default processing mode is overridden from IDLE to PHYSICS under the hood when FTI is on
Did I get it right?
If so, this looks like a sensible approach for an automated switch to FTI for Camera2D, but the bottom line is that FTI is a physics process mechanism so there is no perfect solution with the default node settings without manual adjustments.
And I guess particles suffer from the same syndrome and consequently shall be subjected to the same automated switch to physical processing instead of the idle processing which is also the default for particles.
All in all, enabling FTI looks like a can of worms at this point, messing with the nodes under the hood. I am not very comfortable with this approach. Instead of internal overrides, I’d prefer having the physics interpolated system function goodies to be available at the user level so that I can use them in my manual, explicit switch to FTI for the nodes of my own choice. Not sure this makes any sense, but I generally dislike black magic :-)
As far as I understand, what @Calinou did is enabling the FTI setting in existing projects “as is” to use FTI, which resulted in slower camera updates and particle issues.
Indeed, I didn't make any manual changes (other than removing the smoothing add-on which both projects previously used, and changing the node structure accordingly).
For the bullets, "platshoot" could potentially be improved with a little trick that I need to add to the docs for 3D:
bullet.position = bullet_position
add_child(bullet)
bullet.get_node("RigidBody2D").linear_velocity = bullet_velocity
# Trick for bullet start
bullet.reset_physics_interpolation()
bullet.position = bullet_position + (bullet_velocity * bullet.get_physics_process_delta_time())
Normally when adding a new object to the scene you add it and call reset_physics_interpolation()
. This works for most things like characters, but for moving bullets, it causes a problem - the added object stays glued to the same spot for the first physics tick, because the previous and current transforms are identical.
In order to create a bullet "in flight":
- add the bullet in the initial position
- call
reset_physics_interpolation()
so the previous and current transforms are both the initial position - then set the position to what you expect it to be after the first tick (in this case by applying the linear velocity for the delta expected in that first tick). This means "T0" will be the initial position, and "T1" the position after a tick, and it will begin moving between these two right away.
This means the bullet is to some extent "ahead" of itself, but can make the visuals look nicer. The only thing is you need to be aware that the bullet will likely tunnel through anything it would have hit in that first tick, because as far as the physics is concerned, it is starting at "T+1".
Another alternative is to hide the bullet for the first tick, but this can make the input feel laggy.
@lawnjelly OK - I took the time to review the code changes in detail. Overall things are looking quite good and I am slowly starting to digest the idea of forcing the Camera2D mode to physics for the current camera only but I am still not convinced this is the right thing to do. BTW shouldn't the tools related warning also include a is_current()
check ?
The main question here is whether the forced switch to physics process for the current Camera2D is approproate or not. Let's dive into this a bit, the other changes related to canvas, light & occluder and associated logic in VisualServer being fine IMO.
Firstly, if we force the current Camera2D to physics processing in the engine as it is done now when FTI is on, there is no escape from it. This contradicts the current FTI tutorial, especially the section about manual interpolation of the Camera. I could argue that the FTI tutorial is fine and there is no need to force things on me, me being the current Camera2D where I have plugged custom logic in my _process()
and _physics_process()
functions. If I know what I am doing by using FTI, I will take care to manually switch my Camera2D to physics processing. The tools waring is enough for all cameras in my project which are left with the default idle processing.
Secondly, this forced switch is not done for the (3D Interpolated)Camera while everything suggests that we have the same situation there. Hence there is a functional discrepancy at the moment between the 2D and 3D cameras - the 2D is forced to physics, the 3D is not. This misalignment left me with a sense of an over- or un-accomplished half, either 2D or 3D.
I guess I'd like to hear more arguments on why we are forcing the Camera2D mode to physics in the engine, instead of keeping the current strategy of highligting the FTI feature in the docs. The latter suggest clearly that most of the logic shall move to physics processing and the camera processing adjusted accordingly. The tool warning for the Camera2D shall remain, but people would need to manually change the processing mode to physics to benefit from FTI instead of forcing it like it is done now.
In short, I am not positive that we can transition existing projects smoothly to FTI with only one click on the option enabling it, but I understand the status quo as an effort to achieve this noble goal.
The rest looks okay with obvious complications (like xform => xform_prev/_next) but it looks good to me and obviously this would need more testing in the next betas.
@oeleo1 I did struggle to understand your points, but am I right in thinking you are suggesting Camera2D
should not use fixed timestep interpolation unless changed to physics process mode
manually?
Note that as with 3D, interpolation can be turned on and off individually for all nodes / cameras / branches of the tree using the InterpolationMode
property.
If my guess at your meaning was correct - the problem is that having a Camera2D
in interpolated mode, but not interpolating, is itself a source of confusion and will leave users scratching their heads. If idle process mode
prevents camera interpolation, then users have to ensure TWO things are switched on for it to work.
Additionally, the source code already has functions like is_physics_interpolated_and_enabled()
(some already bound to gdscript and thus compatibility is important - we want the function to do what it says essentially) and having an additional check for process mode would be confusing, versus just overriding the process mode, as the process mode setting effectively becomes redundant when interpolation is in use for the camera.
Bear in mind we strive to make things easiest for majority of users / beginners, who will likely just want to turn on interpolation and have everything interpolated (objects and cameras) without worrying about process modes, even if this comes at the cost of some more advanced case.
Note that this refers to the PR as is. This is all subject to change and may well be changed with follow up PRs depending on regressions etc.
BTW shouldn't the tools related warning also include a is_current() check ?
The warning is WARN_PRINT_ONCE
(and only for interpolated cameras), meaning it prints once, no matter how many times it occurs, I'm not sure there is any value to adding a is_current()
check, as you would typically want to turn off interpolation for cameras that you wished to make use of idle process mode
.
Firstly, if we force the current Camera2D to physics processing in the engine as it is done now when FTI is on, there is no escape from it. This contradicts the current FTI tutorial, especially the section about manual interpolation of the Camera.
This is incorrect. Each node and each branch of the scene tree can be individually controlled using the existing InterpolationMode
property (which was introduced for 3D interpolation). This is in the docs for the manual 3D camera.
Also note that the INTERNAL process mode is not the same as the user process mode. The camera setting determines the internal process mode, you can still use _process()
and _physics_process()
as normal (although you may break interpolation if you attempt to move a camera in _process()
).
I could argue that the FTI tutorial is fine and there is no need to force things on me, me being the current Camera2D where I have plugged custom logic in my _process() and _physics_process() functions. If I know what I am doing by using FTI, I will take care to manually switch my Camera2D to physics processing. The tools waring is enough for all cameras in my project which are left with the default idle processing.
I'm not sure I understand what you are trying to say here, maybe it is based on earlier misunderstanding.
In short, I am not positive that we can transition existing projects smoothly to FTI with only one click on the option enabling it, but I understand the status quo as an effort to achieve this noble goal.
Existing projects will typically require some changes to convert for physics interpolation, as with 3D.
I did struggle to understand your points ...
Same here, but that's what smart people usually do - they struggle internally until they first come to terms with themselves. After that, and once you get your head around other people's arguments, the rest is easy. :-)
To cut a long story short, I didn't struggle excessively with your arguments and came to terms with your points and the suggested PR code. In fact you are not genuinely overriding the Camera processing mode to physics, but activating the internal idle and physics processing for the current camera in order to emulate the equivalent of the smoothing plugin in the core. And that's quite good.
My objection was not against interpolating but against overriding the processing mode of the Camera (effectively Camera2D.set_process_mode() has no effect with FTI). I am still far away from the described Nirvana of enabling FTI on existing projects and expecting them to work right away. For instance, we have custom Camera2D offset processing depending on the player's position and without FTI that happens in idle. With FTI I am not so sure what is going to happen - will find out when FTI for 2D gets in a beta release. The interesting use case for us is on Apple iPads where physics is at 60 fps but the display rate is at 118-120 fps. And we see occasionally some disturbing jitter we'd like to fix there.
To sum up, I'm fine with the PR pending more testing as there are many critical places that have been touched so regressions are always possible. The one additional thing I wish to see happening here is to raise an orange Node warning in the scene tree for the Camera2D through the get_configuration_warning()
mechanism when FTI is on and the camera processing mode is idle. The one shot warning in _update_process_mode()
is good but not enough IMO to trigger the required attention. If I see the orange warning in my scene tree on the Camera2D node explaining why I have it I'll certainly change the processing mode to physics manually to get rid of it.
For instance, we have custom Camera2D offset processing depending on the player's position and without FTI that happens in idle. With FTI I am not so sure what is going to happen - will find out when FTI for 2D gets in a beta release.
Yes, some there's a number of things that historically happen in get_camera_transform()
which may benefit from being split into their own functions. But I suspect we need a beta and some MRPs to know whether or which things need moving to idle (so there could end up being a split with some functionality in physics tick and some in idle). Additionally whatever changes are made here need to preserve compatibility when physics interpolation is off. The easiest way of doing this is not changing this code at all, for now.
The one additional thing I wish to see happening here is to raise an orange Node warning in the scene tree for the Camera2D through the get_configuration_warning() mechanism when FTI is on and the camera processing mode is idle.
I did have an attempt at putting this in before the runtime warning (as I agree it would be better for the user than the runtime warning). The problem is that physics interpolation is hard coded to off in the editor. The is_physics_interpolated()
functions therefore always return false, and the warning never flags. That's why I went with the simpler runtime approach (for now).
It is possible we could get the configuration warning working by pushing the editor off code to a lower level, but it might end up not being worth it. The physics interpolation mode depends on propagation through the tree, so that would end up with unnecessary propagation code working in the editor (just for a config warning) and ideally we don't want to be adding is_editor_hint()
checks all over the place both in terms of possible bottlenecks, and just code readability. It could be worth spending some more time on though.
The problem is that physics interpolation is hard coded to off in the editor. The is_physics_interpolated() functions therefore always return false, and the warning never flags.
Not sure why you need the physics functions operational. Wouldn't reading the FTI value from the project settings and the current Camera2D processing mode be enough to get this done?
Wouldn't reading the FTI value from the project settings and the current Camera2D processing mode be enough to get this done?
No. If you need further info feel free to ping me in Godot rocketchat ( @lawnjelly ). This information is already in the docs as it is common to 3D physics interpolation, and it would probably be better not to discuss here (keeping the PR comment text concise and to the point is important for reviewers). :+1:
No. If you need further info feel free to ping me in Godot rocketchat.
Sorry. Not going to rocket chat nor starting dev activity on Godot on purpose. I had that bit in a prevous life and I want to preserve my user view as much as possible. For me having the FTI setting on and project Camera2Ds in idle (forced to physics, current or not current) is a bug, subject to warning. Period. No need to check whether the camera is within an interpolated branch of the tree or not and whether the interpolation is active for that camera. Take it or leave it.
I can't set the Camera2D limits and just have it teleport to the new position. Forcing scroll update and reset_physics_interpolation() doesn't seem to help with that. (I used the godot-plus 3.6 beta latest release so I'm not sure if it's still relevant)
I can't set the Camera2D limits and just have it teleport to the new position. Forcing scroll update and reset_physics_interpolation() doesn't seem to help with that. (I used the godot-plus 3.6 beta latest release so I'm not sure if it's still relevant)
Ah that could well be a bug, I'll look into it. :+1:
I think the previous godot-plus build was relatively up-to-date, but I'll try and make another soon. I've been working on the 2D particle interpolation since, which is a big task (and probably for a separate PR).
It looks like the camera is lagging behind the player a few frames, especially noticeable when jumping or suddenly changing velocity, like turning around (eg. from velocity Vector2(80.0, 0.0) to Vector2(-80.0, 0.0)). I tried resetting the camera's interpolation when jumping but it doesn't help with that.
Converting to draft as I've noticed while implementing the particles that the logic for traversing the tree needs to be slightly different than that in 3D, to account for turning on and off interpolation per node. In 3D, nodes' global transforms are handled independently, but in 2D, they are accumulated through the hierarchy, so parent interpolation settings can currently affect children, and I need to figure out a sensible way of doing this.
UPDATE: After experimenting on ways to "fix" this, I've decided for now that the on / off behaviour per node for 2D interpolation probably does make more sense to diverge from the behaviour in 3D. In 2D, interpolation is done locally per node, and the effects of this are propagated down the tree. So if for example a "player" node is moved and is interpolated, then a sprite that hangs off of it will also have the transform interpolated, even if the sprite interpolation mode is off.
This may have some implications for cameras but I'm confident they will be solvable.
Relation to 3D
I'm actually of the opinion that it may be worth also fundamentally changing the 3D system to support hierarchies in the VisualServer
, and have the 3D interpolation work more like the 2D. While having global transforms of 3D objects being independent (with no hierarchy info outside the scene tree) has just about worked up to now, the paradigm breaks down when interpolation is used, because it can't take account of pivots, so any 3D interpolation is just a very rough approximation when there is more than one node moving in a chain.
This is something I mentioned during development of 3D, but @reduz was of the opinion to keep the changes minimal and piggyback on the existing system, and was unsure if the pivots would be a problem in practice. But based on testing, I think we should reconsider this when implementing 3D interpolation in 4.x, and possibly modify 3.x VisualServer
to contain hierarchical information as with 2D.
It looks like the camera is lagging behind the player a few frames, especially noticeable when jumping or suddenly changing velocity, like turning around (eg. from velocity Vector2(80.0, 0.0) to Vector2(-80.0, 0.0)). I tried resetting the camera's interpolation when jumping but it doesn't help with that.
I've tracked this down to being an order of operations bug. The problem was that the Camera2D
was doing the current / previous transform update (and retrieving the current transform) on the internal physics tick, which happens before the user physics tick (where the camera might be moved) and before it might get moved as a result of transform changes higher up in the tree. There was thus a one tick delay on the Camera2D
in many circumstances.
Changing the current / prev update to occur on NOTIFICATION_TRANSFORM_CHANGED
fixes this. I just need to make sure the updates still occur when there have been no changes to the camera transform, and make sure exactly one update happens per tick ("the spice must flow" in order for interpolation to work :grin: ).
UPDATE: Ok pushed with this fix. You will need to test the artifacts though rather than my fork as I haven't made builds yet with this change.
I tested this PR on https://github.com/Calinou/platshoot/tree/physics-interpolation-test again, Camera2D smoothing now works well thanks to the automatic override (there's a warning printed). Particles are still not smoothed, but it may be better to leave this for a future PR so this can be merged in 3.6 betas. The player movement itself feels very smooth.
Particles are still not smoothed, but it may be better to leave this for a future PR so this can be merged in 3.6 betas. The player movement itself feels very smooth.
I have CPUParticles2D working in local and global modes. But would prefer for separate PR because this involves some fundamental changes to how they work.
Both 2D and 3D particles in global mode originally previously worked in somewhat strange way (I keep meaning to ask reduz why they work like this, but perhaps it he did not write them originally). They apply the inverse of the parent transform to get to global space, instead of simply marking the nodes as using identity transform. This worked before interpolation (although strange) but with interpolation, this technique is not mathematically good. So for 3D particles I shifted it to marking the node as having identity transform, and baking the global transform into the particles.
For 2D particles, we probably need the same (indeed that is what I've done so far to get it working), but there is an added complication of y-sorting. So I might need to do some experiments here to check this particle system works with y-sorting.
For GPU 2D Particles I have no idea yet. I didn't actually have to do anything special to get them to work in 3D, but they look like they need some tweaks to work with 2D.
For 2D interpolation in 3.6 I'm envisaging we will need 2-3 PRs, plus possible extras for fixing regressions / problem areas as they come up. So just having the basic version in to start with would be good to get feedback as early as possible in betas.
Camera is now perfectly following the player! Tested on 144hz monitor with physics fps set to 60 and it's perfectly smooth and responsive.
Some other bugs I noticed:
- Setting camera offset is being weird. I use tweens to change the offset to shake and pan the camera, and it isn't shaking at all. It works fine with interpolation turned off though.
- If parallax layers use mirroring, when the mirroring "activates", it lerps the mirrored layer to its position, instead of it being seamless.
- Camera still can't change limits and just teleport to the new scroll position.
I'll try and check these out but:
Setting camera offset is being weird. I use tweens to change the offset to shake and pan the camera, and it isn't shaking at all. It works fine with interpolation turned off though.
As with all physics interpolation, tweens will only work if done on the physics tick (there are similar instructions for 3D). I'm not super familiar with tweens, but I'd double check this is the case in your test. Note that when using an interpolated camera, shakes only have the resolution of the physics tick rate, so if you need to use more than this resolution you would need a manually interpolated camera.
UPDATE: offset_h
and offset_v
seem to work fine, so I'm presuming this is some problem with the tween not operating on physics tick.
If parallax layers use mirroring, when the mirroring "activates", it lerps the mirrored layer to its position, instead of it being seamless.
I'll take a look. I had a similar problem with sprites changing direction, and the TransformInterpolator contains a special fix for these instantaneous flips. Maybe I'm not using this for the parallax layers.
Outdated - see later in thread for solution.
UPDATE: although `motion_offset` is interpolated, `motion_mirroring` does not appear to be an interpolated property. Ah, it seems to be set through a "back door" to the `VisualServer` in the function `canvas_set_item_mirroring()`. There are a large number of properties that inevitably _won't be directly supported_ by the core interpolation, we'll have to evaluate on a case by case basis whether they are worth adding direct support. For now these will need manual interpolation (or move in `_process()` rather than `_physics_process()`).To explain this rationale:
In principle almost everything in the engine could be physics interpolated. Changing modulate
colors, animation blends etc etc. The problem is that each of these requires additional code that would complicate the engine codebase, and possibly create new bugs. Therefore the current aim of core interpolation is to support the main use cases (transforms, particles) that are the most tedious to deal with, and leave everything else to the user.
If there is popular demand for particular areas we can add in-built interpolation support on a case by case basis. But I think this will depend on feedback after a beta.
Camera still can't change limits and just teleport to the new scroll position.
I'll take a look. It could be it needs a manual reset_physics_interpolation()
call, or maybe we can automatically detect this.
If you have MRPs for any of these it would be useful. :+1:
Yes I think I'll need MRPs. I'm trying to reverse engineer the problems but the text is not enough to reproduce.
I'm aware that everything like tweens
needs to process on physics tick. I found when physics interpolation is enabled, if the Camera2D
isn't following anything, it will ignore the offset
property.
Here's an MRP for all 3 of the issues in the previous comment:
How to use:
- ~~Press toggle limits button while camera is following player to see the limits bug.~~ Fixed
- ~~Press pan up or pan down to see
offset
working properly (While camera is following the player)~~ - ~~Press toggle camera follow to make the camera stop following the player and break the
offset
.~~ Fixed - ~~Run right with the character to see the mirrored parallax layer flickering (camera must follow)~~ Fixed
Then try with physics interpolation turned off to see that it behaves differently.
Ah much better with the MRPs. :+1:
In fact now from the description I can work out what is probably going on with the offset, the logic in get_camera_transform()
is probably not being run. This is why I'm thinking it might be good to move some of that logic out, because the function does not actually do what it says on the tin, it's more of an update, so the flow of data is more difficult to follow.
I suspect the parallax background is similar to a problem I had to fix when testing "jetpaca". Parallax backgrounds that perform a wraparound mod (e.g. from 0.99 -> 0) work fine without interpolation because you don't see the glitch. With interpolation, you sometimes get an interpolated frame at value e.g. 0.45. For "jetpaca" I simply turned off interpolation for these backgrounds as they were moved in process()
anyway, but maybe there's a more generic way around the problem.
BTW if you change physics tick rate to e.g. 5-10 tps (rather than 60 tps) you can see more clearly what is going on. It's always a good idea to do this when fixing interpolation issues.
The toggle limits is doing exactly what we would expect with interpolation, it is gliding to the new location over a tick. If we want instantaneous movement with interpolation, we usually have to request it explicitly, with reset_physics_interpolation()
.
However in this particular case, the new location is controlled by the limits rather than the user calling e.g. set_position()
, so calling reset_physics_interpolation()
directly after setting the limit may be too early, as it only takes effect in the next get_camera_transform()
. :thinking: I'll try and think of a way around this.
UPDATE: although
motion_offset
is interpolated,motion_mirroring
does not appear to be an interpolated property. Ah, it seems to be set through a "back door" to theVisualServer
in the functioncanvas_set_item_mirroring()
. There are a large number of properties that inevitably won't be directly supported by the core interpolation, we'll have to evaluate on a case by case basis whether they are worth adding direct support. For now these will need manual interpolation (or move in_process()
rather than_physics_process()
).
That's the thing. As discussed, FTI is a physics mechanism which, when enabled, stirs everything to it in order to get things working properly. Almost no node in idle would work as expected, unless it is manually or automatically moved to physics (hence the delta in opinions about the configuration warning, among others).
This is the shift in paradigm I have been struggling with when FTI is on. It's a real shift in thinking, because in Godot idle is the default processing mode for all nodes: cameras, tweens, particles, etc. Making all of these work with FTI automatically looks like mission impossible, unless, perhaps like the Camera2D, the whole branch under an FTI enabled node is cascaded and forced to physics...
Run right with the character to see the mirrored parallax layer flickering (camera must follow)
I now have a fairly simple fix for this in parallax_layer.cpp
. Will push with this.