Text outline shader

I was toying around with a glowing method and tried it on some text, it didn’t work out great so I condensed it and turned it black to create a smooth text outline which has IMO a nice effect.
The down side is you need to setContext to an image and put it on a mesh.


--# Main
-- TextOutline

-- Use this function to perform your initial setup
function setup()
    m = mesh()
    r = m:addRect(WIDTH/2,HEIGHT/2,300,300)
    txtre = image(300,300)
    setContext(txtre)
    pushStyle()
        fill(50,255,0)
        fontSize(50)
        font("AmericanTypewriter")
        textWrapWidth(280)
        textMode(CENTER)
        text("Text Outline! abcdefghijklmnopqrstuvwxyz",150,150)
    popStyle()
    setContext()
    m.texture = txtre
    m.shader = shader(shadr.vS,shadr.fS)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(131, 131, 190, 255)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    m:draw()
end

shadr = {vS = [[

uniform mat4 modelViewProjection;

attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;
    
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
]],
fS = [[
uniform sampler2D texture;
varying highp vec2 vTexCoord;

void main()
{
    highp float radius = 0.01;
    mediump vec4 ot = vec4(0.0);
    mediump vec4 normal = vec4(0.0);
    mediump float x = 0.0;
    mediump float y = 0.0;
    normal = texture2D(texture, vec2(vTexCoord.s,vTexCoord.t));
    for(int i=1;i<5; i++){
    x+=0.1;
    y+=0.1;
    ot += texture2D(texture, vec2(vTexCoord.s-radius*x,
    vTexCoord.t-radius*y));
    ot += texture2D(texture, vec2(vTexCoord.s+radius*x,
    vTexCoord.t-radius*y));
    ot += texture2D(texture, vec2(vTexCoord.s+radius*x,
    vTexCoord.t+radius*y));
    ot += texture2D(texture, vec2(vTexCoord.s-radius*x,
    vTexCoord.t+radius*y));
    }
    ot *= 1.0;
    ot.rgb = vec3(0,0,0);
    //accum.a = 1.0;
    normal = (ot * (1.0-normal.a)) + (normal * normal.a);
    gl_FragColor = normal;
}
]]
}

Very nice job :slight_smile:

also, I got a little question about shaders, since you know alot about them, every shader only works with a mesh…? or not…?

I know far from a lot! Just experimenting with the fragment shader mostly. You can only set a shader to a mesh though.

Little update made it smoother and added width:


--# Main
-- TextOutline

-- Use this function to perform your initial setup
function setup()
    m = mesh()
    r = m:addRect(WIDTH/2,HEIGHT/2,300,300)
    txtre = image(400,400)
    setContext(txtre)
    pushStyle()
        fill(255, 248, 0, 255)
        fontSize(50)
        font("Noteworthy-Bold")
        textWrapWidth(350)
        textMode(CENTER)
        text("Text Outline! ABCDFGHIJKLMNOPQRSTUVWXYZ?",200,200)
        fill(0,0)
        strokeWidth(2)
        stroke(0,255)
        rect(0,0,400,400)
    popStyle()
    setContext()
    m.texture = txtre
    m.shader = shader(shadr.vS,shadr.fS)
    m.shader.width = 2
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(131, 131, 190, 255)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    m:draw()
end

shadr = {vS = [[

uniform mat4 modelViewProjection;

attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;
    
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
]],
fS = [[
uniform sampler2D texture;
varying highp vec2 vTexCoord;
uniform highp float width;

void main()
{
    highp float radius = 0.01;
    mediump vec4 ot = vec4(0.0);
    mediump vec4 normal = vec4(0.0);
    mediump float x = 0.0;
    mediump float y = 0.0;
    normal = texture2D(texture, vec2(vTexCoord.s,vTexCoord.t));
    for(int i=1;i<12; i++){
    x=sin(float(i)*0.5)*width*0.3;
    y=cos(float(i)*0.5)*width*0.3;
    ot += texture2D(texture, vec2(vTexCoord.s-radius*x,
    vTexCoord.t-radius*y));
    ot += texture2D(texture, vec2(vTexCoord.s+radius*x,
    vTexCoord.t-radius*y));
    ot += texture2D(texture, vec2(vTexCoord.s+radius*x,
    vTexCoord.t+radius*y));
    ot += texture2D(texture, vec2(vTexCoord.s-radius*x,
    vTexCoord.t+radius*y));
    }
    ot *= 0.4;
    ot.rgb = vec3(0,0,0);
    //accum.a = 1.0;
    normal = (ot * (1.0-normal.a)) + (normal * normal.a);
    gl_FragColor = normal;
}
]]
}

I’ll have to try this. Thanks!

It’s works better than expected, even on fontsizes of 10 with a width of .5 to make it look more noticeable.

You need to replace m.shader = shader("Documents:OutlineGlow") with m.shader = shader(shadr.vS,shadr.fS).

Oops, sorry! Fixed.

Doesnt work for me. The previous one did. Dont know what is wrong.

@Jmv38 same here, I’m on ipad3

It’s not working for me (I assumed it was an issue with the beta).

sorry if its not working guys I’ll take a look when I get back home.

very great, i like it. just first version works on ipad 2 32Go.

thanks, I’m not able to fix the second one at the moment as I’m not at home for a while, I will edit the post with what I think is the fix now but I can’t promise anything!

@Luatee yes it works now, looking good :wink:

@Stevon8ter thanks bud, I think theres a small problem when using the shader on sprites when the direction is true south and east, it stops blending making it look flat on the side but this isnt the case with text I don’t think