Using INonAnimatableProperty
When you're recording an animation every change you do gets recorded, material property changes included. But sometimes you don't want certain properties to be animated, cause maybe you're using them in a way that animating them would look weird, or simply is not something you want to be recorded if you happen to change it while the animation is recording.
The INonAnimatableProperty interface will help you with that by giving you the possibily separate the code that updates the property in a dedicated method that will never get called when the animation is recording, and notify the inspector that it needs to update a property outside the recording
Tip
SimpleShaderInspector keeps track of controls with this interface and when it detects that some of them need to write updates to a property it will stop the animation recording if it was running, updates the non animatable property values, and then restarts the animation recording if it was stopped.
Warning
Due to the need of using Reflection to stop and restart the animation recording, with the consequent performance cost, this system is disabled by default in any inspector and to activate it the user needs to set the HasNonAnimatableProperties inspector property to true during startup. If a non animatable property control is used when the system is disabled, the update code will run without checking the recording state.
Let's take our template code with INonAnimatableProperty implemented:
using UnityEditor;
using VRLabs.SimpleShaderInspectors;
public class MyCustomControl : PropertyControl, INonAnimatableProperty
{
public bool NonAnimatablePropertyChanged { get; set; }
public MyCustomControl(string propertyName) : base(propertyName)
{
}
protected override void ControlGUI(MaterialEditor materialEditor)
{
}
public void UpdateNonAnimatableProperty(MaterialEditor materialEditor)
{
}
}
INonAnimatableProperty requires you to implement 1 property and one method:
NonAnimatablePropertyChanged is used to let the inspector know that in this frame a material property needs to update outside of the recording.
UpdateNonAnimatableProperty is where we update the value of our MaterialProperty without being recorded.
Let's add a basic slider functionality o the class:
using UnityEditor;
using VRLabs.SimpleShaderInspectors;
public class MyCustomControl : PropertyControl, INonAnimatableProperty
{
public bool NonAnimatablePropertyChanged { get; set; }
public MyCustomControl(string propertyName) : base(propertyName)
{
}
protected override void ControlGUI(MaterialEditor materialEditor)
{
EditorGUI.BeginChangeCheck();
materialEditor.RangeProperty(Property, Content.text);
HasPropertyUpdated = EditorGUI.EndChangeCheck();
}
public void UpdateNonAnimatableProperty(MaterialEditor materialEditor)
{
}
}
In this current state the control will still record the changes into the animation for 2 reasons:
- We don't tell the inspector that we have a property to update outside of it
- We're updating the property inside
ControlGUI
The first one is easy to solve, we just need to set NonAnimatablePropertyChanged to true if the property has changed:
HasPropertyUpdated = EditorGUI.EndChangeCheck();
NonAnimatablePropertyChanged = HasPropertyUpdated;
As for the second one, things may get a bit trickier.
We cannot rely on materialEditor to draw our property, cause the property will get automatically updated, so we need to do it ourself with EditorGUILayout. We also need to store the value we get back so that we can apply it to the property afterwards:
public bool NonAnimatablePropertyChanged { get; set; }
private float _newValue;
protected override void ControlGUI(MaterialEditor materialEditor)
{
EditorGUI.BeginChangeCheck();
_newValue = EditorGUILayout.Slider(Content, Property.floatValue, Property.rangeLimits.x, Property.rangeLimits.y);
HasPropertyUpdated = EditorGUI.EndChangeCheck();
NonAnimatablePropertyChanged = HasPropertyUpdated;
}
And then we update the material property value inside UpdateNonAnimatableProperty:
public void UpdateNonAnimatableProperty(MaterialEditor materialEditor)
{
Property.floatValue = _newValue;
}
And with this, now our material property should update correctly without being recorded in the animation.
Finished example class
using UnityEditor;
using VRLabs.SimpleShaderInspectors;
public class MyCustomControl : PropertyControl, INonAnimatableProperty
{
public bool NonAnimatablePropertyChanged { get; set; }
private float _newValue;
public MyCustomControl(string propertyName) : base(propertyName)
{
}
protected override void ControlGUI(MaterialEditor materialEditor)
{
EditorGUI.BeginChangeCheck();
_newValue = EditorGUILayout.Slider(Content, Property.floatValue, Property.rangeLimits.x, Property.rangeLimits.y);
HasPropertyUpdated = EditorGUI.EndChangeCheck();
NonAnimatablePropertyChanged = HasPropertyUpdated;
}
public void UpdateNonAnimatableProperty(MaterialEditor materialEditor)
{
Property.floatValue = _newValue;
}
}