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


Forum Jump: