Model features
This merge request aims to add various (somewhat) requested features to md3 models.
Three new animation flags have been added, in addition to the existing +i:
+e: for extend, this allows any spr2 animation to go past its allotted frames as determined from the sprites. This only works if there are more frames in the extended model animation than the original sprite animation. These extended frames behave essentially as custom interpolation frames: The frames are squeezed into the same timeframe as normal, but the animation plays faster, filling in the extra ones evenly through the animation. A 4-frame animation extended to 8 frames will play 2 frames in the same amount of time a sprite would just play 1. This allows you to do much higher fps animations than before without nearly as big a risk of distorting the model with linear interpolation. In the same vein, interpolated frames work well with these changes, as now you can better control the transitory frames.
Side note - this has some weird (but i do think correct) behavior with spr2defaults: it will treat the whole animation as the original animations length, repeating when necessary, instead of adapting the animation to the new number of frames. For example, if stand is 4 frames, and you don't include a run animation, it will loop through the stand frames 4 times, a total of 16 frames in the regular timespan.
+n: for no zero angle, this prevents the model from being forced to face the camera. this works on both spr2 models and regular sprite models
+o: for force zero angle, this does the opposite, all frames in the animation are always facing the camera
If these are omitted, the behavior should stay exactly the same as before.
All of these flags can be added simultaneously and with the existing interpolation flag, except for the n and o flags, which are mutually exclusive. If both are found, the second will be prioritized. The logic only checks for the presence of three flags max on sprite2 models, and two on sprite models.
All of these are valid ways to set up the flags:
- SPR2_ANIM+i
- SPR2_ANIM+nie
- SPR2_ANIM+io
- SPR2_ANIM+ei
- SPR+n
- SPR+io
- SPR+ni
These are invalid:
- SPR2_ANIM+no - the zero angle force flag will be used
- SPR2_ANIM+eoni - the no zero angle flag will be used, the interpolation flag will be omitted
- SPR+ie - this should work fine, but the extend flag will not have any effect
- SPR+ei- the interpolation flag will not be used
A showcase of these is in the video.
SRB2 v2.2.14 nightly 2024-04-20 18-25-37.mp4
The STND animation and the RUN animation have the +e flag, with stand having 3 frames (instead of 1) and run having 8, instead of 4.
The ROLL animation and the TRNS animation have the +n flag, allowing viewing of the animation from any angle for either, overriding the default sprite behavior.
The WAIT animation has the +o flag, which makes it always face the camera.
The example blend file in the zip folder shows these changes in effect on the frame markers. The blender addon for exporting things to md3 is at this google drive link https://drive.google.com/drive/folders/1Hv6IaRByirP9L-KaODKf4-COkC2rKoZj, io_export_md3.py The exported md3 is also present in the included zip folder. Example model by fznmeatpopsicle.
In addition to this, I added a feature to sprite models that allows multiple to be included in the same file. If you add a marker on the first frame of the animation with the name of the sprite it should be replacing, you can place the models animations (sequentially) at any frame, not just the first.
For example, if you wanted to include both blue and red crawlas in one file, you can add the marker "POSS" at the first set of frames, and then the marker SPOS where you want the red crawla's animations to start. These will read from the same texture, so if you have reused objects with the same textures (not the case of the crawla here, making this a somewhat bad example), you can throw all of them in the same file. An example blend file of this, as well as an md3 containing both crawlas and their textures is in the zip folder.
These support the long sprite names, to a point, as md3 frame names are limited to 16 charactes max, including internal chars that show frame number characters at the end. If the name is too long, the old behavior can still be used, and a name prefix is no longer required to use the interpolation/zero angle flags
Models.dat lines for md3s are included.
Furthermore, I've made it so that states are the main avenue for determining what model frames to use, not sprites. This makes it so if two states reuse a sprite, a model doesn't necessarily have to use the same animation for both, it can use the default spr2 assigned to the state. For example, this would now let every character have a jump animation separate from their roll.
The last change i made, due to adding the ability to extend the frames, is to the way that all player models animate. There was an 'interpolation limit' in place, which gave a sort of ease in/out to animations around 9 tics and longer. Because modelers can now define their own in between frames, I don't think this forced behavior is necessary or particularly useful to have. I kept it on the sprites, where animations cant be extended, but otherwise it has been entirely removed.
Example showing an affected model:
Original behavior
SRB2 v2.2.13 2024-04-18 18-23-47.mp4
With changes
SRB2 v2.2.13 2024-04-18 18-22-41.mp4
For modelers wanting to test this out: under the "View exposed artifacts" section, click on the appropriate operating system under the "Artifact" table. Then, find the "bin" folder. Within this should be a compiled build for your OS - srb2win.exe for Windows, lsdlsrb2 for Linux, and srb2.app for MacOS.
Merge request reports
Activity
added 1 commit
- 7bca1a47 - Fixed interpolation getting distorted as mesh objects are iterated
added 1 commit
- c64832e3 - test at making available frames tied to mobj states only for spr2s, instead of...
added 1 commit
- 49350728 - fixed state checks for spr2 frames not included in the sprites, very hacky way...
[Click to expand long comment]
What are the consistency implications of
+e
?
If a sprite animation has 4 frames, its model animation has 10 frames, and you pause and disable models during frames 5-10, will the object show an error sprite (while paused) due to rendering an invalid sprite frame?
(And would this also happen if you join (or resync in) a server, while the server host has more-frame animations than you and the "sync" happens while an object is using a frame that you don't have?)Similarly, if you're playing online with models with more frames, and Lua does something on specific frames (or one of the vanilla player-animation-length-dependent(?) states ends later), can't that cause network consistency/synchronisation issues?
[...] +e: [...] This only works if the extended frames are more than the original. [...]
If this "overrides" the sprite frame count, shouldn't it be irrelevant whether it gets overriden to be "more" or "less"?
[...] +n: for no zero angle, [...] +o: for force zero angle, [...]
I've been wanting these animation flags for a while (even though I'm not a modeller myself). I like these.
(If you're looking for letter suggestions, I was thinking+f
for "facing the camera" (force zero angle)... and-f
for "not facing the camera", but maybe+o
for "object angle" (no zero angle) works better when flags are combined like+eio
.)[...] SPR2_ANIM+eoni - the no zero angle flag will be used, the interpolation flag will be omitted [...]
Why will the interpolation flag be omitted? (Because that it aborted at
n
due too
appearing first, soi
was just skipped due to being after it aborted? That feels wrong... but you shouldn't be using+no
at the same time in the first place, of course.)[...] SPR+ie - this should work fine, but the extend flag will not have any effect
SPR+ei- the interpolation flag will not be used [...]Why do
+ie
and+ei
result in different behaviours?
And ifSPR
(instead ofSPR2_ANIM
) means that it's a non-player animation, what's the use case for+e
here (seeing as non-player objects will have hardcoded animation lengths in their states or Lua scripts)?[...] The last change i made, due to adding the ability to extend the frames, is to the way that all player models animate. [...]
Why?
[...] Because modelers can now define their own in between frames, I don't think this forced behavior is necessary or particularly useful to have. [...]
Are you saying that
+e
does not "extend" animations, but instead "add extra keyframes, and make the time between keyframes shorter, to have more keyframes across the original amount of time" (e.g. a sprite having 4 frames at 0.5 frames per tic, and its model having 10 frames at 1.25 frames per tic)? If so...- I think that this could have been explained earlier (but I'm not sure how you'd explain it). The way that I understood
+e
's description is that e.g. a 4-frame sprite animation and a 16-frame model animation with+e
would work like a 16-frame sprite animation and a 16-frame model animation works in v2.2.13.
- Doesn't this mean that if model-makers don't want that "interpolation limit", then they can just double the model's frame rate and set a mid-way keyframe in between themselves, to get around the "forced" behaviour at will?
- If a model uses+e
to make high-frame-rate animations, then the model animation will get slower if an add-on adds more frames to a sprite animation. (But it'd be hard for a model to be "prepared" for this situation regardless, anyway...)
Or, in summary...
- If
+e
"extends" model animations, I'm worried about multiplayer synchronisation when it comes to Lua doing things on certain frames (and vanilla animation-length-dependent states' durations).
- If+e
"changes the model-frame-to-sprite-frame mapping to allow more keyframes with less time in between", e.g. 10 frames at 1.25 frames per tic instead of 4 frames at 0.5 frames per tic, then I don't think that the description did a good job explaining that...? And I'm concerned that if an add-on makes a sprite animation longer, then that could make a+e
model animation slower (but models can't account for this situation either way).
- I like+n
and+o
. (If you're looking for letter suggestions, maybe+o
(instead of+n
) for "object angle", and+f
(instead of+o
) for "facing the camera"?)
- WithSPR2_ANIM+eoni
, why will the interpolation flag be omitted?
- WithSPR+ie
/SPR+ei
, why do+ie
and+ei
result in different behaviours?
- The "interpolation limit" removal changes this merge request from adding features to changing existing behaviour, affecting old models. (And if+e
"changes the model-frame-to-sprite-frame mapping [...]", then the old behaviour is something that new model makers would be able to overcome at will regardless.)The way that the +e flag works is that it uses the existing interpolation frames in order to insert extra frames at non-sprite times, basically increasing the framerate. I think of it as a 'model controlled interpolation.'
For example, if you had a sprite with 4 frames that plays at a 3 tic per frame speed, and you extended the animation to 6 frames, now the model will switch frames every 2 tics instead, keeping the loop duration the same, 12 tics, allowing the modeller to fill in their own extra keyframes. there shouldn't be any synchronization issues because nothing about models is outside of rendering code, it should all be client sided. sprites should behave identically.
An animation extended with lua with a +e model animation will get slower, yes, but like you said theres barely any way to account for this currently as is, other than adding frames to the end, which you can still do by omitting the +e flag. If anything, this might make it more consistent, preventing the animation from looping weirdly as it did before and just slowing it down to account for the new length, and assuming the actual action of the animation is unchanged, its likely that its been sped up to account anyway, which could prevent it from looking significantly different/weird
The naming conventions are there simply because: i only currently check for the max amount of flags possible (3 for spr2 models, 2 for spr models, assuming that you should not be using +n and +o together), the +e flag does not work on sprite models, as you cant really selectively lengthen parts of an animation if there aren't distinct animation states, and the logic exits the flag checking code early if it detects a character that shouldnt be present, which includes the +e flag on normal sprite models. I could change this, but this was pretty similar to how the +i flag alone used to work, and having the model not display as intended could likely hint at the names being incorrect to the modeler.
For the interpolation limit thing, for any animations it effected, (barely any, most notably the wait animation) it would really mess up the frames if you tried extending them, causing them to jump around because it artificially adds periods where it sits on a frame, which doesn't really work if you're trying to linearly extend the animation. its basically trying to account for the fact that you cant define an ease in/out on your own, which inadvertently prevents this feature from working properly.
I could revert this behavior for a non-extended animation, but i did ask parts of the modeling community on the srb2 discord, including jeck jims, what they thought of the change and nobody really seemed to take an issue with it, even if it did modify existing stuff. So for the sake of backwards compatibility/not modifying existing behavior I could add this back in, but it doesnt seem like that particular quirk of model rendering is really well liked or even noticed by most modelers.
Ill definitely look at the wording of the extend flag description though, because it doesnt really 'extend' the duration of the animation, if 'extends' the frames you can work with within the same timeframe and that should be conveyed unambiguously. Thanks for the feedback!
added 4 commits
-
88706ff7...488e6d56 - 3 commits from branch
STJr:next
- 94773025 - Merge branch SRB2:next into model-features
-
88706ff7...488e6d56 - 3 commits from branch
added 3 commits
-
94773025...c2b57e26 - 2 commits from branch
STJr:next
- a42572f8 - Merge branch SRB2:next into model-features
-
94773025...c2b57e26 - 2 commits from branch
added 20 commits
-
a42572f8...a75fbd22 - 19 commits from branch
STJr:next
- 25259f7e - Merge branch SRB2:next into model-features
-
a42572f8...a75fbd22 - 19 commits from branch
If possible, could you copy the fix for #1234 (closed) into a different merge request? It would help the cause of actually getting 2.2.14 out.
mentioned in merge request !2461 (merged)