- Home /
How to use Material Property Blocks in Sprite Renderer and Custom Editor Scripts?
Hi, I'm having some problems with Material Property Blocks...
My objects are always sprite renderers, but they have 3 sprites. The shader controls which Texture to show.
I have a custom editor for sprite renderer that lets you set the 3 sprites. We use different materials for each object, but we decided to use only 1 material and use Material Property Block to change the textures of each object, per renderer. During edit mode it looks it works, I can see the sprites on the scene, but when playing, the material property block gets reset somewhat, as if the sprite renderer was overwriting it, so only the main sprite stays and the other 2 textures are gone.
The question is: once you set a material property block, does it stay like when you set a texture in a material? or do I have to set it everytime I play?
Is there a way to get what I want to do? Using one material for all objects but set the 3 textures different per object?
Thanks for the help.
This the custom editor code: using UnityEditor; using UnityEngine;
[CanEditMultipleObjects]
[CustomEditor( typeof( SpriteRenderer ) )]
public class TestSpriteRendererEditor : Editor
{
#region Accessors
protected bool IsComposer
{
get
{
Material mat = materialProp.objectReferenceValue as Material;
return mat && mat.HasProperty( "_WarmTex" ) && mat.HasProperty( "_ColdTex" );
}
}
private SpriteRenderer _rend
{
get
{
return target as SpriteRenderer;
}
}
#endregion Accessors
#region PrivateFields
//Props
private SerializedProperty materialProp;
private SerializedProperty coldSpriteProp;
private SerializedProperty colorProp;
private SerializedProperty sortingLayerProp;
private SerializedProperty sortingOrderProp;
//sprites are fields taken from textures
private Sprite _neutral_sprite;
private Sprite _warm_sprite;
private Sprite _cold_sprite;
//SortingLayer as an enum, is a field
private UnitySortingLayer _sorting_layer;
private MaterialPropertyBlock _property_block;
#endregion PrivateFields
#region Unity
private void OnEnable( )
{
if( _property_block == null )
{
_property_block = new MaterialPropertyBlock( );
_rend.GetPropertyBlock( _property_block );
}
_SetPropsFromSpriteRenderer( );
_ApplyModifiedPropertiesToRender( );
}
public override void OnInspectorGUI( )
{
serializedObject.Update( );
//Material. Textures will be applied if material changes
EditorGUI.BeginChangeCheck( );
EditorGUILayout.PropertyField( materialProp, new GUIContent( "Material" ) );
if( EditorGUI.EndChangeCheck( ) )
{
_ApplyMaterialTextures( );
serializedObject.ApplyModifiedProperties( );
}
//Rest of the properties
EditorGUI.BeginChangeCheck( );
EditorGUILayout.Space( );
//Sprites
string neutral_sprite_name = IsComposer ? "Neutral Sprite" : "Sprite";
_neutral_sprite = EditorGUILayout.ObjectField( neutral_sprite_name, _neutral_sprite, typeof( Sprite ), true ) as Sprite;
if( IsComposer )
{
_warm_sprite = EditorGUILayout.ObjectField( "Warm Sprite", _warm_sprite, typeof( Sprite ), true ) as Sprite;
_cold_sprite = EditorGUILayout.ObjectField( "Cold Sprite", _cold_sprite, typeof( Sprite ), true ) as Sprite;
}
if( EditorGUI.EndChangeCheck( ) )
{
_ApplyModifiedPropertiesToRender( );
}
}
#endregion Unity
#region PrivateMethods
private void _SetPropsFromSpriteRenderer( )
{
_ApplyMaterialTextures( );
colorProp = serializedObject.FindProperty( "m_Color" );
//Sorting layer
sortingLayerProp = serializedObject.FindProperty( "m_SortingLayerID" );
_sorting_layer = new UnitySortingLayer( );
_sorting_layer.Set( UnitySortingLayerUtils.GetSortingLayerIndex( sortingLayerProp.intValue ), sortingLayerProp.intValue );
//Sorting Order
sortingOrderProp = serializedObject.FindProperty( "m_SortingOrder" );
}
private void _ApplyMaterialTextures( )
{
//Material
materialProp = serializedObject.FindProperty( "m_Materials" ).GetArrayElementAtIndex( 0 );
//Sprites
Texture2D main_tex = _property_block.GetTexture( "_MainTex" ) as Texture2D;
if( main_tex )
{
_neutral_sprite = EditorUtils.GetObjectFromPath<Sprite>( main_tex );
}
Texture2D warm_tex = _property_block.GetTexture( "_WarmTex" ) as Texture2D;
if( warm_tex )
{
_warm_sprite = EditorUtils.GetObjectFromPath<Sprite>( warm_tex );
}
Texture2D cold_tex = _property_block.GetTexture( "_ColdTex" ) as Texture2D;
if( cold_tex )
{
_cold_sprite = EditorUtils.GetObjectFromPath<Sprite>( cold_tex );
}
else
{
Debug.Log( "Cold tex is null" );
}
}
private void _ApplyModifiedPropertiesToRender( )
{
if( IsComposer )
{
_rend.GetPropertyBlock( _property_block );
_SetNeutralTextureInRender( );
_SetWarmTextureInRender( );
_setColdTextureInRender( );
_rend.SetPropertyBlock( _property_block );
}
sortingLayerProp.intValue = _sorting_layer.layerUid;
serializedObject.ApplyModifiedProperties( );
}
private void _SetTextureInRender( string tex_name_, Sprite sprite_ )
{
if( sprite_ && sprite_.texture )
{
_property_block.SetTexture( tex_name_, sprite_.texture );
}
}
private void _SetNeutralTextureInRender( )
{
_SetTextureInRender( "_MainTex", _neutral_sprite );
}
private void _SetWarmTextureInRender( )
{
_SetTextureInRender( "_WarmTex", _warm_sprite );
}
private void _setColdTextureInRender( )
{
_SetTextureInRender( "_ColdTex", _cold_sprite );
}
#endregion PrivateMethods
}
to question. Would love to know that either. It would be very convenient to use $$anonymous$$aterialBlock properties for coloring some prefabs in editor, ins$$anonymous$$d of creating new shader for vertex coloring.
Your answer
Follow this Question
Related Questions
Rigged 2D Sprite looks weird after adding a shadergraph material 0 Answers
Stencil inside Stencil? (Multiple masks on same object) 1 Answer
Shader doesn't work when object is inverted by axis 1 Answer
Sprite behind semi transparent mesh 0 Answers
How to get the spriterender default material in the code 1 Answer