Basic SpriteComponent shader tutorial #3795
kornellapu
started this conversation in
Show and tell
Replies: 1 comment 2 replies
-
|
Would you be interested in adding this tutorial to the official docs as s PR? :) |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hey kind people!
Summary
This tutorial give you a brief understanding how to create and use basic shaders on
SpriteComponentswithPostProcessandPostProcessComponentusing Dart/Flutter and Flame Engine frameworks.My intention was to keep this tutorial as beginner friendly as possible.
So the tutorial starts at ground zero, at installation and preparation (feel free to skip any steps).
Then goes through creating three classes (other than the game and world) and then wire them together.
At the end it will give you a working shader example which you can tweak it further as you wish.
The basic tutorial consists of 1 + 4 sections.
The Appendix section holds one section. Which goes beyond the basics: adding user input responses.
For the basic tutorial, we will create a simple outline shader for sprites which has a transparent layer as background.
This tutorial intended to on transparent images, like
.pngfiles.Created at 2025.12.22 by Kornél (Hoodead) Lapu
The used versions are
Flutter: 3.10.4
Dart: 3.10.4
Flame Engine: 1.34.0
Setup
0.1 Tools
First of all you need to install the frameworks (duh!).
You can find the instructions of installing Flutter here and after that for Flame Engine here.
At the end of installation you should have a working project.
If you dont have it or you already installed then, create a folder for your project, I will use this for example:
C:\Projects\basic_shader_tutorialOpen your folder in VS Code.
Press
Ctr + Jto open terminal window in VS Code.Execute the following commands, to create new flutter project in current directory:
flutter create .Now you have a new flutter project.
Yeey!
0.2 Extensions
While installing through VS Code you are asked to install extensions for Dart and Flutter, I recommend it to add one.
Also we need something to work with fragment (aka pixel) shaders in
.fragfiles, so we need some GLSL highlight or linting. I suggest you to go ahead and download one from the Extensions tab in VS Code.I used a syntax highlighter: GLSL Syntax for VS Code from GeForceLegend, but it is really up to your preferences.
0.3 Image resource
I will use an image (sword.png) created by lapu_land__.
If you fancy to add your own resource, don't hesitate and I also encourage you, to do so.
The important part is to have transparent background in the
.pngfile.Create the folder where you
Copy the choosen file under your assets folder in the project, something like this:
C:\Projects\basic_shader_tutorial\assets\images\sword.pngDo not forget to add the containing folder to assets in
pubspec.yamland save:Pretty much that's it for Setup. We are working with vanilla Flame Engine settings, with nearly vanilla VS Code.
main.dart [1/4]
1.1. Widget, Game and World
Basic stuff, similar to Flame Getting Started.
Replace the whole
main.dartfile with the following:Save and run it from the VS Code terminal (
Ctrl + J).The command is:
flutter run. then choose your device from the available list.You should see a black background in a new window.
The console will contain the "The world is MINE!" message, maybe you have to scroll a little bit upwards, because of the printed flutter commands.
Allright, here we have an empty but working application.
Component(s) [2/4]
Let's create the component where we render our sprite and apply the shader.
For clarity and some modularity I separated the sprite into two classes:
Now if I want to modify the shader of the sword only, I dont have to modify the underlying sprite class or
I can "freely" modify the sprite and add input event mixins to it or add childrens, if it is a composite sprite so on and so on without modifying the shader post process class.
2.1 Sprite
Create a new file named
sword_component.dart(or instead of "sword" use what you have of course):2.2 Wrapper
Here comes the wrapper class for applying shaders and post process, in the same file
(or in a separate one, but don't forget to link them together afterwards via import)
create another class:
2.3 Result
So for me the final
sword_component.dartfile looks like this:So here you will get a syntax error because
OutlinePostProcess()does not exists nor the imported package.. yet!Let's create those next!
Post process(es) [3/4]
Here we are preparing for shaders.
This
PostProcessis the handler of the fragment (pixel) shader, and this class is responsible for creating shader resources and for keeping the uniform variables updated.We also can store shader "settings" here (through uniforms) if you want it to be modifiable in runtime, for example enabling and disabling effects.
3.1 Post process
We create the missing class in a new file, name it to
outline_postprocess.dart:Okay so if the linking / importing is right the syntax error will go away.
The outline should be "under" the image, so I added the
PostProcessComponentas the parent of theSpriteComponent, which would mean the post process (shader) is rendered first, and then theSpriteComponentwith the image overwriting the layer of the shader.You can test it by stacking only
SpriteComponentswithin each other. The last (deepest) child will be rendered on top.Using any kind of
PostProcessComponentwill "overwrite" the rendering order and the post process will decide what will be the final color of the rendered pixel (check out the added hints for the class and it's source code for details).This structure allows us to simply use
rasterizeSubtree(), which will implicitly rasterize all added children.Let's run the application.
Ctrl + J.flutter runthen choose your platform.Nothing, but darkness...
3.2 Usage
Well we did create the components and postprocess classes but we did not added any of those to the game itself.
Go to the
main.dartand add two components to the world with a little positional offsets:In the new
main.dartI replaced theFlameGamewith a custom class where I override the background color, because I have a black-and-white image. You can change it to suit your images too.Also change the position of components based on the size of my images and window size.
Run the application again.
What? There is only one sprite? Why? You may ask, my fellow tutorial buddy.
The reason is printed early in the console, if you whish to trace it.
There is no such file what we would like to load as a shader file in
OutlinePostProcess:[...] Unhandled Exception: Exception: Asset 'assets/shaders/outline.frag' not found [...]I promise there won't be more missing files after the next section.
outline.frag [4/4]
In this section we will create the fragment (pixel) shader program which runs on the GPU then add as a resource.
It is important to note, we are going to program the GPU, so this code will need a little bit of different thinking from what we did before.
Everything is ready to create the GLSL based shader.
4.1 Shader code
Create new directory at
\assets\shadersand a file namedoutline.frag.For example, in my project it looks like this:
C:\Projects\basic_shader_tutorial\assets\shaders\outline.fragOpen the
outline.fragfile and add the following lines:So.. what does this shader do?
Grabbing each transparent pixel and checking: is it next to an opaque pixel?
If yes, then color it as the outline color (passed in as an uniform variable), else it will be full transparent.
That is why the transparency of the
.pngimage was important in the beginning (at Requirements section).4.2 Shader resource
To let the flutter linking process know about this shader asset we have to add it to the
pubspec.yamlfile before compilation.Open the
pubspec.yamland write the following lines under what we already added:Save it and let the automatic
pub getcommand to run.Now the resource will be loaded when the project is next compiled.
Now run the application.
Open the console (
Ctrl + J).Execute
flutter run, then choose your platform.Tadaa!
You should see two sprites in the window.
The left is without an outline, the right one is with a colored outline from the shader.
We are done with the basic tutorial.
Yippyy!
It's time for you to experiment!
Takeaways
According to my logic, there are three layers of using shaders in Flame Engine, where:
SpriteComponentandPostProcessComponentPostProcess.fragfileThere is an option to alter shader behaviour from the component logic too if you are using
PostProcessComponent.Check Appendix A.
I hope this tutorial helped you to understand the basics!
Don't forget, if you know better solutions: go for it! You can tweak this solution to your needs, happy coding!
If you found some errors or mistakes please let me know in the comments and I will look after them and update the tutorial accordingly.
The repository of this tutorial is available here, and it is set to the end of the basic tutorial.
The Appendix files are present, but commented out.
And if you are using any part of the shader codes, please credit me as
Kornél (Hoodead) Lapu
or buy me a coffee here.
Thanks in advance!
Also don't forget to support the superb Flame Engine community too.
Cheers!
Appendix A - User input
This section we will add a Flame
mixinto handle some mouse hover events and change the underlying shader behaviour.A.1 Event handling
Open the
sword_component.dartfile or where yourPostProcessComponentis located.Add the
HoverCallbacksmixin to the class, to have something like this:After that add one private field and the two function to react to hover enter and exit into the class.
(The cancel event should be handled too but for clarity, I omitted).
At this point the solution was not working for me with these modifications.
As I debugged, I found out the size property of
PostProcessComponentwas not handled as I expected, though the value of size property was not a zero vector at runtime.I decided to elevate some part of the code from
PostProcessComponentintoSwordSpritePostProcessedand handle the children changing there.After I explicitly set the size property it was working as intended, attached to
onChildrenChangedevent to let it work with multiple children (but not tested that part).After that the expected bounding box became the target.
At the end the
sword_component.dartfile became this:The result is, when you hover over the sprite bounding box, the outline shader changes to blue, because we set that in the hover event.
If the mouse exits the box, then it is resetted to the original color.
This is how it should look like:
That is the end of Appendix A.
Beta Was this translation helpful? Give feedback.
All reactions