- Home /
Is it possible to automate material creation with new textures?
I have many textures that I need to turn in to materials. Is there a fast way to do this or script this?
For example if I could right click a single or group of textures and select from the right click menu (or use a pop up menu) "Create Material/s from Textures" that would then create materials with the same name and maybe an appendance of _mat or similar?
Answer by Bunny83 · Jul 11, 2014 at 02:09 PM
Sure, just use a script like this:
// CreateMaterialsForTextures.cs
// C#
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Linq;
public class CreateMaterialsForTextures : Editor
{
[MenuItem("Tools/CreateMaterialsForTextures")]
static void CreateMaterials ()
{
try
{
AssetDatabase.StartAssetEditing();
var textures = Selection.GetFiltered(typeof(Texture), SelectionMode.Assets).Cast<Texture>();
foreach(var tex in textures)
{
string path = AssetDatabase.GetAssetPath(tex);
path = path.Substring(0,path.LastIndexOf("."))+".mat";
if (AssetDatabase.LoadAssetAtPath(path,typeof(Material)) != null)
{
Debug.LogWarning("Can't create material, it already exists: " + path);
continue;
}
var mat = new Material(Shader.Find("Diffuse"));
mat.mainTexture = tex;
AssetDatabase.CreateAsset(mat,path);
}
}
finally
{
AssetDatabase.StopAssetEditing();
AssetDatabase.SaveAssets();
}
}
}
Keep in mind this is an editor script and need to be placed in a folder called "editor". Once you have this script in your project and it is compiled you can select one or multiple textures in your project panel and then click "Tools->CreateMaterialsForTextures" in the menubar.
Note: if the script just was compiled the Tools menu might not be visible yet but when you just click any menuitem it should appear.
This script will create a material next to the texture with the same name. However if there is already a material with that name it does nothing.
edit
Here's the same script but turned into a wizard which allows you to select a different shader before you create the materials:
// CreateMaterialsForTextures.cs
// C#
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Linq;
public class CreateMaterialsForTextures : ScriptableWizard
{
public Shader shader;
[MenuItem("Tools/CreateMaterialsForTextures")]
static void CreateWizard ()
{
ScriptableWizard.DisplayWizard<CreateMaterialsForTextures>("Create Materials", "Create");
}
void OnEnable()
{
shader = Shader.Find("Diffuse");
}
void OnWizardCreate ()
{
try
{
AssetDatabase.StartAssetEditing();
var textures = Selection.GetFiltered(typeof(Texture), SelectionMode.Assets).Cast<Texture>();
foreach(var tex in textures)
{
string path = AssetDatabase.GetAssetPath(tex);
path = path.Substring(0,path.LastIndexOf("."))+".mat";
if (AssetDatabase.LoadAssetAtPath(path,typeof(Material)) != null)
{
Debug.LogWarning("Can't create material, it already exists: " + path);
continue;
}
var mat = new Material(shader);
mat.mainTexture = tex;
AssetDatabase.CreateAsset(mat,path);
}
}
finally
{
AssetDatabase.StopAssetEditing();
AssetDatabase.SaveAssets();
}
}
}
ps: I used the default "Diffuse" shader when creating the material. If you want something else, either change the script, or create a wizard.
Oh that is beautiful. Exactly what I needed. I am going to study this a bit, because I originally wanted to try and script this out myself. Scripting / Coding is not my usual thing.
Thanks so much. =)
updated for universal render pipeline:
// CreateMaterialsForTextures.cs
// C#
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Linq;
public class CreateMaterialsForTextures : ScriptableWizard
{
public Shader shader;
[MenuItem("Tools/CreateMaterialsForTextures")]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard<CreateMaterialsForTextures>("Create Materials", "Create");
}
void OnEnable()
{
shader = Shader.Find("Universal Render Pipeline/Lit");
}
void OnWizardCreate()
{
try
{
AssetDatabase.StartAssetEditing();
var textures = Selection.GetFiltered(typeof(Texture), SelectionMode.Assets).Cast<Texture>();
foreach (var tex in textures)
{
string path = AssetDatabase.GetAssetPath(tex);
path = path.Substring(0, path.LastIndexOf(".")) + ".mat";
if (AssetDatabase.LoadAssetAtPath(path, typeof(Material)) != null)
{
Debug.LogWarning("Can't create material, it already exists: " + path);
continue;
}
var mat = new Material(shader);
mat.SetTexture("_BaseMap", tex);
AssetDatabase.CreateAsset(mat, path);
}
}
finally
{
AssetDatabase.StopAssetEditing();
AssetDatabase.SaveAssets();
}
}
}
Answer by kleber-swf · Jul 11, 2014 at 02:06 PM
You could create an editor script to do this using AssetDatabase.CreateAsset as shown in
http://docs.unity3d.com/ScriptReference/AssetDatabase.CreateAsset.html
(the example creates a material, btw)
Thank you for replying. For some reason I couldn't even find that in the docs. =\