beyond-all-reason / beyond-all-reason/RecoilEngine
Interpolate weapon projectile position and rotation between sim frames when rendering
- Dominant language
- C++
- Stars
- 683
- Forks
- 293
- Avg merge
- 3d 2h
- Merged PRs (30d)
- 40
Description
### Problem
Units are drawn interpolated between the previous and current sim frame, so they move and turn smoothly at any fps. Weapon projectiles are not. Position is extrapolated along the velocity and rotation snaps to the latest sim value.
Visible effects:
- a turning missile steps its rotation 30 times a second
- a projectile positioned from Lua each sim frame (`Spring.SetProjectilePosition`) is up to one frame off against the unit it follows, so it stutters against the unit while the unit glides (related to #1898)
Both are easy to see at 0.1x speed, but the rotation stepping is visible at normal speed too on any missile that turns.
### Clips (all at 0.1x)
Turning missile, engine drawn:
https://github.com/user-attachments/assets/30416f7b-50b9-432b-9e76-5e76e784d7e7
Same missile, drawn by a Lua gadget that interpolates position and rotation between the last two sim frames:
https://github.com/user-attachments/assets/406d056e-a8ed-40ac-bd2f-9f34686f9992
_Note: Karganeth here has fixedlauncher set locally so the missile launches along the tube and then turns; stock launches straight at the target._
Another turning missle:
https://github.com/user-attachments/assets/e9629076-cd10-41d6-b1c6-7fecbed95aaa
Same, interpolated:
https://github.com/user-attachments/assets/913876e0-f4a8-4dae-808b-c4dec0e6bcdc
### Proposal
Draw weapon projectiles blended between their previous and current sim transform (position and dir) by the frame time offset, the same way units and pieces are. Rendering only, no sim change.
### How the smooth clips were made
`Spring.UnitRendering.SetProjectileLuaDraw` + `DrawProjectile` returning true to hide the engine model, then `DrawWorld` draws the model at lerp(prev, cur, `Spring.GetFrameTimeOffset()`), with prev/cur sampled in `GameFramePost`. Demo gadget attached.
Contributor guide
Research direction
Start with the projectile rendering path and the frame offset used by Spring.GetFrameTimeOffset; the issue provides Spring.UnitRendering.SetProjectileLuaDraw, DrawProjectile, DrawWorld, and GameFramePost as entry points. Compare the engine result with the demo gadget's interpolation between previous and current transforms, and consider the work done when projectile position and rotation render smoothly without changing simulation behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, lua
- Domain
- computer-graphics, game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100