- Home /
Identifying Rotated Glyphs in Font Texture
I'm using GetCharacterInfo to get the information for a glyph from a Font (which I have imported as a Unicode font, not a Dynamic font), and using that information to access the pixel data for the glyphs in a texture I get from Font.material's mainTexture, converted into a Texture2D. For the most part, CharacterInfo gives me what I need, except that some of the glyphs in the font texture are rotated. It appears they're rotated clockwise 90 degrees to be more efficiently packed.
This means that if I use the UV coordinates and size from the CharacterInfo to try to access that glyph's data, I instead get a partly clipped, sideways version of the glyph I want. If I knew whether a character was rotated, I would be able to account for that, but I can't figure out how to do that. How can I identify whether Unity decided to rotate a glyph sideways? Alternatively, can I force Unity not to do this when importing a font?
Answer by GarrickWinter · Jul 09, 2020 at 04:46 PM
So I've figured it out, with some help from the forums. Posting this here to hopefully save future people some time. There's a deprecated variable on CharInfo called flipped. This works, but it throws a warning, and might be removed in the future, so I don't feel safe relying on it.
warning CS0618: 'CharacterInfo.flipped' is obsolete: 'CharacterInfo.flipped is deprecated. Use uvBottomLeft, uvBottomRight, uvTopRight or uvTopLeft instead, which will be correct regardless of orientation.'
So I looked into it, and here's a roundabout way to establish whether a glyph is flipped from the new non-deprecated data:
//"charInfo" is a CharInfo populated with the given character's information
float uvWidth = charInfo.uvTopRight.x - charInfo.uvBottomLeft.x;
float uvHeight = charInfo.uvBottomLeft.y - charInfo.uvTopRight.y;
//"fontTexture2d" is a Texture2D containing the font's glyphs
int imgWidth = (int)(uvWidth * (float)fontTexture2d.width);
int imgHeight = (int)(uvHeight * (float)fontTexture2d.height);
//If the character is flipped, its width in the font texture will equal its height in the CharInfo
//If the character's width and height are equal, it won't be flipped, because flipping is only done to preserve space, so flipping a square is useless
bool flipped = (imgWidth != imgHeight && imgWidth == charInfo.glyphHeight);
Basically, you need to see if the stated dimensions of the glyph match the calculated dimensions of the glyph's space in the font texture. If they don't, you can then assume it has been flipped, and proceed to rotate your pixel array 90 degrees counterclockwise to fix the flipping.
Answer by Michael-Ryan · Nov 16, 2020 at 06:58 PM
Thanks for the tip, @GarrickWinter.
It seems like rotation can also be identified simply by examining one edge of the UV rect.
public static class CharacterInfoExtensions
{
public static bool IsRotated(this CharacterInfo charInfo)
{
var uvBL = charInfo.uvBottomLeft;
var uvBR = charInfo.uvBottomRight;
return uvBL.x.IsApproximatelyEqualTo(uvBR.x)
&& uvBL.y.IsNotApproximatelyEqualTo(uvBR.y);
}
}
When the X of the bottom left and right are the same, either the glyph has ZERO width, or it's rotated. If the Y of the bottom left and right are also different, then it's definitely rotated.
I use a couple extension methods for float equality testing. Those extension methods are here:
public static class FloatExtensions
{
internal const float Epsilon = 0.00001f;
/// <summary>
/// Compares two float values and tests to see if <paramref name="value1"/> is
/// equal to <paramref name="value2"/> taking the <paramref name="epsilon"/> into
/// account.
/// </summary>
/// <param name="value1">The first value.</param>
/// <param name="value2">The second value.</param>
/// <param name="epsilon">The epsilon.</param>
/// <returns>The result of the comparison.</returns>
public static bool IsApproximatelyEqualTo(this float value1, float value2, float epsilon = Epsilon)
{
return Mathf.Abs(value1 - value2) <= Math.Abs(value1 * epsilon);
}
/// <summary>
/// Compares two float values and tests to see if <paramref name="value1"/> is
/// not equal to <paramref name="value2"/> taking the <paramref name="epsilon"/>
/// into account.
/// </summary>
/// <param name="value1">The first value.</param>
/// <param name="value2">The second value.</param>
/// <param name="epsilon">The epsilon.</param>
/// <returns>The result of the comparison.</returns>
public static bool IsNotApproximatelyEqualTo(this float value1, float value2, float epsilon = Epsilon)
{
return IsApproximatelyEqualTo(value1, value2, epsilon) == false;
}
}
Your answer
Follow this Question
Related Questions
Text blurred: uGUI 4.6 9 Answers
Trying to make Fonts Fallbacks to real Bold/Italic font data 3 Answers
Unity 5.2 Text Rendering issue 0 Answers
Replacing transparency of text with a solid color? 1 Answer
Text Appearance Glitch in Unity UI, 5.3 0 Answers