Fragment Shader Help [3.0]

kaleidxkaleidx Posts: 6Member

Hello,

Having some trouble understanding shader language. I don't plan on using it very much, but I thought I could use it to save me making a lot of extra 2d assets. My mediocre math skills are of no use.

I'm looking to make a glow around a sprite using a shader with a gradual change in color. I've seen the sprite example in the 2.1 template and it has yielded some results. Unfortunately I've come across an impasse on getting it to glow a different color. This is what I have so far:

uniform vec4 aura_color : hint_color;

void fragment() {
    vec4 col = texture(TEXTURE,UV);     //This gets all the pixels?
    vec2 ps = TEXTURE_PIXEL_SIZE;       //Texture size?
    float a;                            //Float var
    float maxa=col.a;                   //Float for every pixels alpha?
    float mina=col.a;                   //Again?
    a=texture(TEXTURE,UV+vec2(0,1)).a;  //Sets float a to the textures UV + coordinate 0,1 (.a?)?
    maxa=max(a,maxa);               //Sets maxa to if float a or maxa is higher?
    mina=min(a,mina);                   //Sets mina to if float a or mina is lower?
    a=texture(TEXTURE,UV+vec2(1,0)).a;  //Again except for 1,0
    maxa=max(a,maxa); 
    mina=min(a,mina);

    COLOR = mix(col,aura_color,maxa-mina);//No idea how to use mix ...
}

My comments are my trying to understand the language.
Anyways, this seems to set the color of the edges fine, but I'm not sure where to go from here. I assume I need to use abs(sin(TIME)) somewhere but I'm not sure where to start.

I appreciate any help or point in the right direction.

Answers

  • MegalomaniakMegalomaniak Posts: 4,430Admin

    a scalar float is a floating point number such as 1.0, 2.0 3.1415... etc. In a shader a vector will hold a float value for/per each pixel/texel.

    For the named floats such as minA and maxA in your example it may seem confusing that they both get assigned col.a but that is just what you are initializing them to, then you will go on to work with the data and the two end up different enough from each other to be useful:

    The format is: function(inputs)
    max(a, maxA); // Gets 2 inputs > for each pixel picks whichever value from the two given is bigger.
    min(a, minA); // Gets 2 inputs > for each pixel picks whichever value from the two given is smaller.

    texture(tex, uv) takes two inputs first one of course is the identifier to a image that would be loaded as texture and after the comma the second is the UV coordinates according to which the image shall be mapped to the sprite/mesh.

    vec2(x, y) is a 2 dimensional vector.
    vec3(x, y, z) is a 3 dimensional vector.
    vec4(x, y, z, w) is a 4 dimensional vector.

    Typically a vector in graphics context is a point in space where in physics its a direction in space(for that in graphics we normally need 2 or more vectors). In shaders everything we do applies per pixel however, so when you are adding the vec2 to the UV coords: UV+vec2(0,1) you are adding something to each pixel coordinate either along x, y, or both(in this case 1 to y).

    Now I've written them as xy, xyz, xyzw in the above example because we were dealing with coordinates however they can be just as well looked at this way:

    vec2(r, g)
    vec3(r, g, b)
    vec4(r, g, b, a)

    Hope you are recognizing this already, I'm now holding color channels in the vector fields. Makes sense? Vectors are just a type of datablock. Vectors can be named.

    vec4 named_vector = vec4(0.25, 0.5, 0.75, 1.0); // r, g, b, a

    Vectors can not only be read from, but in any order(sizzled):

    float a = named_vector.a; // defining float named a > assigning its value to be derivative value a from the named_vector above

    vec3 color_b = named_vector.brg // so color_b will hold the named_vector values in the order input so in this example assigned .brg will become color_b's .rgb: color_b == vec3(0.75, 0.25, 0.5).

    Ok, enough about that. lets talk about that mix node:

    mix(vec a, vec b, float c); // the vectors are what will get mixed together, the float defines how much the values will be mixed together: if float is 0.0 then output value of a, if 1.0 output value of b. if 0.5 them mix exactly half the value of a and half the value of b.

    mix() can also be used with all vector inputs, where the third vectors values determine how each individual pixel from the others gets mixed.

    More can be read at:
    http://docs.godotengine.org/en/3.0/tutorials/shading/shading_language.html

  • kaleidxkaleidx Posts: 6Member

    Wow, thanks for your very complete explanation.
    I think I learn best from examples with comments to see what exactly is doing what and how, so something like this is a great help. I did find the docs and go through them but struggle figuring out how to use them in practice which is why I try to find examples which are few and far, much less commented.

    I do have a follow up question though, which I hope I'm understanding correctly.
    Perhaps I'm misunderstanding because of the naming convention used but I don't understand what col.a is doing exactly. Or what adding .a to a named vector does. I can't do calculus. :'(
    Well, let me take one more step back. So col is a named 4d vector getting its (r,g,b,a) values from the texture and its UV coords? So that means it's simply getting every pixels values from the current image?

    So with float maxa=col.a and float mina=col.a, It's setting maxa to vec4 col's what, exactly?

  • MegalomaniakMegalomaniak Posts: 4,430Admin

    Col is like a picture in an image editor with 4 channels: Red, Green, Blue and Alpha. It has an alpha channel because when you define it you define Col as vec4. With the assignment operator( = ) you are assigning the forth field from col(that is col.a) to the floats named maxa and mina.

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file