• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Outline Text Shader

JeanSwamp

Member
Hey!

I've been messing around with different ways of outline shader, and also checking examples of outline shaders. I've tried to apply the logic to fonts, using font_get_texture instead of sprite_get_texture and I was somewhat close of getting a working font outline, if the outline was just 1px.

This is just fine for pixelart games, however for high res games, 1px outline is not enough, and once the outline gets bigger you start seeing straight lines on the edges. I don't have any screenshot, but I reproduced what I remember happening in Photoshop to showcase what I mean:

69CR49Ljjh.png

Currently, due to not being able to use a shader I am running 8 draw_text to create a smooth outline, and even then sometimes is not very good, depending on font and size.

Has anyone succesfully made an outline shader? Cause I can't seem to find anything on the forums neither on youtube/reddit.
 

JeanSwamp

Member
I just bought it for testing, and this is an absolute garbage, the performance is like 5000% times worse than drawing text 8 times per string.

Profiler info:

243 calls of draw_text_transformed_color 18% step
22 calls of the outline_draw_text given in the asset 43% step

Why would anyone sell something like this?
 
Last edited:

Gizmo199

Member
What you should do is draw your text + anything else you want to have an outline to a surface and apply a standard outline shader to that surface. The reason being each text character is made of vertices where the texture of the letter is displayed. These vertices are pretty small and don't give you a lot of wiggle room to draw in the 'transparent' portions of them. By drawing the text first to a surface you essentially have the entire surface as your vertice. This is also useful if you want to have other elements outlined like items since you can just target your outline surface and draw the said sprite.

here is a shader I whipped up a while ago:
VERTEX SHADER
GML:
//
// Simple passthrough vertex shader
//
attribute vec3 in_Position;                  // (x,y,z)
//attribute vec3 in_Normal;                  // (x,y,z)     unused in this shader.
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
  
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}
FRAGMENT SHADER
GML:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    float outLineSize  = 0.002;
    vec4  outLineColor = vec4(1.0, 0.0, 0.0, 1.0);
  
    vec2 UV = v_vTexcoord;
    vec4 tcol = texture2D(gm_BaseTexture, UV);
  
    if (tcol.a == 0.0)
    {
        if (texture2D(gm_BaseTexture, UV + vec2(0.0,          outLineSize)).a  != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(0.0,         -outLineSize)).a  != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(outLineSize,  0.0)).a          != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(-outLineSize, 0.0)).a          != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(-outLineSize, outLineSize)).a  != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(-outLineSize, -outLineSize)).a != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(outLineSize,  outLineSize)).a  != 0.0 ||
            texture2D(gm_BaseTexture, UV + vec2(outLineSize,  -outLineSize)).a != 0.0)
            tcol = outLineColor;
    }
  
    gl_FragColor = tcol;
  
}

I also HIGHLY recommend this video about outline shaders by @Dragonite

ETA: note that the surface method is super efficient but anything 'intersecting' will conjoin the outline into 1. Eg. If you have two circle sprites overlapped the outline would only outline them both at the same time and not individually.

Here is an example of that shader in action. Each 'bullet' is being drawn to an outline surface.
capture.png

anyway, I hope it helps! :)
 
Last edited:

JeanSwamp

Member
Thanks for the info!

Do you know if this could cause problems drawing the text (that is rendered as a surface) to another surface?

Also, the image you showcased is using your shader, or the video?
 

Gizmo199

Member
Thanks for the info!

Do you know if this could cause problems drawing the text (that is rendered as a surface) to another surface?

Also, the image you showcased is using your shader, or the video?
The image is from my shader (it looks a bit funny because I don't have the app surface properly scaled. haha). And no, you should be fine as long as you draw that surface to the other surface. :)
 
Top