- Home /
how do i create material instances without errors
Is is possible to create an instance of a material within the editor? sometimes i get "New Material (Instance)" just by playing around with it, i wanted to know if i can actually do it on purpose, i would like to create a single material apply it to a bunch of objects and then change some properties individually without having to create a new material
i also want to know how to do the exact same thing with scripts without getting the leak error, basically so far I've been creating instances of a material by simply running a renderer.material
to force the instance, but then i get the leak errors, what is the trick to not leak, i know that line only runs once but that doesn't stop unity to error out
Answer by DaveA · Oct 19, 2012 at 08:04 PM
The trick is to set sharedMaterial, rather than Material.
Example of how to create material here: http://docs.unity3d.com/Documentation/ScriptReference/AssetDatabase.CreateAsset.html
maybe i didn't explain it well, shared$$anonymous$$aterial would be ok if i wanted to keep only one material for multiple objects, but i actually want to instantiate the material, my two problems is that i want to be able to do it on the editor AND/BUT with editor scripts i get an error of leaking materials
Instantiating material due to calling renderer.material during edit mode. This will leak materials into the scene. You most likely want to use renderer.shared$$anonymous$$aterial ins$$anonymous$$d.
Answer by Kurdle_4855 · Mar 05, 2016 at 04:11 PM
I know this thread is old, but here's a little piece of code for those who find this thread looking for the same answers I did. Create a C# script, call it MaterialInstancer, and place it in a folder called 'Editor' then copy and paste this code: using UnityEngine; using System.Collections; using UnityEditor;
public class MaterialInstancer : Editor {
[MenuItem("GameObject/Instance Material")]
public static void Instance()
{
if(Selection.activeGameObject == null || Selection.activeGameObject.GetComponent<MeshRenderer>() == null){
Debug.LogError("No Valid Object Selected");
return;
}
Material mat = Selection.activeGameObject.GetComponent<MeshRenderer>().sharedMaterial;
Selection.activeGameObject.GetComponent<MeshRenderer>().sharedMaterial = new Material(mat);
}
}
All you need to do is select a gameobject in the scene with a meshrenderer, and go to 'GameObject/Instance Material'. This will create an instance of the material on the selected gameobject, and allow you to edit it without changing any of the other materials.
Answer by SinPin · Dec 06, 2012 at 03:13 AM
Hey ;)
I had the same problem as you did - Just tried out some things to use different materials / colors for objects, I created with an editor script... I constantly ran into this "Leak-Error".
Now I just found a solution that worked for me (in Unity4) without getting this leak error, but with having the benefit of using different colors for different objects with sharedMaterial.
I have quickly written a short demo:
using UnityEngine;
using UnityEditor;
using System.Collections;
public class MyEditorScript : Editor
{
// If I want to have new Objects with different colors:
[MenuItem("Test/Create Object with Material")]
public static void CreateDemoObjects()
{
// Create a new GameObject with a material...
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
obj.name = "TestObject";
// Important: sharedMaterial, not material.
obj.renderer.sharedMaterial = new Material(Shader.Find("Diffuse")); // REF1
obj.renderer.sharedMaterial.color = Color.green;
GameObject obj2 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
obj2.name = "TestObject2";
obj2.transform.position = new Vector3(2f, 0f, 0f);
obj2.renderer.sharedMaterial.color = Color.red;
}
// If I just want to change the material, you might use the color of an existing Object
// public void JustASnippet()
// {
// // GameObject _target -> Your exiting target object...
// Material mat;
// // Still using sharedMaterial:
// mat = new Material(_target.renderer.sharedMaterial);
// mat.color = Color.blue; // Taking blue color for demo...
//
// // Work with "mat" here...
// // e.g.: obj.renderer.sharedMaterial = mat;
// }
}
Just try it out in an empty scene -> Drop this Script in an "Editor" Directory. Then activate it by Menu: Test->"Create Object with Material".
As you can see, I am creating new objects and change their color (you can play around with this to change the whole material or whatever you need) without using the material propertie.
Find the "// REF1" comment -> If you comment this line out, you will get two red objects, so this line actually did the trick. (I get a green cube and a red sphere.)
I don't know why, but this "Leak-Error" is always called when using (even reading) the "material" property. (It is not called for creating a "new Material()")
There is only one problem with this code, I have figured out for now: After creating the two demo objects, all the next objects, you will create (Menu: GameObject->Create Other->Cube) in this scene are red by default. (sharedMaterial was set to red at the end of the CreateDemoObjects() Function.)
Also take a look at the JustASnippet() Function, where are some lines, that worked for me too. (I created a new Material based on the sharedMaterial of an already existing object.) This Function-Code is not complete, but I think you can see what I mean.
Just to mention it: If you don't want to create a new Material via Script, you can create it in the Editor and use this one...
I hope my code helped you to avoid the "Leak-Error". If I figure out more about this topic, I will update my content.
Yours SinPin
Yes, please format your code. You can do this by highlighting all your code, then clicking the 10101 button at the top of the edit window.
Though, it may be easier just to delete the code, paste it in again from the source, then highlight all the code and press the 101010 button at the top of the edit window before posting. When you don't mark your code as code, the text gets html escaped and it gets really hard to reformat it.
@alucardj: I reposted and formated the code - Thanks for your help :)
Answer by Clemens-Scharfen · Feb 20, 2020 at 01:27 PM
Hi there,
I am aware that this thread is old, but I came here to look for a solution and was not completely happy with the provided answers (although I wrote one of them myself with another account 8 years ago :P ). I liked the answer from @Kurdle_4855, but I had the impression, that the material instance was gone when restarting the editor. To avoid the "leaking material" issue and to work with instanciated prefabs, I came up with my own (second) solution, that I wanted to share with you (or myself in the future :D ).
Basicly, the code does not really instanciate the material, but creates a copy from the original material, that can be shared via .sharedMaterial property without changing the appearence of other elements.
using UnityEditor;
using UnityEngine;
public class MaterialInstancer : Editor
{
// This function creats a new material based on the one, that is referenced to the selected object(s) and saves this new material into a sub directory close to the original material.
// Note: If you want to change a prefab, instanciate the prefab in a scene, use the InstanceMaterial for alle materials that you want to create an material-instance, and apply the prefab changes to the prefab.
// If you do changes to a prefab directly in the prefab editor, the changes will be lost as soon as the prefab-editor is closed.
[MenuItem("GameObject/Create Material Instance", false, 1111)]
public static void InstanceMaterial()
{
foreach(Transform selectedTrans in Selection.transforms)
{
if (selectedTrans != null)
{
MeshRenderer selectedMeshRenderer = selectedTrans.GetComponent<MeshRenderer>();
if(selectedMeshRenderer != null)
{
Material selectedMat = selectedMeshRenderer.sharedMaterial;
if(selectedMat != null)
{
// Create Material:
Material materialInstance = new Material(selectedMat);
// Save material to assets:
string parentDir = AssetDatabase.GetAssetPath(selectedMat); // returns something like Assets/Materials/matName.mat
parentDir = parentDir.Substring(0, parentDir.Length - (selectedMat.name.Length + ".mat".Length + 1)); // Results in Assets/Materials
string instanceFolder = selectedMat.name + "Instances";
string saveMatInstancePath = parentDir + "/" + instanceFolder;
if(AssetDatabase.IsValidFolder(saveMatInstancePath) == false)
{
string guid = AssetDatabase.CreateFolder(parentDir, instanceFolder);
string newFolderPath = AssetDatabase.GUIDToAssetPath(guid);
Debug.Log("[Create Material Instance] Created new directory for instanced material: " + newFolderPath);
}
// In case, material already exists, add number to its name:
string assetName = selectedMat.name + "Instance";
string[] searchPaths = new string[] { saveMatInstancePath };
int count = 0;
while(AssetDatabase.FindAssets(assetName, searchPaths).Length > 0)
{
assetName = selectedMat.name + "Instance" + (++count).ToString();
}
// Save asset:
AssetDatabase.CreateAsset(materialInstance, saveMatInstancePath + "/" + assetName + ".mat");
// Link material to game object:
selectedMeshRenderer.sharedMaterial = materialInstance;
Debug.Log("[Create Material Instance] " + selectedTrans.name + "s material got instantiated successfully.", selectedTrans.gameObject);
}
else
{
Debug.LogWarning("[Create Material Instance] Selected element does not have a material that can be instanciated.", selectedTrans.gameObject);
}
}
else
{
Debug.LogWarning("[Create Material Instance] Selected Element does not have a MeshRenderer.", selectedTrans.gameObject);
}
}
else
{
Debug.LogWarning("[Create Material Instance] Something went wrong, the selected gameObject does not exist.");
}
}
}
[MenuItem("GameObject/Create Material Instance", true)]
public static bool CheckInstanceMaterial()
{
return (Selection.transforms != null && Selection.transforms.Length > 0);
}
}
Your answer
Follow this Question
Related Questions
Finding and replacing all "instanced" materials 2 Answers
sharedMaterial not working after instantiate 0 Answers
Fade 2 out of 3 gameobjects on the screen who have the same material 2 Answers
Renderer.materials leaking materials 1 Answer
Two questions about building particle systems from scripts 1 Answer