Shaders for beginners

We want to spread knowledge of Defold to as many places as possible, but what we have learnt is that creating high quality video content takes a lot of time and effort, and our bandwidth is limited. And for video content we already have great video content creators in the community, like @sergey.lerg and @dchadwick , and also recently I’ve seen video tutorials in Portuguese.

What we have toyed with is the idea of really short (max 5 minute) tutorials/videos showing hands on use of Defold, focusing on a single feature, concept, component or thing. I think this would make it more manageable and it can be created when we have some time to spare in between other tasks.

But one thing doesn’t exclude another right? I believe that a collaborative blog series with content from both the Defold Foundation and the community would be of interest to a lot of users.

3 Likes

Awesome tutorial! I’ve always wanted to learn about shaders, so I took the time to follow along. Certainly have given me the itch to experiment further :clap:

If anyone is following along with a smoother image (non-pixel art), this code preserves the smooth edges.

varying mediump vec2 var_texcoord0;

uniform lowp sampler2D texture_sampler;
uniform lowp vec4 blink_effect_trigger;

void main()
{
    lowp vec4 color_of_pixel  = texture2D(texture_sampler, var_texcoord0.xy);

    if (blink_effect_trigger.r == 1) {
        color_of_pixel = vec4(1.0) * color_of_pixel.a; // White * Alpha
    }
    
    gl_FragColor = color_of_pixel;
}

Resulting image:
image

2 Likes

@britzl I think that community tutorials and vlogs like Brackeys, GFS, Thomas Brush or Black Thornpod have are awesome, something like this for Defold would mean a lot - you know, generic gamedev topics explained, but with addition of Defold examples :heart:

Both ideas of blogs and vlogs are awesome! I would for sure make some more tutorials!

@SkaterDad great! And thanks for sharing your solution! :heart:

3 Likes

It would be helpful if this tutorial or another addressed how to use var_texcoord0 because this has peculiarities to defold. In particular, it would be easier for new users if they were aware of:

  1. ‘var_texcoord0’ is relative to an entire atlas. So if I try adding more than one sprite to the atlas in the project pawel uploaded, using shaders got more complicated. I have yet to see a solution for this.

  2. Difference between global and local position coordinate space. I have read that we don’t have access to local coordinate space in shaders–I am not sure if this info is outdated, but I seem to recall having trouble with this, but can’t recreate it right now. (Also: coordinates need to be scaled to the aspect ratio of the texture)

4 Likes

This was a great post! I was hoping to also figure out how to tell what the vec4 values of a pixel is in the shader, so that I could change just the pixels that are of a particular color?

2 Likes

Check this post

2 Likes

Hey!

I was trying to follow the flashing sprite tutorial, I got it working but when I did an HTML 5 build I got an error saying it didn’t recognize some of the operations (see attached screen shots). It looks to be some sort of conversion error, I’m super confused by it. Do you know what I could have done wrong or how to fix it?

Thanks!

1 Like

Be careful with mixing ints (like 1 2 3 4) and floats (like 0.1 0.5 1.9) in shader programs (which have more strict rules for types compared to Lua). Generally you want everything to be a float. So if you want to have a 1 you need to write it as either 1.0 or 1. as shorthand (but I prefer to include the 0 for the sake of visual clarity).

5 Likes

You are right! I corrected the code snippets (there were comparisons to 0 and 1 instead of 0.0 and 1.0>

4 Likes

Also note:

  1. Comparing two floats is kind of a strange condition… Float are “approximations” of real numbers. It is better to replace a = b by abs(a - b) < some small number.

  2. IF statement in shaders should be avoided… as in any parallel computation. But this is a long story.

Ciao!

7 Likes

Oh yes, I agree, but I still aimed to make it as simple and understandable as possible :sweat_smile: The whole example is only to highlight some features and understanding of how it works and it shouldn’ be surely used in production, as I mentioned :wink: Do you think I should make it in other way? Or mention some more details or warnings?

No, no. The tutorial is perfect!

If you want to remove the if statement then I think this should work:

varying mediump vec2 var_texcoord0; // as it was
uniform lowp sampler2D texture_sampler; // as it was

void main(){
   float alpha = texture2D(texture_sampler, var_texcoord0).a;
   gl_FragColor = vec4(1.0, 1.0, 1.0, alpha)
}

However I have not tested it…

Ciao!

1 Like

Thank you!

That’s awesome article. I am making fruit slot machine game. When I try to make fruits only visible in rectangle area, the solution I can find is using shader program to change the color of the pixel. Here is the code I use in fp:

varying mediump vec4 position;
varying mediump vec2 var_texcoord0;

uniform lowp sampler2D texture_sampler;
uniform lowp vec4 tint;

void main()
{
	// Pre-multiply alpha since all runtime textures already are
	lowp vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
	if(position.y >= 465.0 && position.y <= 815.0) {
		gl_FragColor = texture2D(texture_sampler, var_texcoord0.xy) * tint_pm;
	} else {
		gl_FragColor = texture2D(texture_sampler, var_texcoord0.xy) * vec4(1.0, 1.0, 1.0, 0.0);
	}
}

I got error says Input of fragment shader ‘position’ not written by vertex shader.

Can I use the varying position to check whether it in the rectangle area? Any help will be appreciate.

1 Like

What does the vertex shader look like?

I am using the default build in sprite.vp.

The default sprite.vp doesn’t write to any position varying afaik. You can either:
Copy the sprite.vp and paste:

uniform highp mat4 view_proj;

// positions are in world space
attribute highp vec4 position;
attribute mediump vec2 texcoord0;

varying mediump vec2 var_texcoord0;
varying mediump vec4 position;

void main()
{
gl_Position = view_proj * vec4(position.xyz, 1.0);
var_texcoord0 = texcoord0;
position = position;
}

The two things added are:
varying mediump vec4 position;

and position = position;

OR:
You can use gl_FragCoord in your conditional (gl_FragCoord - OpenGL 4 Reference Pages)


To clarify, the issue you are facing is that the vertex shader only binds the “attribute” of the mesh vertices which is usually the components of the triangles such as position, uv, color and so forth. The data between the vertex and fragment stages are not written automatically, that needs to be specified explicitly by specifying (and setting) these varying variables. In newer versions of GLSL, these variables are named “input” and “output” between stages, which I think is more understandable than “attribute” and “varying”. Just ask if you get stuck!

4 Likes

Thx for your reply. I got error from the vp code you provided. It says
ERROR:GRAPHICS: ERROR: 0:8: Regular non-array variable ‘position’ may not be redeclared
ERROR: 0:14: Left-hand-side of assignment must not be read-only.

@Dong_Wang please share .vp, .fp and .material file that you use.

Regular non-array variable ‘position’ may not be redeclared

You cannot have two variables declared with the same name.

Rename the added one to var_position, and use that in your .fp file instead:

varying mediump vec2 var_texcoord0;
varying mediump vec4 var_position;
3 Likes