Skip to content

Instantly share code, notes, and snippets.

@kimsama
Last active January 19, 2018 02:27
Show Gist options
  • Select an option

  • Save kimsama/7b81fffb0f153b7cbd71 to your computer and use it in GitHub Desktop.

Select an option

Save kimsama/7b81fffb0f153b7cbd71 to your computer and use it in GitHub Desktop.
NGUI Tip: A way to apply a shader on one sprite in an atlas. Find UISprite.material property in the UISprite.cs then sustitue it with the following code. It works on NGUI 3.7.0 or higher version.
//////////////////////////////////////////////////////////////////////////
//
// ShaderMenuUtility
//
// Created by hwkim.
//
// Copyright 2014 MonsterSmile.Inc
// All rights reserved
//
//////////////////////////////////////////////////////////////////////////
using UnityEngine;
using UnityEditor;
using System.Linq;
/// <summary>
///
/// </summary>
public static class ShaderMenuUtility
{
#region Helper
private static GUIContent _tempText = new GUIContent();
private static GUIContent TempContent(string text)
{
_tempText.text = text;
return _tempText;
}
#endregion
#region Shader Name Cache
private static GUIContent[] _shaderNames;
//-------------------------------------------------------------------------
private static void ClearShaderCache()
{
_shaderNames = null;
}
private static Material _dummyMaterial;
//-------------------------------------------------------------------------
private static void PrepareShaderCache()
{
if (_dummyMaterial == null)
{
_dummyMaterial = new Material(Shader.Find("Diffuse"));
_dummyMaterial.hideFlags = HideFlags.HideAndDontSave;
}
// This is a little wasteful, but unfortunately needed :/
UnityEditorInternal.InternalEditorUtility.SetupShaderMenu(_dummyMaterial);
// Fetch shaders and filter
Shader[] shaders = (Shader[])UnityEngine.Resources.FindObjectsOfTypeAll(typeof(Shader));
shaders = shaders.Where(s => s != null && s.name != "" && !s.name.StartsWith("__")).ToArray();
// Generate list of shader names
_shaderNames = shaders.Select(s => new GUIContent(s.name)).ToArray();
}
#endregion
//-------------------------------------------------------------------------
// EditorGUI style version
public static Shader ShaderField(Rect position, string label, Shader shader)
{
int controlID = GUIUtility.GetControlID(FocusType.Passive);
EventType eventType = Event.current.GetTypeForControl(controlID);
// Clear shader cache before layout is processed for control
if (eventType == EventType.Layout)
ClearShaderCache();
if (!string.IsNullOrEmpty(label))
position = EditorGUI.PrefixLabel(position, controlID, TempContent(label));
// Prepare list of shaders
if (_shaderNames == null)
PrepareShaderCache();
int selectedIndex = (shader != null)
? System.Array.FindIndex(_shaderNames, c => c.text == shader.name)
: -1;
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUI.Popup(position, selectedIndex, _shaderNames);
if (EditorGUI.EndChangeCheck())
{
shader = (selectedIndex >= 0 && selectedIndex < _shaderNames.Length)
? Shader.Find(_shaderNames[selectedIndex].text)
: null;
}
return shader;
}
//-------------------------------------------------------------------------
// EditorGUILayout style version
public static Shader ShaderField(string label, Shader shader, params GUILayoutOption[] options)
{
Rect position = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.popup, options);
return ShaderField(position, label, shader);
}
//-------------------------------------------------------------------------
/// <summary>
/// Used to reflect a shader setting on NGUI's UIShader component.
/// </summary>
public static SerializedProperty ShaderField(string label, SerializedObject serializedObject, string property, params GUILayoutOption[] options)
{
SerializedProperty sp = serializedObject.FindProperty(property);
if (sp != null)
{
Shader shader = sp.objectReferenceValue as UnityEngine.Object as Shader;
if (shader == null)
{
shader = Shader.Find("Unlit/Transparent Colored");
}
Rect position = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.popup, options);
shader = ShaderField(position, label, shader);
sp.objectReferenceValue = shader;
}
return sp;
}
}
//public override Material material
//{
// get {
// return (mAtlas != null) ? mAtlas.spriteMaterial : null;
// }
//}
[HideInInspector][SerializeField]
Shader mShader;
Material mMaterial;
// cache materials
static Dictionary<int, Dictionary<int, Material>> mCachedAtlasMaterials = new Dictionary<int, Dictionary<int, Material>>();
/// <summary>
/// Substitute UISprite's material to dynamically change a shader of the given atlas material.
/// </summary>
public override Material material
{
get
{
if (mShader != null)
{
if (mMaterial == null || mChanged)
{
Dictionary<int, Material> shaderMaterials;
if (!mCachedAtlasMaterials.TryGetValue(atlas.GetInstanceID(), out shaderMaterials))
mCachedAtlasMaterials[atlas.GetInstanceID()] = shaderMaterials = new Dictionary<int, Material>();
if (!shaderMaterials.TryGetValue(mShader.GetInstanceID(), out mMaterial) || mMaterial == null)
{
if (mAtlas != null)
shaderMaterials[mShader.GetInstanceID()] = mMaterial = new Material(mAtlas.spriteMaterial) { shader = mShader};
}
}
return mMaterial;
}
return (mAtlas != null) ? mAtlas.spriteMaterial : null;
}
}
/// <summary>
/// Specified sprite to change material with the given shader so enables a shader on each of a sprite.
/// Pass null if it needs to be restored and NGUI handles a material.
/// </summary>
public void SetShader (Shader shd)
{
mShader = shd;
panel.RebuildAllDrawCalls(); // need to force redraw to prevent not applying the shader on the sprite.
}
/// <summary>
/// It may need to add the following line the shader to be shown on the inspector view.
/// </summary>
protected override bool ShouldDrawProperties ()
{
// add this line
ShaderMenuUtility.ShaderField("Shader", serializedObject, "mShader", GUILayout.MinWidth(20f));
GUILayout.BeginHorizontal();
...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment