Rendering Text in WebGL

Just like OpenGL and most rendering engines that I know of, WebGL has no builtin support for text rendering. And on top of that, I can’t use the approach we use in PointLine at the moment. PointLine gets the outlines for the characters from the Windows GDI. So I was looking for something cross platform.

Searching on the internet there are two main approaches:

  1. Render the alphabet or the word in question to an image, and then use that image to texture some triangles.
  2. Trace the outlines of the characters and triangulate the polygons.

Although I prefer the second approach, I found an example of the first that looked simple enough on nehe. It was based on FreeType and for OpenGL.  I started converting it to WebGL, but it was not as easy as it looked. It makes heavy use of display lists which are not available in WebGL.

So I looked further, and found the FTGL library which is also based on FreeType. It sounded like just what I need, but for OpenGL. So, I extended the library to allow me to extract the triangles for processing in WebGL. I sent my patch to the FTGL developers and hope for inclusion.

Meanwhile I can render texts in WebGL with my modified version of FTGL …  of course it’s only so easy to do when using Wt::WGLWidget from the excellent witty library.

Here is my research prototype which now has text.

Here are the important parts of how it’s done with the modified libftgl:

void WebGlWidget::initializeGL()
{

vertices_.clear();
FTGLTriangleExtractorFont font(fontName_.c_str(), vertices_);
font.FaceSize(textSize_);
font.Render(txt_.c_str());

const WebGlWidget::ShaderInfo& shinf = wglw.GetShaderByName(“Text”);
wglw.useProgram(shinf.shaderProgram_);

vertexPositionAttribute_ = wglw.getAttribLocation(shinf.shaderProgram_, “aVertexPosition”);
wglw.enableVertexAttribArray(vertexPositionAttribute_);

vertexBuffer_ = wglw.createBuffer();
wglw.bindBuffer(wglw.ARRAY_BUFFER, vertexBuffer_);
wglw.bufferDatafv(wglw.ARRAY_BUFFER, vertices_.begin(), vertices_.end(), wglw.STATIC_DRAW);
}

void WebGlWidget::paintGL()
{

const WebGlWidget::ShaderInfo& shinf = wglw.GetShaderByName(“Text”);
wglw.useProgram(shinf.shaderProgram_);

wglw.bindBuffer(wglw.ARRAY_BUFFER, vertexBuffer_);
wglw.vertexAttribPointer(vertexPositionAttribute_, 3, wglw.FLOAT, false, 3 * 4, 0);

wglw.drawArrays(wglw.TRIANGLE_STRIP, 0, vertices_.size() / 3);

}

Update:

I now maintain my changes to ftgl at github and in my ppa.

5 Replies to “Rendering Text in WebGL”

  1. Hi. Are you aware that passing in a string that contains spaces causes your implementation to segfault?

    #0 0x0894bf34 in FTVectoriser::MakeMesh (this=0x0, zNormal=1, outsetType=1, outsetSize=0)
    at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTVectoriser.cpp:266
    #1 0x08949ce6 in FTTriangleExtractorGlyphImpl::RenderImpl (this=0xb6014810, pen=…, renderMode=65535)
    at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTGlyph/FTTriangleExtractorGlyph.cpp:101
    #2 0x0894a89b in FTGlyphContainer::Render (this=0xb6005ea8, charCode=32, nextCharCode=51, penPosition=…,
    renderMode=65535) at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTGlyphContainer.cpp:114
    #3 0x08946ec0 in RenderI (this=0xb6000b18, string=0xb75fbd74 “12 34”, len=-1, position=…,
    spacing=…, renderMode=65535) at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTFont/FTFont.cpp:493
    #4 FTFontImpl::Render (this=0xb6000b18, string=0xb75fbd74 “12 34”, len=-1, position=…, spacing=…,
    renderMode=65535) at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTFont/FTFont.cpp:511
    #5 0x08947b56 in RenderI (this=0xb6000b18, string=0xb75fbd74 “12 34”, len=-1, position=…,
    spacing=…, renderMode=65535)
    at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTFont/FTTriangleExtractorFont.cpp:97
    #6 FTTriangleExtractorFontImpl::Render (this=0xb6000b18, string=0xb75fbd74 “12 34”, len=-1, position=…,
    spacing=…, renderMode=65535)
    at /devel/cockpit/FOQA/ftgl-2.1.3/src/FTFont/FTTriangleExtractorFont.cpp:107
    #7 0x089454e5 in FTFont::Render (this=0xb60097a0, string=0xb75fbd74 “12 34”, len=-1, position=…,

  2. Hi Norman,

    no, I wasn’t aware, at least I can’t remember.
    Although looking at my demo program where I output “HelloWorld” without a blank, I have the impression, that I must have noticed, but didn’t put it on my todo list.
    I will investigate…
    What is your application?

    Rgds
    Richard

  3. Hi Norman,

    The fix is very easy. Your stack trace leads right to where it is:

    const FTPoint& FTTriangleExtractorGlyphImpl::RenderImpl(const FTPoint& pen,
    int renderMode)
    {
    (void)renderMode;

    if(NULL == vectoriser)
    return advance;

    vectoriser->MakeMesh(1.0, 1, outset);

    Just add the ckeck for NULL, and the bug is fixed.
    I will upload the fixed version to my ppa soon, but since you provided the stack trace, you compiled it yourself anyway.

    Thanks for reporting.

    Rgds
    Richard

  4. Hi

    I’m trying a simple example with your patch, but it doesn’t work. I have two segmentation fault using the functions FaceSize and Render like your example.

    My question is, what are the type of txt_ and txtSize_ ? They are string and int ? And what values have you put ?

    It’s the first time I’m using this library …

    Thank you a lot

    Regards,
    Bart

    1. Hi,

      I resolved the problem. The two are string but the fontName_ has to give the path of a file .tff

      Another problem, the resolution of the FaceSize doesn’t work. We can change the resolution. It doesn’t affect the text size.

      I’m looking for what we have to change but I don’t find…

      Thanks

      Regards
      Bart

Leave a Reply

Your email address will not be published. Required fields are marked *