- Home /
Custom font rendering in UI.Text via shader
Hi all, I am trying to achieve something for a couple of days now and find myself stuck. The problem briefly is :
A Character, lets say 'd' should show slightly displaced vertically upwards (by x) if the character before it was an 'a'. But if the character before it was 'e', it should be vertically displaced downwards (by x*2). I have a big set of similar conditions to meet for other characters. I can not use TextMesh, the text has to be UI.Text inside a 'Screen Space Camera'.
I initially got it working by modifying unused characters' glyphs so that they had the same letter 'd' but with different vertical offsets. But this approach is not viable for say 100 other such pair of characters.
So I took Unity's Built-In Font shader from here and tried to modify it for my requirement, but I have not had any success.
The following function is a monobehaviour method, called in Update, that I am using to set the parameters values of the shader
void SetDPos()
{
font.RequestCharactersInTexture(_str);
CharacterInfo dInfo = new CharacterInfo();
for (int i = 0; i < _str.Length; i++)
{
CharacterInfo ch;
font.GetCharacterInfo(_str[i], out ch);
if (_str[i] == 'd')
dInfo = ch;
}
float [] dArray = new float[]
{
dInfo.uvTopLeft.x,
dInfo.uvTopLeft.y,
dInfo.uvBottomRight.x,
dInfo.uvBottomRight.y
};
Material fontMaterial = _text.material;
fontMaterial.SetTexture("_MainTex", font.material.mainTexture);
fontMaterial.SetInt("_TexCoorCount", 1);
fontMaterial.SetFloatArray("_TexCoorArray", dArray); //two uv's of character d
_text.material = fontMaterial;
}
Then I changed the vertex function to take the uv values of character 'd', passed inside "_TexCoorArray" so that if the texcoord parameter was inside the uv coordinates, the vertex should be displaced by 10, as follows :
v2f vert (appdata_t v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.color = v.color * _Color;
for( int j = 0; j < _TexCoorCount; j+=4)
{
if(v.texcoord.x >= _TexCoorArray[j + 0] && v.texcoord.y >= _TexCoorArray[j + 1]
&& v.texcoord.x <= _TexCoorArray[j + 2] && v.texcoord.y <= _TexCoorArray[j + 3] )
{
v.vertex = float4(v.vertex.x + 10, v.vertex.y, v.vertex.z, v.vertex.w);
}
}
o.texcoord = (v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw);
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
But my condition never seems to be met. I believe the 'texcoord' is the uv for the font texture, and the parameter I am passing is also based on the same texture. Please guide me to a solution here, I am not familiar with writing shaders.
Answer by Xepherys · Jun 24, 2020 at 02:46 PM
I'm actually looking to see if I can implement SIL Graphite in Unity as either a wrapper or a replacement for the font renderer. This would be one possible use case, though it would require rebuilding your existing TTF/OTF font with Graphite SDL markup for your needs.
But, this sort of situation is a great example of the usefulness. Hopefully I can get something that'll work using the Graphite libraries.