Some questions about text

I can’t get small text to be rendered in a very sharp way. Usually it gets so blured it’s almost impossible to read. I noticed some games render very small text with almost pixel precision. How can we do this with panda?

Also noticed when rendering an onscreen text like this:

textnode = OnscreenText(text = text, 
                            pos = (-1.3, .95-.06*i), 
                            fg=(1,1,1,1),
                            align = TextNode.ALeft, 
                            scale = 0.05,
                            mayChange = 1)

I get the idea that the default font letters like the O or the P, without non-uniform scaling, should have been circular and not oval. Thus my impression that the text is being a little distorted (scaled down) on the horizontal.

It’s strange that when i reparent the text node to aspect2d nothing changes. When the textnode is reparented to render2d the shape of the letters is the right one (circular and not oval) and with much less bluring but the text becomes disaligned.

Any sugestion on how to solve these two problems?

Thanks in advance.

The idea makes sense, but unfortunatly it doesn’t work. Theres something else bluring the text. Maybe it needs some magic scale values that depend on the screen resolution we are using, together with clearAntilalias() in order for it to work.

I suspect it has something to do with the arguments you pass to loadFont; you can pass loader.loadFont(“font.ttf”, pixelsPerUnit=100) to get sharper text, as well as a few other keywords like pointSize it may be worth playing around with. It seems to work here, although I only just found it.

See panda3d.org/apiref.php?page=Loader#loadFont

You can disable any filtering on DynamicTextFont :

loader.loadFont(myfont,minFilter=0,magFilter=0)

but watchout, there are 2 syntax errors in showbase/Loader.py :

font.setMinFilter(minFilter)
font.setMagFilter(magFilter)

the setM…Filter should be setM…filter.

I have been toying with text with much better results. Im using Microsoft arial font that helps a lot.

Disabling the filters makes the text sharp like in a text editor or the letters in this post but some pixels disapear. In the worst case a ‘t’ for example, the pixels in the vertical bar disapear leaving only tree dots.

How can we render sharp text without disapearing pixels like the letters in this post?

Thanks in advance.

This is the best i can do.

#Load the ttf font.
f = loader.loadFont("Font/arial.ttf")
f.setPointSize(8) 
f.setPixelsPerUnit(30)
f.setScaleFactor(1)
f.setTextureMargin(2)
f.setMinfilter(0)
f.setMagfilter(0)

#Create a text node for a 800x600 pixels screen.
tx1 = TextNode("myText")
tn1 = render2d.attachNewNode(tx1)
tn1.setPos(0,0,0)
tx1.setText("Some text")
tx1.setFont(f)
tx1.setTextColor(1,1,1,1)
tx1.setAlign(TextNode.ACenter)
tn1.setScale(30.0/800.0,1.0,30.0/600.0)

It gets resonable small and readable sharp text but not pixel-perfect as the letters in this post.

That’s the right idea, though remember that the render2d coordinate system has a range of 2.0 in both dimensions (it goes from -1 to 1), so the actual scale to exactly match an 800 x 600 window will be twice what you have (that is, divide by 400, 300 instead of dividing by 800, 600). That’s why you’re not quite matching up yet.

Note that you can write the font texture out to disk, for instance as a .png file, so you can look at it closely outside of Panda and see exactly how big your letters are in the texture. In order to get pixel-accurate text, these must be exactly the same pixel size in the texture as they appear onscreen.

While I was testing this, I discovered that when you have set Texture.FTNearest as the minfilter and you are rendering very small text, the graphics card is likely to choose the wrong pixel as the nearest pixel on alternating letters–so you end up with text that doesn’t line up on the baseline. An easy fix is to offset the text by 0.5 of a texel in u and v, which should put the UV coordinate exactly in the center of the texel. This appears to fix the baseline problem, at least on my graphics card.

I’ll check in this fix, so it will get picked up by future versions of Panda; in the meantime, you can work around it by putting an explicit texture transform of (0.5/256, -0.5/256) on your TextNodes. Or even better, (0.4/256, -0.4/256), which will work with current versions of Panda, as well as with new versions that have my fix.

Here’s your example, modified to give truly pixel-accurate text, or at least as truly pixel-accurate as your 3-D card can do. (Note that 3-D cards in general don’t actually ever promise to deliver pixel-accurate rendering, so your mileage may vary.)

from direct.directbase.DirectStart import *
from pandac.PandaModules import *

#Load the ttf font.
f = loader.loadFont("Font/arial.ttf")
f.setPointSize(8)
f.setPixelsPerUnit(15)
f.setScaleFactor(1)
f.setTextureMargin(2)
f.setMinfilter(Texture.FTNearest)
f.setMagfilter(Texture.FTNearest)

#Create a text node for a 800x600 pixels screen.
tx1 = TextNode("myText")
tn1 = render2d.attachNewNode(tx1)
tn1.setPos(0,0,0)
tx1.setText("Some text")
tx1.setFont(f)
tx1.setTextColor(1,1,1,1)
tx1.setAlign(TextNode.ACenter)
tn1.setScale(15.0/400.0,1.0,15.0/300.0) 

# Apply an offset to fix the low-level pixel accuracy.  
tn1.setTexOffset(TextureStage.getDefault(), 0.4/256, -0.4/256)    

# Generate the text immediately, to force the letters
# into the font now, so we can dump the font to disk.
tx1.generate()

# Dump the font texture into an image file, so we 
# can inspect it outside of Panda and observe its 
# pixel size directly.
f.getPage(0).write(Filename('font_image.png'))

David

Thanks for the detailed help. Examining the saved png image shows some very soft and almost unnoticeable anti-aliasing. I couldn’t notice anything unless i zoomed on the text, so the text matches very close what i would get when using the same font and point size on a text editor.

You don’t even want the subtle antialiasing that FreeType provides? In that case, you can do:

f.setNativeAntialias(0)

to turn this off.

For myself, I kind of like the soft look that you get with all of the antialiasing turned on. Sure, it’s a little fuzzy, but it’s not pixelly in any way. :slight_smile:

David