Sort Layer Renderer Extension

Hello Guys,
As we know since Unity 4.3, Unity have a sort layer manager. This feature is exposed and fully manageable from Edit->Project Settings->Tags and Layers.
Every Renderer have some exposed variables to deal with the sort layer but only the Sprite Renderer has it exposed on the inspector.
So I find a way to do an extension to Unity Renderers, adding sort layer options as in Sprite Renderer to every Renderer. (so you can use it at TrailRenderer, LineRenderer, ParticleLegacyRenderer and etc…)
I did it yesterday so Im not sure, at this moment, if it really works as it should work in all cases. The code is also a little dirt (sorry for that). I also added a include child toggle option because well... its quite useful.

I tried to do the same in Shuriken Particle System but Im new in this Custom Editor thing and Im not able to change Shuriken Particle System without destroy that charming look from Shuriken Particle System Inspector.

//  SortLayerRendererExtension.cs
//   Author:
//       Yves J. Albuquerque <yves.albuquerque@gmail.com>
//  Last Update:
//       27-12-2013 
//Put this file into a folder named Editor.
//Based on Nick`s code at https://gist.github.com/nickgravelyn/7460288 and Ivan Murashko solution at http://forum.unity3d.com/threads/210683-List-of-sorting-layers?p=1432958&viewfull=1#post1432958 aput by Guavaman at http://answers.unity3d.com/questions/585108/how-do-you-access-sorting-layers-via-scripting.html
using System;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Reflection;

[CanEditMultipleObjects()]
[CustomEditor(typeof(Renderer),true)]
public class SortLayerRendererExtension : Editor
{
    Renderer renderer;
    Renderer[] childsRenderer;
    string[] sortingLayerNames;

    int selectedOption;
    bool applyToChild = false;
    bool applyToChildOldValue = false;

    void OnEnable()
    {
        sortingLayerNames = GetSortingLayerNames();
        renderer = (target as Renderer).gameObject.renderer;
        if ((target as Renderer).transform.childCount > 1)
            childsRenderer = (target as SortingLayerExposed).transform.GetComponentsInChildren<Renderer>();

        for (int i = 0; i<sortingLayerNames.Length;i++)
        {
            if (sortingLayerNames[i] == renderer.sortingLayerName)
                selectedOption = i;
        }
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        if (!renderer)
        {
            return;
        }

        EditorGUILayout.LabelField("\n");

        selectedOption = EditorGUILayout.Popup("Sorting Layer", selectedOption, sortingLayerNames);
        if (sortingLayerNames[selectedOption] != renderer.sortingLayerName)
        {
            Undo.RecordObject(renderer, "Sorting Layer");
            if (!applyToChild)
                renderer.sortingLayerName = sortingLayerNames[selectedOption];
            else
            {
                for (int i = 0; i<childsRenderer.Length;i++)
                {
                    childsRenderer[i].sortingLayerName = sortingLayerNames[selectedOption];
                }
            }
            EditorUtility.SetDirty(renderer);
        }

        int newSortingLayerOrder = EditorGUILayout.IntField("Order in Layer", renderer.sortingOrder);
        if (newSortingLayerOrder != renderer.sortingOrder)
        {
            Undo.RecordObject(renderer, "Edit Sorting Order");
            renderer.sortingOrder = newSortingLayerOrder;
            EditorUtility.SetDirty(renderer);
        }

        applyToChild = EditorGUILayout.ToggleLeft("Apply to Childs", applyToChild);
        if (applyToChild != applyToChildOldValue)
        {
            for (int i = 0; i<childsRenderer.Length;i++)
            {
                childsRenderer[i].sortingLayerName = sortingLayerNames[selectedOption];
            }
            Undo.RecordObject(renderer, "Apply Sort Mode To Child");
            applyToChildOldValue = applyToChild;
            EditorUtility.SetDirty(renderer);
        }
    }

    // Get the sorting layer names
    public string[] GetSortingLayerNames()
    {
        Type internalEditorUtilityType = typeof(InternalEditorUtility);
        PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
        return (string[])sortingLayersProperty.GetValue(null, new object[0]);
    }
    
    // Get the unique sorting layer IDs -- tossed this in for good measure
    public int[] GetSortingLayerUniqueIDs()
    {
        Type internalEditorUtilityType = typeof(InternalEditorUtility);
        PropertyInfo sortingLayerUniqueIDsProperty = internalEditorUtilityType.GetProperty("sortingLayerUniqueIDs", BindingFlags.Static | BindingFlags.NonPublic);
        return (int[])sortingLayerUniqueIDsProperty.GetValue(null, new object[0]);
    }
}

EDIT:
Still wanted some help here but I did a little trick. Not the wanted solution but worked until someone comes with an integrated solution for Shuriken.

This is the Editor code

//  RendererLayerEditor.cs
//   Author:
//       Yves J. Albuquerque <yves.albuquerque@gmail.com>
//  Last Update:
//       28-12-2013 
//Put this file into a folder named Editor.
//Based on Nick`s code at https://gist.github.com/nickgravelyn/7460288 and Ivan Murashko solution at http://forum.unity3d.com/threads/210683-List-of-sorting-layers?p=1432958&viewfull=1#post1432958 aput by Guavaman at http://answers.unity3d.com/questions/585108/how-do-you-access-sorting-layers-via-scripting.html
using System;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Reflection;

[CanEditMultipleObjects()]
[CustomEditor(typeof(RendererLayer))]
public class RendererLayerEditor : Editor
{
    ParticleSystem[] l_particleSystems; //reference to our particle systems
    Renderer[] l_renderers;//reference to our renderers

    string[] sortingLayerNames;//we load here our Layer names to be displayed at the popup GUI
    int popupMenuIndex;//The selected GUI popup Index
    bool applyToChild = false;//Turn on/off if the effect will be extended to all renderers in child transforms
    bool applyToChildOldValue = false;//Used this old value to detect changes in applyToChild boolean

    /// <summary>
    /// Raises the enable event. We use it to set some references and do some initialization. I don`t figured out how to make a variable persistent in Unity Editor yet so most of the codes here can useless
    /// </summary>
    void OnEnable()
    {
        sortingLayerNames = GetSortingLayerNames(); //First we load the name of our layers
        l_particleSystems = (target as RendererLayer).gameObject.GetComponentsInChildren<ParticleSystem>();//Then we load our ParticleSystems
        l_renderers = new Renderer[l_particleSystems.Length];//and Initialize our renderers array with the right size

        for (int i = 0; i<l_particleSystems.Length;i++) //here we loads all renderers to our renderersarray
        {
            l_renderers[i] = l_particleSystems[i].renderer;
        }

        for (int i = 0; i<sortingLayerNames.Length;i++) //here we initialize our popupMenuIndex with the current Sort Layer Name
        {
            if (sortingLayerNames[i] == l_particleSystems[0].renderer.sortingLayerName)
                popupMenuIndex = i;
        }
    }

    /// <summary>
    /// OnInspectorGUI is where the magic happens. Here we draw and change all the stuff
    /// </summary>
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector(); //first we draw our DefaultInspector

        if (l_renderers.Length == 0) //if there`s no Renderer at this object
        {
            return; //returns
        }

        popupMenuIndex = EditorGUILayout.Popup("Sorting Layer", popupMenuIndex, sortingLayerNames);//The popup menu is displayed simple as that
        int newSortingLayerOrder = EditorGUILayout.IntField("Order in Layer", l_renderers[0].sortingOrder); //Specifies the order to be drawed in this particular SortLayer
        applyToChild = EditorGUILayout.ToggleLeft("Apply to Childs", applyToChild);//If this change will be applyed to every renderer or just this one

        if (sortingLayerNames[popupMenuIndex] != l_renderers[0].sortingLayerName ||
            newSortingLayerOrder != l_renderers[0].sortingOrder ||
            applyToChild != applyToChildOldValue) //if there`s some change
        {
            Undo.RecordObject(l_renderers[0], "Change Particle System Renderer Order"); //first let record this change into Undo class so if the user did a mess, he can use ctrl+z to undo

            if (applyToChild) //change sortingLayerName and sortingOrder in each Renderer
            {
                for (int i = 0; i<l_renderers.Length;i++)
                {
                    l_renderers[i].sortingLayerName = sortingLayerNames[popupMenuIndex];
                    l_renderers[i].sortingOrder = newSortingLayerOrder;
                }
            }
            else //or at least at this one
            {
                l_renderers[0].sortingLayerName = sortingLayerNames[popupMenuIndex];
                l_renderers[0].sortingOrder = newSortingLayerOrder;
            }

            EditorUtility.SetDirty(l_renderers[0]); //saves
        }
    }

    // Get the sorting layer names
    public string[] GetSortingLayerNames()
    {
        Type internalEditorUtilityType = typeof(InternalEditorUtility);
        PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
        return (string[])sortingLayersProperty.GetValue(null, new object[0]);
    }
}

But unfortunately you need to put a code in your Shuriken Effect. An almost empty code with a particular name. Sad but true.

using UnityEngine;
public class RendererLayer : MonoBehaviour{}
2 Likes

IT WORKS WITH PARTICLES! Thank you for making this extension! You saved me some trouble!

1 Like

I’m not using Shuriken, but need help showing the sorting layer for non sprites. How exactly do I proceed with this?

I want to try this but it isn’t working for me. The first script doesn’t even compile, it says:

…/ShortLayerRendererExtension.cs(77,77): Error CS0246: The type or namespace name `SortingLayerExposed’ could not be found. Are you missing a using directive or an assembly reference? (CS0246) (Assembly-CSharp-Editor)

Where is that class defined?

Bests!

Ok, forget my previous question. I found the git repository here:

https://gist.github.com/nickgravelyn/7460288

Still wondering how to get it working.

Got it working.

You might like to try this guy’s free addon. It seems to be pretty slick, though the sorting orders seem to reset after a play / stop.

Hello guys,
I’ve included an updated version of Sort Layer Renderer at Asset Store. (Compatible with Unity 5)
It’s included into a tutorial called ESR (Now, for FREE).
Best regards,

1 Like