Blog

Adding Text-To-Texture at Runtime in Unity3D Without Using Render Texture

August 20, 2010 by Devin Reimer

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

  1. Create a font image in a grid pattern and collect kerning values (either manually or using the Unity Font Mapper)
  2. Import the font image(texture) into Unity and select ‘Build Alpha From Grayscale’ and set ‘Is Readable’ to true.
  3. Add this texture to a material
  4. 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)
  5. 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.

23 Responses to "Adding Text-To-Texture at Runtime in Unity3D Without Using Render Texture"

  1. Rafael says:

    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 ;)

  2. Devin Reimer says:

    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.

  3. Michael says:

    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?

  4. Devin Reimer says:

    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.

  5. 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.

  6. 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).

  7. 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!

  8. Devin Reimer says:

    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.

  9. 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?

  10. Devin Reimer says:

    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.

  11. Marty Plumbo says:

    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?

  12. Devin Reimer says:

    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.

  13. Antonio says:

    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

  14. Jonathan says:

    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.

  15. Guillermo Flores says:

    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.

    • Devin Reimer says:

      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.

  16. Mike Canty says:

    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.

  17. Johan says:

    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.

    • Abdul says:

      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

  18. Abdul says:

    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

Leave a response