Hi, thanks for your help Ken. I definitely appreciate it.
Fonts just look bad unless they are rendered at or very close to the same size as their pixel value. At least with regular filtering. Mipmapping might help. In your comment you seem to say that there will not be a mipmapping option in the next release. I vote that there should be.
I’ve come up with what I think is a workable approach. Actually two approaches-- one uses drawText3D and one uses drawText.
approach 1:
immediately after making the main frame visible, but before initializing the GL eventListener I call this method:
public void makeFonts(String fontName)
{
Graphics2D g2D = (Graphics2D) frame.getGraphics();
FontRenderContext frc = g2D.getFontRenderContext();
for (int i = 18; i < 400; i+=4) //or whatev...
{
fonts.add(new FontInfo(new Font(fontName, Font.PLAIN, i), frc));
}
}
Of course you can alter the loop to use less fonts. But even if I create 400 fonts the application loads immediately. I haven’t tested if there is any performance/memory penalty by loading up so many text textures.
FontInfo is basically a struct which holds information about the font and also the TextRenderer for this font as well.
public class FontInfo
{
public Font font;
public FontRenderContext frc;
public Rectangle2D bounds;
public float w;
public float h;
public TextRenderer textRenderer = null;
public FontInfo(Font font, FontRenderContext frc)
{
this.font = font;
this.frc = frc;
this.bounds = font.getMaxCharBounds(frc);
this.w = (float) (bounds.getWidth());
this.h = (float) (bounds.getHeight());
}
Now within my rendering loop I have a method which determines the appropriate TextRenderer to use based both on a projection of the width in world space to the pixel width in screen space and also the number of characters to expect within this width. Non-monotype fonts of course have different widths for different characters of course. So I use the maximum width (using “(font.getMaxCharBounds(frc)).getWidth()” to calculate.
The projection uses glProject, which is probably pretty standard and I put in another posting.
So, I have a pixelWidth of a character which I compare against the max width of a character using the font and fontsize. Using this I can pick the appropriate font for the particular coordinates in world space.
Then I create a scale value for the draw3D function and use it like so:
float scaleVal = (worldSpaceWidth / numCharsToFitIntoWorldSpaceWidth) / maxWithOfCharForFontWeJustChose;
textRenderer.draw3D("text", worldX, worldY, worldZ, scaleVal);
This works great. Two slight issues. There is slight fuzzing when between fonts. That is, if I have a TextRenderer for font size 18 and another for font size 24, it will be slightly fuzzy when it can’t find a render for font size 22.25 or whatever and chooses the closest one it can. I think mipmapping would solve this. The other issue is that fonts look slightly different even when just one size apart, especially in the lower sizes, like 9 to 10. Jumping between these sizes is a bit jarring. So there’s a tradeoff between bluriness/aliasing and jumpiness. At larger sizes it doesn’t look as bad.
approach 2:
This is a bit simpler. I find the appropriate sized font in the same way as above. Then I find the screen coordinate of where I want to put the text in pixels using glProject. Then I use textRenderer.draw method using those pixel coordinates.
This I guess is a bit cleaner in that the text will always look sharp, but there is no way to get in-between values and any switch to a differently sized font is abrupt.
Ok this is pretty wordy. Anyhow, if anyone has any other approaches I would be interested in hearing them. It definitely seems that font sharpness is dependent on the pixel width of the area you are drawing on. Also, this assumes that the font is always straight-on. If the z-coord wasn’t the same across the object then there would be an issue with this method.
-spiraljetty