Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 8 of 8

Thread: Creating a white outline around text texture Open-ES 2.0

Hybrid View

  1. #1
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39

    Creating a white outline around text texture Open-ES 2.0

    Hi, I have just learned how to render text on to the screen. This text is rendered on top of a map. For clarity, what I would like to do is make a white outline or glow (just a couple of pixels wide) around the rendered text.

    The fonts come from a ttf file and get transformed into a bitmap texture atlas.

    Below is a screen shot: (Bottom left is where the text is)
    Click image for larger version. 

Name:	device-2013-10-28-023405.jpg 
Views:	114 
Size:	9.7 KB 
ID:	1172

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    645
    You could first draw the text with the bold form of the font in white and then draw the regular text on top of it. Valve's technique using distance fields to store the font glyphs (paper) also allows adding an outline in a shader.

  3. #3
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    Thanks Carsten, I think if I can implement it in the shader I will, however implementing what Valve has done into it has got me a little baffled.

    Below is my vertex and fragment shader.

    public static String getFontVertexShader()
    {
    return
    "precision highp float; \n"
    + "uniform mat4 u_MVPMatrix; \n" // An array representing the combined model/view/projection matrices for each sprite

    + "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
    + "attribute vec2 a_TexCoordinate; \n" // Per-vertex texture coordinate information we will pass in
    + "varying vec2 v_TexCoordinate; \n" // This will be passed into the fragment shader.
    + "void main() \n" // The entry point for our vertex shader.
    + "{ \n"
    + " v_TexCoordinate = a_TexCoordinate; \n"
    + " gl_Position = u_MVPMatrix * a_Position; \n" // gl_Position is a special variable used to store the final position.
    + "} \n";
    }

    public static String getFontFragmentShader()
    {
    return
    "precision highp float; \n" // Set the default precision to medium. We don't need as high of a precision in the fragment shader.
    + "uniform sampler2D u_Texture; \n" // The input texture.
    + "uniform vec4 u_Color; \n"
    + "varying vec2 v_TexCoordinate; \n" // Interpolated texture coordinate per fragment.

    + "void main() \n" // The entry point for our fragment shader.
    + "{ \n"
    + " gl_FragColor = (u_Color * texture2D(u_Texture, v_TexCoordinate).w); \n"
    + "} \n";
    }

    Would really appreciate help on this

  4. #4
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    645
    Hmm, what exactly is your question?
    As a simpler alternative and since (if I read it correctly) you are only using the alpha channel of your texture you could implement a simple edge detection in your fragment shader and use a different colour if you detect an edge texel. For the edge detection, in addition to sampling at the fragment's texture location sample neighbouring texels and determine if the values are "similar enough" - you should be able to find lots of material on this, since it is used for many post processing effects as well as a whole bunch of anti-aliasing techniques.

    PS: source code is usually easier to read in a monospace font, [code][/code] tags should take care of that.

  5. #5
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    Yes I am only using the alpha. Edge detection sounds promising I will check it out.
    PSS: Next time round I will do that.

  6. #6
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    I have found this fragment shader at example:

    Code :
    precision mediump float;
    uniform sampler2D u_Texture;
    varying vec2 v_TexCoordinate;
     
    void main()
    {
    vec3 irgb = texture2D(u_Texture, v_TexCoordinate).rgb;
    float ResS = 720.;
    float ResT = 720.;
     
    vec2 stp0 = vec2(1./ResS, 0.);
    vec2 st0p = vec2(0., 1./ResT);
    vec2 stpp = vec2(1./ResS, 1./ResT);
    vec2 stpm = vec2(1./ResS, -1./ResT);
     
    const vec3 W = vec3(0.2125, 0.7154, 0.0721);
     
    float i00 = dot(texture2D(u_Texture, v_TexCoordinate).rgb, W);
    float im1m1 = dot(texture2D(u_Texture, v_TexCoordinate-stpp).rgb, W);
    float ip1p1 = dot(texture2D(u_Texture, v_TexCoordinate+stpp).rgb, W);
    float im1p1 = dot(texture2D(u_Texture, v_TexCoordinate-stpm).rgb, W);
    float ip1m1 = dot(texture2D(u_Texture, v_TexCoordinate+stpm).rgb, W);
    float im10 = dot(texture2D(u_Texture, v_TexCoordinate-stp0).rgb, W);
    float ip10 = dot(texture2D(u_Texture, v_TexCoordinate+stp0).rgb, W);
    float i0m1 = dot(texture2D(u_Texture, v_TexCoordinate-st0p).rgb, W);
    float i0p1 = dot(texture2D(u_Texture, v_TexCoordinate+st0p).rgb, W);
    float h = -1.*im1p1 - 2.*i0p1 - 1.*ip1p1 + 1.*im1m1 + 2.*i0m1 + 1.*ip1m1;
    float v = -1.*im1m1 - 2.*im10 - 1.*im1p1 + 1.*ip1m1 + 2.*ip10 + 1.*ip1p1;
    float mag = length(vec2(h, v));
     vec3 target = vec3(mag, mag, mag);
    gl_FragColor = vec4(mix(irgb, target, 1.0),1.);
     }

    I have altered this so ResS = 17, ResT = 24 for my own texture size.
    After testing this however it just displays a black box, I guess this is caused by the fact that it is not using alpha?

    My questions are:
    What do I need to change to get it to work with alpha.
    and
    What is the process, do I do two draws first to draw the white edge I am after, then do a second draw for the actual text itself?

  7. #7
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    645
    If I'm reading it correctly it converts each RGB sample to a luminance value (with the dot product with W). I suppose you could try getting rid of that and just use the alpha component of the texture. What also looks odd is the mix() call at the bottom, since the last parameter is a constant it does not really interpolate between irgb and target, but always uses the value of target.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •