Search Unity

  1. All Pro and Enterprise subscribers: find helpful & inspiring creative, tech, and business know-how in the new Unity Success Hub. Sign in to stay up to date.
    Dismiss Notice
  2. Dismiss Notice

Help Wanted Apply Active Color Space through code

Discussion in 'General Graphics' started by Archanor, Jan 28, 2021.

  1. Archanor

    Archanor

    Joined:
    Dec 2, 2013
    Posts:
    520
    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.

    Tagging @richardkettlewell just in case :)
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    10,410
    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.
     
    Archanor likes this.
  3. Archanor

    Archanor

    Joined:
    Dec 2, 2013
    Posts:
    520
    @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.

    m_ApplyActiveColorSpace: 0


    upload_2021-1-29_14-43-52.png
     
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,765
    Hmmm tricky!

    I'm not sure why it's not exposed in script, possibly an oversight.
    Here is the basics of how to modify properties through reflection: https://answers.unity.com/questions/483831/how-to-modify-particlesystem-from-editor-script.html

    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 :)
     
    Archanor likes this.
  5. Archanor

    Archanor

    Joined:
    Dec 2, 2013
    Posts:
    520
    @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?
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    10,410
    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.

    https://docs.unity3d.com/ScriptReference/ParticleSystemRenderer-allowRoll.html
    http://www.zuluonezero.net/2020/02/...s-and-prefabs-with-a-given-component-by-type/

    Code (csharp):
    1. var psr = GetComponent<ParticleSystemRenderer>();
    2. psr.allowRoll = !psr.allowRoll; // make it dirty!
    3. psr.allowRoll = !psr.allowRoll; // reset it to the original value, but still dirty!
    Or use the EditorUtility.SetDirty and similar functions.


    The one issue is I don't know if old components are upgraded on load, or when viewed by an inspector. :(
     
    richardkettlewell likes this.
  7. Archanor

    Archanor

    Joined:
    Dec 2, 2013
    Posts:
    520
    Hey, thanks for the help!

    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:

    1. Import the package to your project
    2. Select the prefab or folder you want to upgrade in the Project tab
    3. 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.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.IO;
    5.  
    6. namespace AACSUpdateTool
    7. {
    8.  
    9. public class AACSUpdateTool : EditorWindow
    10. {
    11.     private List<string> prefabNames;
    12.     private List<GameObject> tempPrefabs;
    13.  
    14.     private void Awake()
    15.     {
    16.         prefabNames = new List<string>();
    17.         tempPrefabs = new List<GameObject>();
    18.     }
    19.  
    20.     [MenuItem("Tools/Apply Active Color Space Tool")]
    21.     public static void EnableWindow()
    22.     {
    23.         GetWindow(typeof(AACSUpdateTool));
    24.     }
    25.  
    26.     private void OnGUI()
    27.     {
    28.         GUILayout.Space(10);
    29.  
    30.         var customLabelStyle = new GUIStyle();
    31.         customLabelStyle.normal.textColor = Color.black;
    32.         customLabelStyle.fontStyle = FontStyle.Bold;
    33.         customLabelStyle.alignment = TextAnchor.MiddleCenter;
    34.         GUILayout.Label("Select prefabs and/or prefab folders and press the button.", customLabelStyle);
    35.  
    36.         GUILayout.Space(10);
    37.  
    38.         if (GUILayout.Button("Turn on Apply Active Color Space"))
    39.         {
    40.             RefreshParticleSystems();
    41.         }
    42.     }
    43.  
    44.     private void RefreshParticleSystems()
    45.     {
    46.         tempPrefabs.Clear();
    47.  
    48.         string path = "Assets";
    49.  
    50.         foreach (Object obj in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
    51.         {
    52.             if (!IsFolder(obj))
    53.             {
    54.                 if (obj.GetType() == typeof(GameObject))
    55.                 {
    56.                     //Instantiate prefab
    57.                     GameObject newPrefab = Instantiate(obj) as GameObject;
    58.                
    59.                     if (newPrefab.GetComponent<ParticleSystem>())
    60.                     {
    61.                         //Cache prefab name and directory
    62.                         path = AssetDatabase.GetAssetPath(obj);
    63.                         prefabNames.Add(obj.name);
    64.  
    65.                         //Cache new prefab
    66.                         tempPrefabs.Add(newPrefab);
    67.  
    68.                         ParticleSystemRenderer[] prefabParticleSystemsRenderers = newPrefab.GetComponentsInChildren<ParticleSystemRenderer>(true);
    69.  
    70.                         for (int i = 0; i < prefabParticleSystemsRenderers.Length; i++)
    71.                         {
    72.                             if (prefabParticleSystemsRenderers[i].renderMode != ParticleSystemRenderMode.None)
    73.                             {
    74.                                 var so = new SerializedObject(prefabParticleSystemsRenderers[i]);
    75.                                 so.FindProperty("m_ApplyActiveColorSpace").boolValue = true;
    76.                                 so.ApplyModifiedProperties();
    77.  
    78.  
    79.                                 PrefabUtility.SaveAsPrefabAsset(newPrefab, path);
    80.                             }
    81.                         }
    82.                     }
    83.                     else
    84.                     {
    85.                         DestroyImmediate(newPrefab);
    86.                     }
    87.                 }
    88.             }
    89.         }
    90.  
    91.         //Clean hierarchy
    92.         for (int i = 0; i < tempPrefabs.Count; i++)
    93.         {
    94.             DestroyImmediate(tempPrefabs[i]);
    95.         }
    96.     }
    97.  
    98.     private bool IsFolder(Object obj)
    99.     {
    100.         if (obj != null)
    101.         {
    102.             string asset_path = AssetDatabase.GetAssetPath(obj);
    103.             if (asset_path.Length > 0)
    104.             {
    105.                 string file_path = Application.dataPath + "/" + asset_path.Replace("Assets/", "");
    106.                 FileAttributes file_attr = File.GetAttributes(file_path);
    107.                 if ((file_attr & FileAttributes.Directory) == FileAttributes.Directory)
    108.                 {
    109.                     return true;
    110.                 }
    111.                 else
    112.                 {
    113.                     return false;
    114.                 }
    115.             }
    116.             else
    117.             {
    118.                 return false;
    119.             }
    120.         }
    121.  
    122.         return false;
    123.     }
    124. }
    125.  
    126. }

    Note: There's no 'undo' button, so use at your own risk.
     

    Attached Files:

    Last edited: Feb 10, 2021
    richardkettlewell and bgolus like this.
unityunity