haymo's picture

TextureFont - (yet again), texture coord correction

... just figured out the possible cause of the artefacts described in that thread. Texture coordinates should obviously be related to the center of the edge pixels in texture image given in TexSubImage2D. Right now, in the TextureFont class they point to the outside edge of those pixels. Therefore - for linear texture mapping - situations exist, where the neighboring pixels from the texture sheet are used for interpolating the edge pixels in the rasterizing step.

After a short test, it seems the corresponding code in TextureFont should be like this:

 rectangle = RectangleF.FromLTRB(
                (rect.Left + 0.5f) / texture_width,
                (rect.Top + 0.5f) / texture_height,
                (rect.Right - 0.5f) / texture_width,
                (rect.Bottom - 0.5f) / texture_height);
 
            loaded_glyphs.Add(g.Character, rectangle);

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

I see what you mean, but how could this cause problems in the *middle* of the glyph? If that picture showed an interpolation artifact, wouldn't the problem appear at the border texels only?

haymo's picture

I guess, the artefacts in the picture (from the old thread) can be explained by that issue. In the word "Roman" for example are 2 vertical lines visible, disturbing the "m" character. The first of them might come from the right edge of the previous char ('o'), the second one comes from the left edge of the 'a' following the 'm' (I suspect).

haymo's picture

It took me some hours to figure out, how to archieve the same nice crisp rendering result with the texture offset described above. Especially small fonts looked blurry again. One has to offset and decrease the quads also! Now its working - even when drawing in world coords no such ugly artefacts appeared anymore.

One more thing I found out (by accident). You probably know already:
While storing the glyphs in the texture storage, one does not have to copy the sub-bitmap into a fresh array before. There are usefull PixelStore parameters enabling us to define the offset in the bitmap array:

             GL.BindTexture(TextureTarget.Texture2D, m_textureId);
            BitmapData bmp_data = bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height), 
                                    ImageLockMode.ReadOnly,
                                     System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            // setup OpenGL pixel store
            GL.PixelStore(PixelStoreParameter.UnpackAlignment,1.0f); 
            GL.PixelStore(PixelStoreParameter.UnpackRowLength,bmp.Width); 
            GL.PixelStore(PixelStoreParameter.UnpackSkipRows,bmpRect.Y); 
            GL.PixelStore(PixelStoreParameter.UnpackSkipPixels,bmpRect.X); 
            GL.TexSubImage2D(TextureTarget.Texture2D, 0, (int)rect.Left, (int)rect.Top,
                                        bmpRect.Width, bmpRect.Height,
                                        OpenTK.Graphics.PixelFormat.Rgba, 
                                        PixelType.UnsignedByte, bmp_data.Scan0);
            bmp.UnlockBits(bmp_data);

This theoretically even works with other then 4bpp-formats. One has to watch out for the UnpackAlignment than.

the Fiddler's picture

Thanks, I was sure there was a way to avoid copying the sub-bitmap, but never managed to nail it. This will significantly speed up glyph loading.

haymo's picture

In the technical FAQ Wiki on the OpenGL website, I found another (maybe even easier?) workaround:
======================================================
When you have a 2D or 3D or Cubemap texture and you want to clamp the texture coordinates, if you use

glTexParameteri(GL_TEXTURE_X, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_X, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_X, GL_TEXTURE_WRAP_R, GL_CLAMP); //For 3D textures

then when sampling takes place at the edges of the texture, it will filter with border color so you might see black edges.
By default, the border color is black.
Instead of GL_CLAMP, use GL_CLAMP_TO_EDGE.

Link to that wiki

the Fiddler's picture

Ah, of course. Thanks!