I’ve been looking to upgrade a few thousand particle systems that was created before the ‘Apply Active Color Space’ toggle was added in. When it was introduced sometime in 2018 (?) it was not set to be enabled by default unless you created a new particle system.
I’ve had some help writing a script to attempt to enable ‘Apply Active Color Space’, but it seems there is no way to access the property through code, or we simply can’t find it in the documentation.
Any ideas what to do here? I was sure I would find it in the documentation here (??), but now I’m lost.
The 30 000 click alternative seems to be to open each particle system individually, then select each sub-emitter/child and click the toggle button. Does not sound like a fun time.
Hmm… you’re right. It isn’t exposed to the c# script. I know there’s a way to access component properties that aren’t exposed using System.Reflection, but uh … I have no idea how to do it.
The way I solve these kinds of problems, especially when I know the property name is super unique, is to use an external text editor. Find and Replace.
Look for something like this in the .prefab or .unity files. ApplyActiveColorSpace
Old files (once resaved) will likely show that value with a 0. New ones with a 1. Search and replace the lines with a 0 with a 1.
@bgolus So it seems that the line I’m looking for doesn’t exist at all in my pre-2018 prefabs until I actually enable it in the particle system, then it shows up in the Renderer settings.
You may need the prefab to upgrade before it can be accessed, in order to be able to find the property, I’ve really no idea how that bit works… hopefully it’s already upgraded in-memory, though.
Let us know if it works or not, and we can try other things if not
@richardkettlewell Thanks for the response. It’s extra tricky considering I don’t do much scripting myself, and I’m not sure what it would mean to ‘upgrade’ the prefab. I assumed prefabs with the particle system component would have their component upgraded on import, but I guess it’s just the particle system interface (in the inspector) that is updated?
I’ll see if I can get some help updating it using reflection.
Is there any chance you’ll be updating the scripting API to make the setting a public Property in a LTS version?
My understanding is objects are upgraded when loaded in the editor, and if you save the asset it’ll upgrade the file on disk. However Unity won’t save a prefab / scene unless it’s “dirty” (something has been changed, and auto upgrading alone may not count).
The hacky method may be to have a script go through every particle system and toggle some other innocuous property on the ParticleSystemRenderer component. Like toggle allowRoll twice.
var psr = GetComponent<ParticleSystemRenderer>();
psr.allowRoll = !psr.allowRoll; // make it dirty!
psr.allowRoll = !psr.allowRoll; // reset it to the original value, but still dirty!
Looks like we found a workaround using your suggestions, my friend wrote me a tool for upgrading older particle systems.
The script will search through folders and gameobjects of your choice that has particle systems attached. Click a button and the script will instantiate them and modify the renderer value before the instantiated prefabs replaces the old ones. Scene is cleaned up afterwards.
How to use:
Import the package to your project
Select the prefab or folder you want to upgrade in the Project tab
Go to ‘Tools>Apply Active Color Space’.
If you’re upgrading a folder or multiple particle systems, Unity may be unresponsive for a bit until the process is complete.
AACSUpdateTool.CS
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.IO;
namespace AACSUpdateTool
{
public class AACSUpdateTool : EditorWindow
{
private List<string> prefabNames;
private List<GameObject> tempPrefabs;
private void Awake()
{
prefabNames = new List<string>();
tempPrefabs = new List<GameObject>();
}
[MenuItem("Tools/Apply Active Color Space Tool")]
public static void EnableWindow()
{
GetWindow(typeof(AACSUpdateTool));
}
private void OnGUI()
{
GUILayout.Space(10);
var customLabelStyle = new GUIStyle();
customLabelStyle.normal.textColor = Color.black;
customLabelStyle.fontStyle = FontStyle.Bold;
customLabelStyle.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("Select prefabs and/or prefab folders and press the button.", customLabelStyle);
GUILayout.Space(10);
if (GUILayout.Button("Turn on Apply Active Color Space"))
{
RefreshParticleSystems();
}
}
private void RefreshParticleSystems()
{
tempPrefabs.Clear();
string path = "Assets";
foreach (Object obj in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
{
if (!IsFolder(obj))
{
if (obj.GetType() == typeof(GameObject))
{
//Instantiate prefab
GameObject newPrefab = Instantiate(obj) as GameObject;
if (newPrefab.GetComponent<ParticleSystem>())
{
//Cache prefab name and directory
path = AssetDatabase.GetAssetPath(obj);
prefabNames.Add(obj.name);
//Cache new prefab
tempPrefabs.Add(newPrefab);
ParticleSystemRenderer[] prefabParticleSystemsRenderers = newPrefab.GetComponentsInChildren<ParticleSystemRenderer>(true);
for (int i = 0; i < prefabParticleSystemsRenderers.Length; i++)
{
if (prefabParticleSystemsRenderers[i].renderMode != ParticleSystemRenderMode.None)
{
var so = new SerializedObject(prefabParticleSystemsRenderers[i]);
so.FindProperty("m_ApplyActiveColorSpace").boolValue = true;
so.ApplyModifiedProperties();
PrefabUtility.SaveAsPrefabAsset(newPrefab, path);
}
}
}
else
{
DestroyImmediate(newPrefab);
}
}
}
}
//Clean hierarchy
for (int i = 0; i < tempPrefabs.Count; i++)
{
DestroyImmediate(tempPrefabs[i]);
}
}
private bool IsFolder(Object obj)
{
if (obj != null)
{
string asset_path = AssetDatabase.GetAssetPath(obj);
if (asset_path.Length > 0)
{
string file_path = Application.dataPath + "/" + asset_path.Replace("Assets/", "");
FileAttributes file_attr = File.GetAttributes(file_path);
if ((file_attr & FileAttributes.Directory) == FileAttributes.Directory)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
return false;
}
}
}
Note: There’s no ‘undo’ button, so use at your own risk.