Speed line shader/effect when boosting
#1
Hello all,

I am in the process of implementing a speed lines shader to the stk-codebase. With this post I'm hoping to discuss the possibility of adding it to the game.

Intro
Speed lines (aka wind streaks) (see the videos below for more info) are quite a common feature in kart racing games, as the name suggests they come on screen when the player experiences a speed boost of some sorts, usually through an upgrade. I personally noticed them first in Mario Kart, but I've since gone and checked a few other kart racers (Sonic, Crash Team Racing etc.) and they all feature them in some capacity. The main purpose is to provide an extra sense of speed to the player, by mimicking wind rushing past at high speeds.

Shader
I initially started writing the effect purely in GLSL, but pivoted to using Godot's visual shader graph for quicker iteration. Before delving into more specifics here's what it looks like in isolation:
https://youtu.be/_1LBMsESjSQ

(or see next post for embedded view)

There are quite a few tweakable parameters for the shader. Ranging from: 
  • Density of particles
  • Softness of the particles
  • Amount of wisps (i.e. how many subdivisions of the UV space to sample the noise texture from)
  • Wind speed (very useful as we can tie the intensity of the boost to this)
  • Radial stretch (how blobly should the wisps be, effectively stretches the uv.x coordinate)
  • Radial mask size (how much of the screen should be ensure is always free of the effect - for gameplay purposes)
  • etc.
At the moment I have implemented a primary control to the shader (value ranging from 0-1 as a scalar float) BoostIntensity. That value is driving:
  • the wind speed
  • size of the radial mask (make the mask a bit tighter at higher intensities to really bring home the sense of speed)
  • color saturation (make the effect pop more at higher intensities, makes the wind feel more intense)
While I still need to profile on some weaker hardware, the shader should be really cheap to run on most hardware. On my machine it was close to 30us (7900xt). The effect works with sampling a noise texture at 2 samples per pixel, which is really modest in my experience.

Preview
Hooking up the shader and it's driving value -> BoostIntensity. We get something like the following:

(note the effect does look somewhat choppy due to the video quality, but is smooth during actual gameplay)


Implementation
I am still trialing the proper CPU side implementation, mainly on the 'how exactly' the effect should come in, how strong and how long should it last etc.

I've been experimenting with a few different options for the question 'how exactly'. Ranging from:
  • Should it come in mainly based on current velocity ratio with maximum velocity?
  • Should it be on impulse/activation of a SpeedIncrease?
I believe at the moment I'm going with a bit of a hybrid solution of the both, this looks roughly like the following:
  • Use the trigger of any SpeedIncrease modifier as the impulse 

    (as long as there's no active SpeedDecrease or Attachment like the anchor/parachute etc.).

  • Then shortly driving up the value and overshooting slightly to a target value.

    (make the impulse of the effect a tad stronger than it's sustained intensity).

  • Then settle down the intensity value and base it on the ratio between the current speed and the maximum speed.
    The last step here effectively helps tie the effect to match with the current speed regardless of difficulty setting.

  • Then I use the already pre-existing unique duration(s) of the SpeedIncrease to keep the effect active.

  • Once the SpeedIncrease runs out we linearly interpolate back down to 0 to gently ease out.

  • There are also some provisions for correctly latching whether we've crashed into something, drastically lost speed or got hit with a SpeedDecrease to then directly ease down to 0 (rather than waiting for the effect to run out naturally).

I am still needing to properly clean up and dial in the logic, but I personally think it's getting closer to the final solution. A couple of notes from my side:
  • The effect does still ramp up to 1.0f quite fast at the moment, dialing this down is something I'm working on, it should only really be at 1.0f if we've stacked 2-3 speed increases and going fast (i.e. coming out of red skid + zipper + nitro should be 1).

  • Once we crash the effect can come down just a tad faster in my book, at the moment it uses the same linear ease down to 0 as when the effect normally runs out.

  • Certain SpeedIncrease items we can maybe experiment with not having it contribute to the intensity (i.e. turn it off for skids etc.?)

Closing Remarks
If this feature/effect looks of interest to you and would be a good fit for the game, let me know and I can clean up my code and start the PR. From there we can discuss further and iterate on feedback/suggestions.

PS: I did only notice at the posting of this post that there might be a related thread to another implementation of speed lines, my apologies there, but I do think we can work out a way to combine our efforts. https://forum.supertuxkart.net/thread-200.html

Thanks and kind regards,
stbdev
Reply
#2
Hi, always great to see a new contributor! Smile

First up this looks very, very nice and is definitely something we are very interested in for the game.

It's really nice that you added so many paramenters to tweak, that will make it easy to fine tune the effect if needed, or even create different variants of the effect.

The colors look pretty rainbowy, which looks nice imo and works well for the tracks you used in the video, however I'm wondering how it will look on tracks that are darker in tone, such as Fort Magma or STK Enterprise. Is the coloring also something that can be easily changed inside the shader?

Another question I have is: how does the effect work with different aspect ratios?



Regarding activation conditions:

We certainly wouldn't want normal drifts or nitro alone to be enough for an activation.
Good players are most of the time in a drift + nitro boost and the effect shouldn't be active most of the time.
So I'm thinking that maybe a purple drift + nitro could be enough for an activation, but a yellow drift + nitro shouldn't be enough, a red drift + nitro could be thought about.

Perhaps this is something that should be different for lower difficulties though, since less experienced players are getting drifts way less often.

I think some items should have an activation tied directly to them, the zipper would of course make sense and then the electro shield and nitro hack could have that as well.

Other conditions such as jumping or being in a canon for a certain amount of time, or overtaking a couple of karts in a short amount of time are also things that could potentially be thought about.


When you open a PR make sure to use the BlanceSTK2 branch which is the branch we are using to develop STK Evolution Smile
It also includes the third drift level and the two new items I mentioned, from your video I'm assuming you are using 1.5 or the master branch.
Reply
#3
(Yesterday, 04:00 PM)stbdev Wrote: While I still need to profile on some weaker hardware, the shader should be really cheap to run on most hardware. On my machine it was close to 30us (7900xt). The effect works with sampling a noise texture at 2 samples per pixel, which is really modest in my experience.

A 7900XT is still a pretty good discrete GPU. The vast majority of STK players have much weaker cards, and many people play the game on integrated GPUs or on phones. 30µs is fine, but if it's something like 300µs or 500µs on a weaker machine, that's significant.

The effect looks pretty good, but it probably should come with a toggle in the graphics settings and be only enabled at some presets to-be-determined through testing. Probably level 4 (within the current levels).

(Yesterday, 04:00 PM)stbdev Wrote: Should it come in mainly based on current velocity ratio with maximum velocity?

Maximum speed is variable, which makes it a poor reference. More on that below.

(Yesterday, 04:00 PM)stbdev Wrote: Should it be on impulse/activation of a SpeedIncrease?

All speeds that are genuinely high require collecting at least one source of max speed boost, but:
  • There are many speed boost sources, and trying to come up with a list of combinations that should or should not trigger the effect would lead to a messy and unsatisfying result.
  • There are many situations in which a speed boost can be triggered while going at a fairly low speed. Displaying the speed lines in that situation, but not at a higher speed obtained with less boost sources, would simply be odd.
  • When you mix in sources of SpeedDecrease, it becomes even messier.

There is a much simpler and more elegant solution: make both the trigger threshold and the intensity depend on the ratio to the generic max speed.

Generic max speed is currently used in the speed formula for basketballs, but it also works very well here because unlike a kart's own max speed, it is constant throughout the race.

This gives us some very good properties:
  • Lower difficulties will have lower requirements to activate the speed lines (generic-max-speed is difficulty-dependent), so the speed lines will be available at all difficulties. They would trigger more often and more intensely for players that drift, which is more common at higher difficulties, but I think that's fine.
  • The speed lines would be a reliable indicator that players can use as a complement to the speedometer, instead of a potential source of confusion.
  • It's much easier to fine-tune two values (activation threshold and intensity ramp curve) than a plethora of if-else tests combined with parameters. If we set the activation threshold at say 25% above generic max speed, we might not know which speed boosts exactly went in there to reach the threshold - but we know for sure there had to be some boost sources, and that they more than compensated any potential penalty. It also makes it easier to tune how often and how intensely the effect appears.
  • It removes the need for most of the machinery to check if the effect should keep going or not, the speed itself is the judge.

The kart's speed itself may have significant discrete frame-to-frame changes, particularly when driving on zipper pads, so a mechanism to avoid intensity increasing too suddenly may still be used if required to make the visuals smoother, although I'm not sure if it's actually needed.

The concept loses the idea you mentioned of having the speed lines stronger just after the activation of a boost to emphasize it, but I think the overall trade-off is reasonable.

(Yesterday, 04:00 PM)stbdev Wrote: If this feature/effect looks of interest to you and would be a good fit for the game, let me know and I can clean up my code and start the PR. From there we can discuss further and iterate on feedback/suggestions.

Yes, it would certainly interest us. SuperTuxKart is in need of more/better shaders, so help here is welcome.

I suppose we can start discussing some specific details once we can test your code locally.

Sven mentioned the Evolution branch (BalanceSTK2) for a PR. Currently, the main branch receives mainly bugfixes and most features are directed to the Evolution branch, but there are some things we do directly in the main branch when there is no extra cost to it.

I suppose like Sven do that your code currently targets the master branch, I would say don't bother porting your code to the Evolution branch for now. It won't cost anything more to do it later if need be, and perhaps this visual effect would make sense to integrate for 1.5.1.

Of note: there is also the motion blur shader that's supposed to fill a similar role. I can't remember off the top of my head what issue it has (I think there was something making it look not so good), but I remember distinctly that activation conditions for the motion blur effect are bad, and much of what I suggested for your speed lines goes back to thoughts I had regarding activation conditions for motion blur.

Personally, I prefer the visual style of speedlines, and there is a reason why blur effects are not part of the main graphics slider, but any integration of your effect into SuperTuxKart should give some consideration to how the two effects interact, and motion blur's activation conditions should be revised too (although in a separate commit/PR).

(Yesterday, 04:00 PM)stbdev Wrote: PS: I did only notice at the posting of this post that there might be a related thread to another implementation of speed lines, my apologies there, but I do think we can work out a way to combine our efforts. https://forum.supertuxkart.net/thread-200.html

I remember that thread. I had it on my list of things to get to for a while before letting it go.

The problem is that the visual effect didn't look so great and the code quality was poor (I think a bunch of it was AI-generated and ended up very verbose, making a proper code review too time-consuming for what it was).

Your shader is more visually appealing, so that makes any effort required to tune it and integrate it easier to justify.
Reply
#4
Hey both,
Cheers for the welcome, glad to be here! I'm glad to hear you like the effect/shader. Having read through both of your posts, there's definitely some good suggestions as to the next steps for this.

Let me quickly address a few questions first:
(Yesterday, 06:58 PM)Sven Wrote: The colors look pretty rainbowy, which looks nice imo and works well for the tracks you used in the video, however I'm wondering how it will look on tracks that are darker in tone, such as Fort Magma or STK Enterprise. Is the coloring also something that can be easily changed inside the shader?

Another question I have is: how does the effect work with different aspect ratios?

Thanks, and yes I agree I personally think it works well at the moment, even in the darker tracks. The color change happens over time and helps break up the uniformity of the effect. That being said I should be able to parameterize it such that we can try a different range of hues. It is certainly something we can easily experiment with and tweak to polish up the effect Smile

As for the aspect ratio, it's something I correct for in the very beginning of the shader by factoring in the screen resolution in the UV calculation. As such it should behave uniformly on most screens.

Alayan Wrote:A 7900XT is still a pretty good discrete GPU. The vast majority of STK players have much weaker cards, and many people play the game on integrated GPUs or on phones. 30µs is fine, but if it's something like 300µs or 500µs on a weaker machine, that's significant.

The effect looks pretty good, but it probably should come with a toggle in the graphics settings and be only enabled at some presets to-be-determined through testing. Probably level 4 (within the current levels).
Yes the GPU I have is certainly overkill for profiling and running this game, that being said performance is something I analyze on the daily and is certainly something I want to make sure is good for all players. I've got some other hardware that I can try for testing to be certain. Generally however the effect is really cheap conceptually, so I don't think we'll run into any issues with it, but I definitely want to test it properly before we ship it.

Alayan Wrote:All speeds that are genuinely high require collecting at least one source of max speed boost, but:

    There are many speed boost sources, and trying to come up with a list of combinations that should or should not trigger the effect would lead to a messy and unsatisfying result.
    There are many situations in which a speed boost can be triggered while going at a fairly low speed. Displaying the speed lines in that situation, but not at a higher speed obtained with less boost sources, would simply be odd.
    When you mix in sources of SpeedDecrease, it becomes even messier.


There is a much simpler and more elegant solution: make both the trigger threshold and the intensity depend on the ratio to the generic max speed.

Generic max speed is currently used in the speed formula for basketballs, but it also works very well here because unlike a kart's own max speed, it is constant throughout the race.
This does track with some of the woes I had trying to implement a good BoostIntensity value for the effect indeed. Initially I was trying to just use the ratio of current speed over the maximum speed. Then I noticed it was dynamic based on active speedboosts/decreases etc. I'll have a look at what you're mentioning here with the generic max speed instead.

Alayan Wrote:Of note: there is also the motion blur shader that's supposed to fill a similar role. I can't remember off the top of my head what issue it has (I think there was something making it look not so good), but I remember distinctly that activation conditions for the motion blur effect are bad, and much of what I suggested for your speed lines goes back to thoughts I had regarding activation conditions for motion blur.

Personally, I prefer the visual style of speedlines, and there is a reason why blur effects are not part of the main graphics slider, but any integration of your effect into SuperTuxKart should give some consideration to how the two effects interact, and motion blur's activation conditions should be revised too (although in a separate commit/PR).
I did look at the motion blur and it looks like it's triggered on a speed increase as well and then lasts for a fixed time (0.75s if memory serves me right), but it doesn't appear to really use any intensity value to dampen/strengthen the effect depending on the player's speed. I think if we apply the same BoostIntensity that we'll feed into the SpeedLine shader, we might genuinely have a nice layered effect.

Overall thanks both for the feedback on it! I'll try and implement it using the Generic Max Speed to try it out and post results here. After that if you guys agree maybe we can start a draft PR so we can all test it locally and see what needs changing to make it into the game? 

Cheers and kind regards,
stbdev
Reply
#5
(5 hours ago)stbdev Wrote: I did look at the motion blur and it looks like it's triggered on a speed increase as well and then lasts for a fixed time (0.75s if memory serves me right), but it doesn't appear to really use any intensity value to dampen/strengthen the effect depending on the player's speed. I think if we apply the same BoostIntensity that we'll feed into the SpeedLine shader, we might genuinely have a nice layered effect.

Yeah, the motion blur effect's intensity doesn't seem to scale nicely (the shader code has a boost_amount parameter but that doesn't seem to work great). By default the effect is very weak and hard to see, but just naively increasing the blur_factor to make it more visible doesn't look so good, with some serious artifacting.

[Image: attachment.php?aid=237]

(5 hours ago)stbdev Wrote: Overall thanks both for the feedback on it! I'll try and implement it using the Generic Max Speed to try it out and post results here. After that if you guys agree maybe we can start a draft PR so we can all test it locally and see what needs changing to make it into the game?

Sure, sounds good!


Attached Files Thumbnail(s)
   
Reply


Forum Jump: