Shaders for beginners (with examples in OpenGL and Defold)

Oct. 16, 2020
protect

I had many problems with understanding shaders, but after getting a grasp - it is so easy, convenient and powerful! I present to you my twisted version of understanding this, hoping it will help other aspiring devs.

This is my slow path from a total noob to a less-noob-ish shader programmer. It will be for someone totally new, so don't mind a plain style and many simplifications or depictions (not exactly totally true, because saying them totally true demands more explanations and those explanations demands more explanations and so on, and so on) Later, things will be clear for you and you will get to know easily how it is really working.

The post is full of useful links and you should check them all - additionally I am encouraging you to check out all the awesome documentation Defold has after reading this post.

 

Drawing a picture

You use a sprite to see a visual in your game. Defold uses (Nerd's babble alert!) OpenGL (a framework to draw graphics) to draw your sprite to a screen. There is a special way of telling the graphics card how it should be drawn. There are two programs that runs for every pixel every frame before the final color of that particular pixel is displayed on the screen.
Those are (OMG more babble!) vertex program and fragment program. There are joined together in something called a material.

image
image

Materials to study

In Poland we say "How a horse looks like? Everyone sees!" (a not-so-scientific explanation of Mr. Chmielowski in his New Athens (encyclopedia))
Material is like it looks like - in our real world we have materials like silk, wool or cotton. They have, let's think, a texture and a colour! (pun intended, you will get it soon). In computer's world it specifies how a sprite/particle/mesh and other visual assets are rendered (displayed on a screen) to resemble something.

 

Recipe for an image

This is a recipe (from here):

image

I will refer to it many times below:

In a 3D engine (like Defold is) everything visual is a bunch of points (vertices). They are transformed from 3D space to a 2D screen space like a camera captures a 2D image of a real 3D world. From those points we can specify some basic geometrical shapes (primitives), imagine retro style 3D:

image


(source: https://wallpapersden.com/retro-wave-wallpaper/2560x1440/)

But screen is consisting only of pixels, and each of them can glow in one of different colors so we can see a picture on the screen. So we are taking the picture we have (continuous geometry) and chop it into a handful of small pieces (aka rasterize it into fragments). Then, we have an interpolated colour of a fragment (and we can modify it) so we can light that one diode in our newest OLED monitor. And another. And another...
 

Vertex program

It's taking care of the first part of that process - calculating position of vertices (aka points in a 3D space that specify the geometry) from 3D space to a 2D screen space - so it somehow answers a question - where to draw. But let's leave it for now - it demands some further explanations about cameras, projections and so on and you will need it mostly for 3D games. For now we are taking care of sprites in single 2D games and sprite geometry is simple as is - a rectangle. We'll use a default vertex program.

image

Fragment program

It simply defines what colour should have each fragment (pixel). It's used in the last stage of the process of preparation of your image to be displayed on the screen. So it somehow answers a question what to draw. That's it, can't say here anything more useful or wiser, but I want that definition to be a little bit longer so it looks professional :)
image

After reading above and getting a grasp of what it is, you should read about those programs for a correct and deeper understanding.

Excersises

You must try something in order to stop being afraid of that thing. You must face a demon before it hits you. But when it hits you, you will probably blink in white (games are teaching!)


(https://sventhole.itch.io/blademaster)

We will make that effect in shaders, but normally it will be more efficient to just tell your graphic designer (or yourself) to just draw that one frame in white, ok? Although such exercise will teach you:

1. getting pixels from a texture 
2. changing color of pixels
3. sending a data to a shader

 

Let's start!

Create an empty project in Defold with a sprite. 
Add an image - make an atlas and add that image into it. Add game object with sprite to your collection to it and set its image and default animation to you new image.

image


Copy a default sprite material, fragment and vertex program to your working folder. I don't care about tidiness so much for this exercise. (But that alter ago speaking in brackets will be watching you! 👁ï¸Â Remember for future that a good structure is crucial!):

image

You can (should!) rename them. Open your new material and change the fragment program to your new fp (fragment program), however you named it (however?!):

image

Save it (save frequently!) and open you new fragment program. (and do backups!¸)

Magic explained line by line, just like here, but, you know, without Nerd's babble (it's a professional documentation!)
It's a code written in GLSL (OpenGL Shading Language), something similar to C++. You will notice I commented out some lines that are useless here. (if there is a useless code remove it! don't leave comments!) For now just focus on the essence which is for each fragment to:

1. Get a position from vertex program
2. Get your image data
3. Get a colour of that particular pixel by sampling your texture at an interpolated position 
4. and write it to the output (gl_FragColor)

/*1*/ varying mediump vec2 var_texcoord0; // position of your fragment = output from vertex shader = input for fragment shader

/*2*/ uniform lowp sampler2D texture_sampler; // your image = texture data used like a reference here to create an image = this is automatically assigned by Defold engine, because you specified an image for a sprite
//uniform lowp vec4 tint; //vector representing a color in RGBA (red, green, blue, alpha)
// above are uniform variables - passed to the fragment program (first by engine, second by user)

void main() //this is hmm, a main function of your program, it looks like it has no output (void), but you'll know it's not particularly true
{
//lowp vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);

/*3+4*/ gl_FragColor = texture2D(texture_sampler, var_texcoord0.xy); // * tint_pm; I commented out multiplying the color by tint, texture2D() is a function that takes sampler data and interpolated position and gives you a color of the fragment as a vector in RGBA (red, green blue, alpha)
}

Save it. Open you collection with a game object with a sprite and change its Material property to your new material.

image</

JikGuard.com, a high-tech security service provider focusing on game protection and anti-cheat, is committed to helping game companies solve the problem of cheats and hacks, and providing deeply integrated encryption protection solutions for games.

Read More>>