Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
September 2, 2014
arrowPress Releases
September 2, 2014
PR Newswire
View All
View All     Submit Event





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
Importing Textures Into Unity
by Amir Barak on 05/19/14 10:02:00 am   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

I'm usually better at the whole pun for title thing, honest.

Importing textures into Unity is usually a fairly simple process involving the following steps;

  • Copy image into assets folder.
  • Update import settings.
  • Apply import settings.
  • Rinse/Repeat.

Yup, no problems there. Except that the projects I'm currently working on have A LOT of textures. And you know what, even if they didn't, I'm lazy. I can't stand manually doing something which can be automated. Oops, gave away the rest of the post. Let's automate.

Disclaimer; the system I'm actually using has evolved from this simple concept and is not presented here. The core idea though is the same.

First though let's address the question burning in everyone's mind. Amir, why do you even want to automate it?? That's just crazy!

Well, yeah, sort of. But not all textures should be treated the same, meaning not all textures require the same import values. And that means that unless we have a mechanism for grouping images we're going to have to remember to update everything and every time we bring in a new file. And for me, that way lies madness.

Secondly, how do we group textures?

I'm glad you asked. At the moment, by folders. This way we can have a folder for mipmapped textures and a folder for sprite textures and a folder for whatever-we-want-textures. Our puzzle is made of the following pieces; the asset post processor, a simple MonoBehaviour script attached to a prefab and a custom inspector.

Let's get to some code!

We'll start from the simplest piece. The TextureProcessingFolders component [MonoBehavior]. This component is a simple string container for holding directories.

public class TextureProcessingFolders
  : MonoBehaviour
{
    public List<string> Folders;
}

 

The next step is to create a prefab and add this script to it. Save the prefab to a known location so we can later load and use it. The reason I've gone with this approach rather than some custom made XML or JSON or whatever script is twofold. First Unity already gives us simple serialization for free using components/prefabs and secondly, it's easier to use Unity's native inspector capabilities to manipulate the string list during editing. Okay, now we have our prefab and the behaviour it's time to add a custom inspector.

But wait! Why do we even need a custom inspector? Unity will automatically create an inspection view of the component and we can just add directory strings manually. You may have guessed the answer by the usage of the word manually. If I wanted to do things manually I'd go build a lego house (I do love playing with Lego by the way but that's another story). The goal of our custom inspector then is to allow dragging folders and automatically setting their path into our list.

Here's the code. Bit cute if I do say so myself.

[CustomEditor(typeof(TextureProcessingFolders))]
public class TextureProcessingInspector
  : UnityEditor.Editor
{
    public override void OnInspectorGUI()
    {
      var processing = (TextureProcessingFolders) targets;
      var dragged = EditorGUILayout.ObjectField("Folder", null, typeof(Object), false);
      if (dragged == null)
        return;

      var path = AssetDatabase.GetAssetPath(dragged);
      if (!processing.Folders.Contains(relative_folder)
        processing.Folders.Add(path);
    }
}

 

As you can see we're using Unity's own object inspection field to allow retrieving dragged asset paths. I've not added in but there should be checks to make sure that the dragged object is actually a directory and all that jazz.

This post is dragging a bit as well but it's nearly over so I'll let it slip. The last piece of the puzzle comes in the form of the asset post processor.

public class TextureProcessor
  : AssetPostprocessor
{
  public void OnPreprocessTexture()
  {
    var prefab = AssetReader.Get<gameobject>(prefab_path);
    var processing = prefab.GetComponent<textureprocessingfolders>();
    var asset_path = Path.GetDirectoryName(assetPath);
    var process_asset = processing.Folders.Any(asset_path.Contains);
    if (!process_asset)
      return;

     var settings = new TextureImporterSettings
       {
         mipmapEnabled = false,
         wrapMode = TextureWrapMode.Clamp,
         textureFormat = TextureImporterFormat.RGBA32,
         maxTextureSize = 2048,
         alphaIsTransparency = true,
       };

    var importer = (TextureImporter) assetImporter;
    importer.SetTextureSettings(settings);
  }

 

Ah, I love Unity's solid API. Let's just take a moment to appreciate the fact the we're inherting from the Post processor in order to use its Pre processing method.

Well, that's it. No more. Any thoughts whether this is useful and how to extend it into a more robust system?

 "I think of flying down into a sea of pens and feathers; and all other instruments of faith and sex and God"

Related Jobs

Playtika Santa Monica
Playtika Santa Monica — Santa Monica, California, United States
[09.01.14]

Sr. BI Developer
Wargaming.net
Wargaming.net — Hunt Valley, Maryland, United States
[09.01.14]

Engineering Manager
Wargaming.net
Wargaming.net — Chicago, Illinois, United States
[09.01.14]

Engineering Manager
Wargaming.net
Wargaming.net — Hunt Valley, Maryland, United States
[09.01.14]

Graphics Software Engineer






Comments


Guillaume Martin
profile image
Hi!

Interesting topic!


Here are some suggestions to extend it into a more robust system: use a ScriptableObject instead of a Monobehavior to store the path.

Let me explain it quickly.

The basic idea is to create "CustomTextureImportSettings : ScriptableObject" class (http://docs.unity3d.com/Documentation/ScriptReference/ScriptableO
bject.html) and instantiate it in each folder of your project where you want to have a custom importer.

When processing the texture, you will not seek for a prefab but for a scriptable object. You can search in the directory of the texture, and recurse in the root folders until you find a scriptable object. That way you can have a system that is overridable.

The scriptable object instance will contains various texture import settings (mipmapenabled, wrapmode, etc).
In your actual system, you can also expose the texture import settings in your TextureProcessingFolders so it's easier to have various importer (for example, a "GUI" folder will import the textures in GUI mode, whereas a "In Game" folder will compress textures, etc).

To end with this scriptable object approach, you can define a custom inspector for the Object that will catch a lots of stuff (folders, unity scene, etc). You can determine the type of the inspector you'll have to display by looking for an extension in the asset path (folders don't have extensions).
Then you can stack the drawing of the scriptable objects inspector in the folder inspector.

This method will scale well with other "custom import settings" (like sounds, and many custom stuff, like extracting stuff from Photoshop PSD file).

Amir Barak
profile image
That's actually a really cool solution for extending this thing. The way I'm implementing the system at the moment is with a hierarchy of prefabs. So I have the main prefab called "Texture-Processing-Controls" which is a parent of other entities. Each of the child entities has a component called "Folders" and a component called "TextureImportSettings". The "Texture-Processing-Controls" also has a single behaviour script used by its custom inspector to expose a button which lets the game designer add more folder/setting map prefabs. And the processor itself just finds the correct folder/setting pair for its current asset.

I think once I get some time I'll try to implement the whole prefab per folder scheme. Sounds promising. The one thing I'm a bit cautious though is adding extra files to manage in different locations.

The other thing I've not actually touched on is sharing these settings between team members (that is, if you have team members). Not a trivial thing I find with Unity (especially the free version).

Maxime Plantady
profile image
Yes quite an interresting topic.
Unity is still lacking some native features to create a smooth pipeline on large projects / teams.

What we've made to import textures, is slightly different. We are working with .psd and we don't want the overhead of hundreds of Mb in our versioned Asset folder, but without losing the ability to access and update texture sources quickly.

So, we've created a tool that allows to import / update .psd & mirror an external directory.
Here, what it looks like : http://imagizer.imageshack.us/a/img842/4933/a383.png

The same method is used for .max > .fbx.

Ujn Hunter
profile image
Thanks. I hate having to set all the same settings for all my textures, over and over and over again... this should help nicely.

adam anthony
profile image
dang, where was this article 2 weeks ago?! Just finished a project and cringed at bringing in all of my textures/assigning them. Thank you for the info!


none
 
Comment: