I was working on a library in Unity that was using a lot of 3D text and therefore was requiring a lot of draw calls. This got me thinking, since all the pieces of text were on the same orientation plane would there be a way instead to draw all the text to a one texture and render that instead. Another benefit of doing this would be you could then apply text at runtime to a non-flat mesh via a texture. This would allow you to do cool things like personalizing a player’s jersey with the user’s name, localizing complex in-game advertisements, etc. So I decided to look into this. What started as a few experiments turned into not so small project.
Doing research I found a way of achieving this using Render Texture. What you could do was by using either with GUI text or 3D Text place a camera to capture a single frame and render it to a texture. While not completely straightforward or easy it does work and allows quite a bit of flexibility on what you are creating. This method does come with a drawback, it needs Render Texture support. Only Unity Pro supports Render Texture, plus they are not supported on the iPhone (Unity Feature Breakdown).
Since my goal was to create a library that all Unity developers could use, this was not an acceptable solution.
My next idea was to manually draw the text to a texture using SetPixels. While the performance of writing to a texture using SetPixels is less than ideal, I only needed to do this once.
Note: The reason why this is so slow is after calling setPixel(s) you have to call Apply which send the whole texture to the GPU. The Apply method is unfortunately very slow, but is “usable” if you are not needing to call it repeatedly.
I thought developing this using this method shouldn’t be too bad as I knew when you import a font into Unity, Unity automatically creates a texture containing the font. What I didn’t anticipate was that the letters were not in a grid format, but places tightly together. With no runtime access to letter position data, this was not going to work.
Next on my list was Custom Font, a feature where you can “easily” create your own font in Unity. With Custom Font you supply your own font image laid out in a grid. Using this method I could determine where the letters were positioned. I now needed a way create a font image in a grid pattern and get all the Per Character Kerning values from a font.
In digging through the internet I came across a few mentions of something called the Unity Font Mapper. It took me a very long time but I finally tracked down a link to the app: http://loewald.com/unity/unityfontmapper.zip. This Mac application not only generates the font image in a grid pattern, but generates a file containing the Per Character Kerning information.
Once I had a Custom Font working I then discovered there is no programming access to any of its properties (I still use Custom Font as part of my final solution in hopes at some point access will be opened up to those values). This means these values now needed to be entered twice if you want to use the same font for both a Text-to-Texture font and as a regular font.
I now had all the pieces and it was just a matter of putting it all together. While the current version of this code is far from perfect and is missing features like colored text it does exactly what I wanted it to do.
To check out the demo click here.
To get the source (unitypackage) click here.
To get only the TextToTexture class (TextToTexture.cs) click here.
Source Requirements: Unity 2.6
Setup Steps
- Create a font image in a grid pattern and collect kerning values (either manually or using the Unity Font Mapper)
- Import the font image(texture) into Unity and select ‘Build Alpha From Grayscale’ and set ‘Is Readable’ to true.
- Add this texture to a material
- Within Unity create a Custom Font. If you aren’t wanting to use this font for anything but Text-to-Texture you can just setup the basics and ignore the Per Character Kerning values within the Custom Font (these take a long time to enter)
- Create a script that calls TextToTexture and passes all the required information (example in source: AddTextToTexture.cs)
Note: I used a Decal material in this demo so the text would appear on top of the primary texture. But you can use any material that you wish.
37 Responses to "Adding Text-To-Texture at Runtime in Unity3D Without Using Render Texture"
Hey man, could you help me?
I’m trying to run the project, but when i hit apply text to texture button, i get the message:
“Unsupported texture format – needs to be ARGB32, RGBA32, RGB24, Alpha8 or DXT”
This error occurs when you call GetPixels on fontTexture…
Tanks 😉
Hi @Rafael
In the texture’s inspector you will need to select Advanced. Check Read/Write Enabled, and then change from Automatic Compressed to one of those supported formats.
Give this a try and let me know if you have any other issues.
Hi, could you provide some more detail on how to use this?
I created a custom font (readable) and applied the script AddTextToTexture to a plane in my scene, the custom font is dragged onto ‘custom font’ var in the script inspector for AddTextToTexture.
Should the plane have a texture already mapped onto it – will this get replaced by the text texture?
I get no errors on runtime, but the plane in the scene doesn’t seem to get any text texture applied to it, and the framerate drops a bit also.
Can you tell me where I’m goin wrong?
Hi @Michael,
The mesh doesn’t need a texture already mapped onto it. But it does need a material with shader attached. In the Add Text to Texture inspector you need to change the Texture ID to the texture name used in the selected shader. In my example I used the Decal shader and the decal texture is called ‘_DecalTex’.
Let me know if this doesn’t solve your problem. If it still isn’t working feel free to send over your project or part of project and I can take a look.
Neat trick, and good access to the parameters. I’m also glad to see it dropped right in to Unity3.x with no problem. Thanks!
I’m working with Unity for a dome production application. Check my Google+ profile to see. http://bit.ly/tp3UWh
I’ll look to see if you are on G+ also.
One note: The downloaded project worked great. The pop-up demo didn’t – it said I needed to download the Unity webplayer, which I know I have. Possible it is looking for a previous version (for 2.6).
Hi Devin – I have this working on a different mesh and a different texture. But I have one issue: It’s not picking up the default kerning so all the letters are on top of each other. I see in the script that there is a table of kernings but (as you note in the script comment) I don’t want to have to enter this through the editor.
What can I do about that?
I know I’ll have other questions but I can puzzle through most of them once the text starts reading out properly.
Thanks!
Hi @Dave,
I ended up manually entering though values all though the editor. It was annoyingly time consuming but it worked. You might be able to write a Unity editor script that would do the heavy lifting for you.
Thanks for getting back to me quickly. I have another puzzle – letters seem to be upside down (I can spin my object but they seem to be trying to start too close to the margin of the texture). I will enter kernings and then see where I stand.
Also, I see y position in the editor. Is there an x starting position I can expose and adjust?
Hi @Dave,
Kernings should fix that, if not play around with FontX, FontY. As for starting position X that is something I did not add, but I don’t think it should be too hard to implement.
Awesome, Devin. I’m curious though, are there any benefits of this technique over mapping a camera to a texture in Unity Pro – other than not needing Pro?
Hi @Marty
When I first wrote this Render-To-Texture was also not supported on iOS, this has since changed (now supported in iOS Pro and Android Pro) but I’ve heard there are some size limitations with that.
Performance wise I’m unsure if there is a difference. With my method once complete it is like a normal texture. I don’t know if RenderTexture has any additional overhead.
Hi, thanks to you I could find a solution to paint text on a texture.
It works perfect but when I try to save this texture with the painted text, the resulting image has some inaccuracies
If you can help me, here is the project:
http://goo.gl/rdB6j
There you can find the package of the project and a more detailed explanation of my problem
Hello Devin,
I am trying to use
TextToTexture Script = new TextToTexture(_font, 1, 1, null, false);
Script.CreateTextToTexture(_group.Text, 0, 0, 1, 5, 1);
but I am getting an error
NullReferenceException: Object reference not set to an instance of an object
TextToTexture.GetCharacterKerningValuesFromPerCharacterKerning (.PerCharacterKerning[] perCharacterKerning) (at Assets/Scripts/TextToTexture.cs:241)
TextToTexture..ctor (UnityEngine.Font customFont, Int32 fontCountX, Int32 fontCountY, .PerCharacterKerning[] perCharacterKerning, Boolean supportSpecialCharacters) (at Assets/Scripts/TextToTexture.cs:50)
I know it’s because of the null that I put in, what should I pass in for the PerCharacterKerning[]. I am using the custom Arial font you provided.
Hi Jonathan,
You need to pass in the kerning values for each character. That implementation requires that to be done manually.
Is there anyway to put automatically the size and the characters in the PerCharacterKerning[] perCharacterKerning automatically with a foreach or something, I’m having a bad time here, someone please?
I’m still a newbie in c#, I now I can assign them in the inspector but It’s needed in like 50 game objects, if someone could give me a hint, would be appreciated, btw it’s the best job out there, congratulations Devin Reimer.
Hi Guillermo,
You might be able to write an editor script to that for you, but at the time I writing this code I didn’t know of a way to easily do that.
Sorry I can’t be more help.
no problem anyway, I’m going to give it a try by my own, and thanks a lot for sharing this.
Looking at this code gave me an idea. In order to have multiple text in different positions and rotations, I wonder if there is a way to rotate the text thats getting created (i.e. vertical or horizontal. if anyone has tried this I would be interested.
http://forum.unity3d.com/threads/220217-DrawText-on-Texture2D?p=1474196&viewfull=1#post1474196
Hi ,
It’ wonder full demo, i’am the beginer in unity3d.if any body help me out from this problem its greet..
just imported .FBX 3d model in unity3d and mapped text to texture to the model and even same i ‘am using same fonts which is give in the demo.
when click the button of text to texture that text is not fetching to my 3d model
here i found one thing , can’t able to getting the per character kernal values. is it necessary to get the character kernal values or any thing i have to do for font setup.
Hi @johan,
I think you have to apply the script on object having texture and don’t forget to select the Decal shader. I think you might be stuck their due to positions. Try to change positions.
Regards,
Abdul
Hi,
This has made my day. This is great awesome thing you have done. All the Best for All your future works.
Actually i need to apply the all above thing with transparency. I m not good at shader scripting , So will you please give some instructions for it. I need the text to texture effect plus transparency.
Regards,
Abdul
HELLO DOES NOT WORK IN UNITY 5.0 CAN YOU FIX THE TWO SCRIPTS THAT CAUSES THE BUGS
oh yeh ive forgotten to say thanks for your awesome scripts
You are totally wrong, that’s not Texture::Apply that is time consuming, it’s just SetPixel…
Hi, I am trying to apply the text to texture with the standard shader, which texture is should I use?, my current object has an albedo texture and emission texture, tried using detail albedo and didn’t go very well.
I’m impressed, I must say. Seldom do I come across a blog that’s both equally educative and interesting, and without a doubt, you’ve hit
the nail on the head. The problem is an issue that not enough people are speaking intelligently about.
I’m very happy that I came across this during my hunt
for something regarding this.
Hi Devin Reimer,
Thanks for your share good job…I wonder if we can add colors to text?
Thanks in advance!
If you desire to increase your know-how simply keep visiting this web page and be updated with the newest news posted
here.
Hi!
I read on commets that dosent work in Unity ver 5? Is that correct?
I have ver 5.61f1
Or are there another solutions? or New version? or what I’m doing wrong?
Thank´s for your time and helping me!
Regard
Micael Roxenhall
Hello,
I was searching for a solution like this to put a text into a sphere.
The solution worked for me (I’m using Unity version 2018.4.13f1).
Now I need to change the code to add more lines and characters. Any heads ups?
Thank you for your work and any help.
Best Regards
Gibrel
You can use special characters “//n” inside your text.
Just remember to set it TRUE when calling the TextToTexture function.
Inside the TextToTexture class you can find how it works:
”
if (letter == ‘\\’ && supportSpecialCharacters)
(…)
if (letter == ‘n’ || letter == ‘r’) //new line or return
”
Ok? Tell me if you got it
i would like to use UI input field to change to dynamic texture, but i dont now how to implement, could you tell me some tips? thanks
I tried to use the script but I get an error as
Cannot access pixel data of compressed texture formats which cannot be partially decompressed (such as Crunch).
Works on unity 2021.3.2f1, thank you.