Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
3
Question by Steven-1 · Apr 11, 2013 at 01:59 PM · guieditoreditorguilayoutgradient

How to have a gradient editor in an editor script?

I was making an editor script where you have to define a gradient, and I noticed there's a gradient editor in the particle system editor: http://docs.unity3d.com/Documentation/Manual/GradientEditor.html and there's also the gradient class you can access from script: http://docs.unity3d.com/Documentation/ScriptReference/Gradient.html

So is there a way to have this in an editor script? I mean something like EditorGUILayout.GradientField (like there is EditorGUILayout.ColorField)

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image numberkruncher · Apr 11, 2013 at 02:28 PM 1
Share

You would need to use reflection since UnityEditor.EditorGUILayout.GradientField is declared for internal use only and its return is UnityEditor.Gradient which is also declared for internal use only. You should make a feature request on the Unity Feedback site because they often get listened to!

avatar image Steven-1 · Apr 21, 2013 at 02:58 PM 0
Share

hm, alright, thanks. I'm still using 3.5something though, so if they do change this, I would have to switch to 4 to be able to use it. :s

5 Replies

· Add your reply
  • Sort: 
avatar image
7
Best Answer

Answer by numberkruncher · Apr 21, 2013 at 07:27 PM

In Unity 3.5.7 this functionality is provided entirely by the editor API (whilst in Unity 4.x the Gradient data class is available from the runtime library).

Here is a quick reflection based hack which I have quickly put together for you which allows you to make use of the gradient editor field in both Unity 3.5.7 and Unity 4.x. To make this easier to use I have created a wrapper, but this functionality is strictly editor-only.

alt text

I would recommend adding error handling to the reflection side of things, this was literally just a quick mashup to demonstrate the concept which I mentioned in my earlier comment. I hope that this will be of some help to you :)

Side Note: It probably be relatively easy to replicate this with an entirely custom editor field since you could probably just use vertex colors to simulate the gradient blending.

Assets/Editor/GradientTest/GUIGradientField.cs

 using UnityEngine;
 using UnityEditor;
 
 using System.Reflection;
 
 using Type = System.Type;
 
 public static class GUIGradientField {
     
     #region Initial Setup
     
     private static MethodInfo s_miGradientField1;
     private static MethodInfo s_miGradientField2;
     
     static GUIGradientField() {
         // Get our grubby hands on hidden "GradientField" :)
         Type tyEditorGUILayout = typeof(EditorGUILayout);
         s_miGradientField1 = tyEditorGUILayout.GetMethod("GradientField", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string), GradientWrapper.s_tyGradient, typeof(GUILayoutOption[]) }, null);
         s_miGradientField2 = tyEditorGUILayout.GetMethod("GradientField", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { GradientWrapper.s_tyGradient, typeof(GUILayoutOption[]) }, null);
     }
     
     #endregion
     
     public static GradientWrapper GradientField(string label, GradientWrapper gradient, params GUILayoutOption[] options) {
         if (gradient == null)
             gradient = new GradientWrapper();
 
         gradient.GradientData = s_miGradientField1.Invoke(null, new object[] { label, gradient.GradientData, options });
         
         return gradient;
     }
     
     public static GradientWrapper GradientField(GradientWrapper gradient, params GUILayoutOption[] options) {
         if (gradient == null)
             gradient = new GradientWrapper();
 
         gradient.GradientData = s_miGradientField1.Invoke(null, new object[] { gradient.GradientData, options });
         
         return gradient;
     }
     
 }

Assets/Editor/GradientTest/GradientWrapper.cs

 using UnityEngine;
 using UnityEditor;
 
 using System.Reflection;
 using System.Linq;
 
 using Activator = System.Activator;
 using Array = System.Array;
 using Type = System.Type;
 
 [System.Serializable]
 public class GradientWrapper {
     
     /// <summary>
     /// Wrapper for <c>GradientColorKey</c>.
     /// </summary>
     public struct ColorKey {
         public Color color;
         public float time;
         
         public ColorKey(Color color, float time) {
             this.color = color;
             this.time = time;
         }
     }
 
     /// <summary>
     /// Wrapper for <c>GradientAlphaKey</c>.
     /// </summary>
     public struct AlphaKey {
         public float alpha;
         public float time;
         
         public AlphaKey(float alpha, float time) {
             this.alpha = alpha;
             this.time = time;
         }
     }
     
     #region Initial Setup
     
     /// <summary>
     /// Type of gradient.
     /// </summary>
     public static Type s_tyGradient;
     
 #if (UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9)
     private static MethodInfo s_miEvaluate;
     private static PropertyInfo s_piColorKeys;
     private static PropertyInfo s_piAlphaKeys;
 
     private static Type s_tyGradientColorKey;
     private static Type s_tyGradientAlphaKey;
 #endif
 
     /// <summary>
     /// Perform one-off setup when class is accessed for first time.
     /// </summary>
     static GradientWrapper() {
 #if (UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9)    
         Assembly editorAssembly = typeof(Editor).Assembly;
 
         s_tyGradientColorKey = editorAssembly.GetType("UnityEditor.GradientColorKey");
         s_tyGradientAlphaKey = editorAssembly.GetType("UnityEditor.GradientAlphaKey");
 
         // Note that `Gradient` is defined in the editor namespace in Unity 3.5.7!
         s_tyGradient = editorAssembly.GetType("UnityEditor.Gradient");
         s_miEvaluate = s_tyGradient.GetMethod("CalcColor", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(float) }, null);
         s_piColorKeys = s_tyGradient.GetProperty("colorKeys", BindingFlags.Public | BindingFlags.Instance);
         s_piAlphaKeys = s_tyGradient.GetProperty("alphaKeys", BindingFlags.Public | BindingFlags.Instance);
 #else
         // In Unity 4 this is easy :)
         s_tyGradient = typeof(Gradient);
 #endif
     }
     
     #endregion
     
 #if (UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9)    
     #region Unity 3.5.7 Implementation
     
     private object _gradient = Activator.CreateInstance(s_tyGradient);
     
     public object GradientData {
         get { return _gradient; }
         set { _gradient = value; }
     }
     
     public Color Evaluate(float time) {
         return (Color)s_miEvaluate.Invoke(_gradient, new object[] { time });
     }
     
     public void SetKeys(ColorKey[] colorKeys, AlphaKey[] alphaKeys) {
         if (colorKeys != null) {
             Array colorKeyParam = (Array)Activator.CreateInstance(s_tyGradientColorKey.MakeArrayType(), new object[] { colorKeys.Length });
             for (int i = 0; i < colorKeys.Length; ++i)
                 colorKeyParam.SetValue(Activator.CreateInstance(s_tyGradientColorKey, colorKeys[i].color, colorKeys[i].time), i);
             s_piColorKeys.SetValue(_gradient, colorKeyParam, null);
         }
         if (alphaKeys != null) {
             Array alphaKeyParam = (Array)Activator.CreateInstance(s_tyGradientAlphaKey.MakeArrayType(), new object[] { alphaKeys.Length });
             for (int i = 0; i < alphaKeys.Length; ++i)
                 alphaKeyParam.SetValue(Activator.CreateInstance(s_tyGradientAlphaKey, alphaKeys[i].alpha, alphaKeys[i].time), i);
             s_piAlphaKeys.SetValue(_gradient, alphaKeyParam, null);
         }
     }
     
     #endregion
 #else
     #region Unity 4.x Implementation
     
     private Gradient _gradient = new Gradient();
     
     public object GradientData {
         get { return _gradient; }
         set { _gradient = value as Gradient; }
     }
     
     public Color Evaluate(float time) {
         return _gradient.Evaluate(time);
     }
     
     public void SetKeys(ColorKey[] colorKeys, AlphaKey[] alphaKeys) {
         GradientColorKey[] actualColorKeys = null;
         GradientAlphaKey[] actualAlphaKeys = null;
 
         if (colorKeys != null)
             actualColorKeys = colorKeys.Select(key => new GradientColorKey(key.color, key.time)).ToArray();
         if (alphaKeys != null)
             actualAlphaKeys = alphaKeys.Select(key => new GradientAlphaKey(key.alpha, key.time)).ToArray();
 
         _gradient.SetKeys(actualColorKeys, actualAlphaKeys);
     }
     
     #endregion
 #endif
     
 }

Assets/Editor/GradientTest/GradientEditorWindow.cs

 using UnityEngine;
 using UnityEditor;
 
 public class GradientEditorWindow : EditorWindow {
     
     [MenuItem("Window/Gradient Editor Test")]
     public static void Show() {
         GetWindow<GradientEditorWindow>("Gradient Editor Test Window");
     }
     
     GradientWrapper gradient;
     float time;
     
     GUIStyle previewStyle;
     
     void OnEnable() {
         previewStyle = new GUIStyle();
         previewStyle.normal.background = EditorGUIUtility.whiteTexture;
     }
     
     void OnGUI() {
         gradient = GUIGradientField.GradientField("Test Gradient", gradient);
         
         if (GUILayout.Button("Set Keys Test")) {
             OnSetKeysTest();
             GUIUtility.ExitGUI();
         }
         
         time = Mathf.Clamp01(EditorGUILayout.Slider("Time", time, 0, 1));
         
         // Extract color at specific time.
         Color restoreBackgroundColor = GUI.backgroundColor;
         GUI.backgroundColor = gradient.Evaluate(time);
         GUILayout.Box(GUIContent.none, previewStyle, GUILayout.Width(200), GUILayout.Height(50));
         GUI.backgroundColor = restoreBackgroundColor;
     }
     
     void OnSetKeysTest() {
         GradientWrapper.ColorKey[] colorKeys = new GradientWrapper.ColorKey[] {
             new GradientWrapper.ColorKey(Color.red, 0f),
             new GradientWrapper.ColorKey(Color.green, 0.5f),
             new GradientWrapper.ColorKey(Color.blue, 1f)
         };
         
         GradientWrapper.AlphaKey[] alphaKeys = new GradientWrapper.AlphaKey[] {
             new GradientWrapper.AlphaKey(1f, 0f),
             new GradientWrapper.AlphaKey(1f, 1f)
         };
         
         gradient.SetKeys(colorKeys, alphaKeys);
     }
     
 }



screenyt.png (24.3 kB)
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Steven-1 · Apr 22, 2013 at 11:48 AM 0
Share

wow, thanks for the extensive reply! I can't look at it right now, but I'll look at it later today (I'm at work now, and this is for a hobby project)

avatar image Steven-1 · Jul 31, 2013 at 08:33 AM 0
Share

Sorry for the late reply, the project I needed this for had been on hold for a while. But I have tested it and it works like a charm. I'm not familiar with reflection though, so I don't really know how it works, but I get a warning saying s_miGradientField2 isn't used (in GUIGradientField.cs). I commented it out and everything still works. Anyway, thanks a lot for this. :)

avatar image codeguyross1 · Dec 05, 2016 at 08:45 PM 0
Share

This was a cut and paste and it worked solution for me. Thanks!

avatar image
3

Answer by ickydime · May 16, 2013 at 08:14 PM

I found a simpler way. At least less code.

Use EditorGUILayout.PropertyField and pass in a serializedProperty of a Gradient.

In my case I created a class that has a public gradient property. Example of some pseudo code below. Note, you will need to create a GradientContainer class that extends MonoBehaviour and has a public Gradient variable named 'ColorGradient'.

 // OnEnable 
 GameObject tempObject = new GameObject();
 
 GradientContainer gradientContainer = (GradientContainer) tempObject.AddComponent("GradientContainer");
 
 SerializedObject serializedGradient = new SerializedObject(gradientContainer);
 SerializedProperty colorGradient = serializedGradient.FindProperty("ColorGradient");
 
 // OnGUI
 EditorGUI.BeginChangeCheck();
 EditorGUILayout.PropertyField(colorGradient, true, null);
 if(EditorGUI.EndChangeCheck())
 {
     serializedGradient.ApplyModifiedProperties();
 }
 
 // Accessing Later
 GradientContainer gradientContainer = (GradientContainer)serializedGradient.targetObject;
 
 
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image numberkruncher · May 16, 2013 at 08:48 PM 0
Share

Yes this is much simpler, though the example that I demonstrated will also work for recent versions of Unity 3.5 (which was the primary source of the complexity). But you are right, you propose a good solution for Unity 4 users :)

avatar image ataxkt · Dec 09, 2014 at 03:14 PM 1
Share

This worked for me. If you're making an Editor Window that doesn't need to remember variables, you can just use this

 EditorGUI.BeginChangeCheck();
         SerializedObject serializedGradient = new SerializedObject(this);
         SerializedProperty colorGradient = serializedGradient.FindProperty("gradient");
         EditorGUILayout.PropertyField(colorGradient, true, null);
         if(EditorGUI.EndChangeCheck()) {
             serializedGradient.Apply$$anonymous$$odifiedProperties();
          }



avatar image TobiasB ataxkt · Aug 28, 2018 at 01:32 PM 0
Share

You just saved my day! :)

PS: It makes NO sense that this is not the most correct answer to the question as it does exactly what you need...

avatar image
2

Answer by darrinm · Apr 20, 2013 at 10:26 PM

To have the gradient editor appear for a property of your script, just declare it as:

C#:

 public Gradient myGradient;

JS:

 myGradient:Gradient;

Then you can access it via script as per the documentation you already found.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Steven-1 · Apr 21, 2013 at 03:01 PM 0
Share

well yeah, but I was asking about the use in an Editor script. So I still need a GUI function to draw it in OnGUI()

avatar image Alismuffin · Jan 16, 2016 at 07:04 AM 0
Share

This is great! I did notice however that the gradient does not actually serialize unless you have

[SerializeField] on private Gradient _gradient = new Gradient();

avatar image
0

Answer by TheDreamMaster · Mar 12, 2015 at 05:27 AM

How exactly does one implement ickydime's solution?

I have tried to follow what he describes but have been unable to get the pseudocode to a usable state.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by kiwon · Aug 18, 2017 at 02:08 AM

   //using System.Linq //using System.Reflection
     var method = typeof(EditorGUI)
                     .GetMethods(BindingFlags.NonPublic |BindingFlags.Static )
                     .First(t=>t.Name == "GradientField");
      var change = m.Invoke(null, new object[] { rect, gradient });

it's working anyway.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

19 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

BeginScrollView - But make background darker? 1 Answer

Space for describing text in EditorGUILayout too short 1 Answer

How can I determine when user presses enter in an editor text field? 3 Answers

How do I prevent "Argument Exception: Getting control 1's position in a group with only 1 controls when doing repaint" in OnGUI function of my CustomPropertyDrawer? 2 Answers

Get height of a group of GUILayout controls 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges