Changing prefab property by script

Hi,

I do a script which change the scale in lightmap by script with this function :

private void ScaleInLightmapAll (GameObject go)
	{
		//Check if he got a renderer
		if (go.renderer != null) {
			//Serialized my object to allow to modify every property in it
			SerializedObject so = new SerializedObject (go.GetComponent<Renderer> ());
			SerializedProperty goScaleProperty = so.FindProperty("m_ScaleInLightmap");
//			Debug.Log ("Scale value : " + so.FindProperty ("m_ScaleInLightmap").floatValue.ToString ());

			//Find the property and modify them
			goScaleProperty.floatValue = m_nScaleInLightmap;

//			Debug.Log ("Scale value after : " + so.FindProperty ("m_ScaleInLightmap").floatValue);

			//Apply the modified properties
			Debug.Log ("succes ?   " + so.ApplyModifiedProperties ()); //Send true but this is working ? oO

			Debug.Log ("Scale value after : " + so.FindProperty ("m_ScaleInLightmap").floatValue);
		}
	}

All my debug line seems ok before and after but when I bake my lightmap with another script, my lightmap is bake with the initial value of each prefab (1).

Someone got an idea on this, it can be a good thing :wink:

Did you save the changes?

I thought the ApplyModifiedProperties() did it.

But with your answer I think maybe not.

Must I do this :

			string sAssetPath = AssetDatabase.GetAssetPath( go );
			AssetDatabase.ImportAsset( sAssetPath );

at the end of my function ?

And I see that I modified my lightmap setting with a new editor script but when I come back in the editor after a bake, all parameters are come back in their first state ? It’s normal ?

I think ApplyModifiedProperties just applies all changes back to your target object, before that every change is only cached in the SerializedObject (only a guess).

I think you must also call this:

before you can import your changes, Iam not even sure if you need to reimport it. Would be nice if someone with more experience than me can clarify this.

I don’t know well the AssetDatabase library thanks for this function.
Create a tool for automatize lightmapping on numerous scenes which are baked in the same scene is really hard sometimes. But it’s nearly over :smile:. My two last problems are :

Prefab value seems never change (Maybe AssetDatabase.SaveAsset() ) can repair that combine with a reimport ?

And my lightmap setting I do a window which is like the unity window and I add my own field in the middle. But for example when I do this :

EditorGUILayout.Space ();
				EditorGUILayout.BeginHorizontal ();
					EditorGUILayout.PrefixLabel ("Quality");
					LightmapEditorSettings.quality = (LightmapBakeQuality)EditorGUILayout.EnumPopup (LightmapEditorSettings.quality);
				EditorGUILayout.EndHorizontal ();

The "LightmapEditorSettings.quality " is change for my first bake then the others come back to the initial value before the user change it :/. That’s rally strange.
Maybe I must used temp value for each of them then push the temp value in the “LightmapEditorSettings.quality”

So maybe I’m doing this wrong too !!

//Recursive function switch all uv2 of mesh to true
	private void GenerateLightMapUV2 (GameObject gameObject)
	{
		MeshFilter meshFilter = gameObject.GetComponent<MeshFilter> ();
		MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer> ();

		//Check if my mesh have and filter and a renderer so it's the final
		if (meshFilter != null  meshRenderer != null)
		{
			//Take the mesh of the file
			Mesh meshLightmapped = meshFilter.sharedMesh;

			//Take the file's path and put it in a string
			string path = AssetDatabase.GetAssetPath (meshLightmapped);

			string extensionPath = System.IO.Path.GetExtension (path);
			if (!extensionPath.Equals (".asset"))
			{
				//Define a modelImporter to modify its importing settings
				ModelImporter model = AssetImporter.GetAtPath (path) as ModelImporter;

				//Put the generateSecondaryUV field to true and GenerateUVSet for the mesh
				if (!model.generateSecondaryUV)
				{
					model.generateSecondaryUV = true;
					Unwrapping.GenerateSecondaryUVSet (meshLightmapped);
				}
			}
			else
				Unwrapping.GenerateSecondaryUVSet (meshLightmapped);
			//Update the mesh setting in editor
			AssetDatabase.ImportAsset (path);
		}

		//Iterate on the children if they have something to render too
		foreach (Transform t in gameObject.transform)
			GenerateLightMapUV2 (t.gameObject);
	}

Cause I don’t use “AssetDatabase.SaveAssets()” and I just use “AssetDatabase.ImportAsset (path)” maybe it’s not a good solution :confused:

If someone can confirm or correct me if I’m doing it wrong ?

For the lightmapSetting I found the solution ! Unity you are really nasty.

The lightmap settings parameters are link with the scene, if you don’t save your scene, your baking parameters are reinitialized !
Now I can tweak this easily :smile:

Hope this can help someone in the future !

And still hope have a tips for my prefabs problem :slight_smile:

Edit : No one have an idea ?

I just see something fun, when you do AssetDatabase.SaveAssset(), it asks to the user to confirm each time the function is call.

There is something to do to avoid that ? :x

My tools need to be full automatic :slight_smile:

I try a new pass with my tools and edit this post when I’ll get or not the dialog window. Use only one core for this function :

Unwrapping.GenerateSecondaryUVSet (meshLightmapped);

take really a long time, it’s sad that I can’t force use more :confused:

Thats strange, I used this in the past and never have seen any dialog like you described.

Oh my god, I know why it’s ask me every asset to save it…
This function display a window when it’s called : EditorApplication.SaveAssets();

I call it to be sure that all is save before to do the assetdatabase save, maybe comment it will be better in that case…

So I got something like this :

for (int i = 0; i < gameObject.Length; i++)
		EditorUtility.SetDirty( gameObject[i] );
EditorApplication.SaveAssets();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

Maybe it’s to violent :x

I confirm with this part of code :

for (int i = 0; i < gameObject.Length; i++)
		EditorUtility.SetDirty( gameObject[i] );
//EditorApplication.SaveAssets();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

Unity display a dialog window. Maybe it’s the fact I force the SetDirty on each GameObject I update with the generateUVLightmap.

Ok, I find the solution as I said in this topic :
http://forum.unity3d.com/threads/150314-SetDirty()-amp-dialog-window-to-save

There is really something that I don’t understand with this part of my script >_<…
To be sure I use this

for (int i = 0; i < gameObject.Length; i++)
        EditorUtility.SetDirty( gameObject[i] );

EditorApplication.SaveAssets();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

everywhere I modify a prefab or something but the ScaleInLightMap value is never saved…

I gonna give details on what i’m doing if someone can explain what I’m doing wrong :x

First I generate the UV set for lightmap with those 2 functions :

//Function to genereate the lightmap uv of each prefab and children
	private void GenerateLightmapUVArray (GameObject[] gameObject)
	{
		//Check if the array is empty, if yes USER GTFO !
		if (nSizeLightMapArray == 0 || LightMapUvMeshsToGenerate [0] == null)
			m_sErrorStringUV = "Need at least 1 mesh in the array above !";
		//Otherwise loop on each prefab and check them wit hthe recursive function
		else
		{
			for (int i = 0; i < gameObject.Length; i++)
				GenerateLightMapUV2 ( gameObject [i] );

			//Update the mesh setting in editor
			//Debug.Log("Save the assets");
			for (int i = 0; i < gameObject.Length; i++)
				EditorUtility.SetDirty( gameObject[i] );
			EditorApplication.SaveAssets();
			AssetDatabase.SaveAssets();
			AssetDatabase.Refresh();
		}
	}

	//Recursive function switch all uv2 of mesh to true
	private void GenerateLightMapUV2 (GameObject gameObject)
	{
		MeshFilter meshFilter = gameObject.GetComponent<MeshFilter> ();
		MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer> ();

		//Check if my mesh have and filter and a renderer so it's the final
		if (meshFilter != null  meshRenderer != null)
		{
			//Take the mesh of the file
			Mesh meshLightmapped = meshFilter.sharedMesh;

			//Take the file's path and put it in a string
			string path = AssetDatabase.GetAssetPath (meshLightmapped);
//			Debug.Log ("Model path : " + path);

			string extensionPath = System.IO.Path.GetExtension (path);

//			Debug.Log ("extension path : " + extensionPath);

			if (!extensionPath.Equals (".asset"))
			{
				//Define a modelImporter to modify its importing settings
				ModelImporter model = AssetImporter.GetAtPath (path) as ModelImporter;

				//Put the generateSecondaryUV field to true and GenerateUVSet for the mesh
				if (!model.generateSecondaryUV)
				{
					model.generateSecondaryUV = true;
					Unwrapping.GenerateSecondaryUVSet (meshLightmapped);
				}
			}
			else
				Unwrapping.GenerateSecondaryUVSet (meshLightmapped);
		}

		//Iterate on the children if they have something to render too
		foreach (Transform t in gameObject.transform)
			GenerateLightMapUV2 (t.gameObject);
	}

then when it’s done I want bake my lightmap that use those prefabs so I use my personnal lightmap window cause I add custom field as I said in the previous posts and I’m doing this to bake my lightmaps :

//Init our scene view with all game object
	private void InitScene ()
	{
		string sTagToUse = "";
		bool bIsFirstTimePassThrough = true;
		GameObject[] m_goToBakeArray;
		int nTempArraySize = 0;

		//Init all the gameobject from our window in the scene (Transform must be set in the prefab before import them in editor window )
		foreach (GameObject go in LightMapUvMeshsToGenerate)
			Instantiate (go);

		//Think to do the same thing for the lights cause just 1 light possible here so associate a tag to a light
		Instantiate ( DirectionnalLightArray );
	}

	//Force all game object in our scene as static
	private void StaticAllTheScene ()
	{
		//Iterate on all our gameobject in the scene and put them as static
		GameObject[] goList = new GameObject[GameObject.FindSceneObjectsOfType (typeof(GameObject)).Length];

		//Take all gameobject type and put them in da list
		goList = (GameObject[])GameObject.FindSceneObjectsOfType (typeof(GameObject));

//		Debug.Log ("Real start of static  scale in lightmap...");
		for (int i = 0; i < goList.Length; i++) {
//			Debug.Log("Liste de game object : " + goList[i].name );

//			Debug.Log("====================================================");
//			Debug.Log("Is Static : " + goList[i].isStatic + " My object name : " + goList[i].name );
//			Debug.Log("His parent : " + goList[i].transform.parent + " - have a light ? " + goList[i].GetComponent<Light>());
//			Debug.Log("====================================================");

			//Put all gameObject static field to true
			if ( goList [i].GetComponent<Light> () == null )
			{
				goList [i].isStatic = true;
				ScaleInLightmapAll (goList [i]);
			}

//			Debug.Log("====================================================");
//			Debug.Log("Is Static : " + goList[i].isStatic + " My object name : " + goList[i].name );
//			Debug.Log("His parent : " + goList[i].transform.parent + " - have a light ? " + goList[i].GetComponent<Light>());
//			Debug.Log("====================================================");
		}
//		Debug.Log ("Static  scale in lightmap over so save all this changes");

		EditorApplication.SaveAssets();
		AssetDatabase.SaveAssets();
		AssetDatabase.Refresh();
	}

	//Modify all scale of our object to a new one
	private void ScaleInLightmapAll (GameObject go)
	{
		//Check if he got a renderer
		if (go.renderer != null)
		{
			//Serialized my object to allow to modify every property in it
			SerializedObject so = new SerializedObject (go.GetComponent<Renderer> ());
			SerializedProperty goScaleProperty = so.FindProperty("m_ScaleInLightmap");

			//Find the property and modify them
			goScaleProperty.floatValue = m_nScaleInLightmap;

			//Apply the modified properties
			Debug.Log ("succes ?   " + so.ApplyModifiedProperties ()); //Send true but this is working ? oO

			Debug.Log ("Scale value after : " + so.FindProperty ("m_ScaleInLightmap").floatValue);

			EditorUtility.SetDirty( go );
		}
	}

//Bake all the scene in async mod if it's the last thing to do or sync if it's the complete execution
	private void BakingScene ()
	{
		//Check all the mesh in the scene and put them static
//		Debug.Log ("Convert all mesh to static...");
		StaticAllTheScene ();
//		Debug.Log ("Convertion over.");
//		Debug.Log ("=============================");
//
//		Debug.Log ("Baking...");
//		Debug.Log ("Current tooltip : " + toolbarInt.ToString ());

		//Bake the current scene in synchronous mod to block all the rest and stop the application
//		if (toolbarInt == 2)
//			Lightmapping.BakeAsync ();
//		else 
                if (toolbarInt == 4)
			Lightmapping.Bake ();
//		Debug.Log ("Baking over");
//		Debug.Log ("=============================");

		SetDirtyAll();
		EditorApplication.SaveAssets();
		AssetDatabase.SaveAssets();
	}

To be simple, I init my scene with all necessary prefab of object and light needed in my scene. Then I convert them to static to allow lightmapping and I modify their scale in lightmap to be sure their size in the lightmap texture is good.

Then I bake and at the end of the bake, if I understand what Unity do with its real baking window, it updates all those prefab lines :

m_LightmapIndex: 255
m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0}

With those 2 lines, the prefab can re-apply in everyscene the good tilling and offset for the corresponding uv lightmap texture. So to be sure that it’s done too, I use again after the bake the function to save assets modification.

If I’m not clear in some part of my explaination or if you need more informations on what I’m doing, ask it and I answer it ;).

Hope someone can help me on that cause I really become crazy cause of those asset saves and serializedObject.