Unity Tutorial - Using MaterialPropertyBlock with Renderer for simple Sprite colorization

Unity Tutorial: Using MaterialPropertyBlock with Renderer for simple Sprite colorization

Unity Tutorial: Using MaterialPropertyBlock with Sprite Renderer for simple. easy and quick Sprite colorization.

When creating a UI in Unity, we sometimes need to display the same sprites but with distinct colors. We can use MaterialPropertyBlock to colorize our Sprites at runtime, avoiding using many sprites.

Loading just a few Sprites might not have a significant impact on our game, but if the number of Sprites we use grows, this will impact loading times and performance. Using MaterialPropertyBlock can help us reduce the number of resources (e.g. Sprites) we need to load, and just reuse the same Sprite multiple times with different colors.

Colorizing a Sprite

Using a MaterialPropertyBlock with a Sprite Renderer is quite easy – we retrieve the Renderer‘s MaterialPropertyBlock, manipulate it any way we want, and assign it back to the Renderer. Let’s look at a simple example to colorize a Sprite:

[RequireComponent(typeof(Renderer))]
public class ColorizeWithMaterialPropertyBlock : MonoBehaviour
{
    void Awake()
    {
        var selectedColor = Color.HSVToRGB(Random.Range(0f, 1f), 1f, 1f);

        var renderer = GetComponent<Renderer>();

        var propBlock = new MaterialPropertyBlock();
        renderer.GetPropertyBlock(propBlock);
        // Assign our new value.
        propBlock.SetColor("_Color", selectedColor);

        // Apply the edited values to the renderer.
        renderer.SetPropertyBlock(propBlock);
    }
}

The code is trivial – we select a random color, populate the values of our MaterialPropertyBlock from the Renderer using the GetPropertyBlock method. We then assign it a new value to the “_Color” property and assign it back to the Renderer using the SetPropertyBlock method.

Rotating between colors

We can use the same mechanism to dynamically change the color of our Sprite as time passes. We’ll slightly modify the above code – we’ll get two colors from the user, and lerp between them. In addition, as we call the SetColor property frequently, we’ll use a more efficient method of finding the property’s ID, and use that instead:

[RequireComponent(typeof(Renderer))]
public class RotateColorsWithMaterialPropertyBlock : MonoBehaviour
{
    public Color Color1, Color2;
    public float Speed = 1, Offset;

    private Renderer _renderer;
    private int m_colorID;
    private MaterialPropertyBlock _propBlock;

    void Awake()
    {
        _propBlock = new MaterialPropertyBlock();
        // Get the current value of the material properties in the renderer.
        _renderer = GetComponent<Renderer>();
        _renderer.GetPropertyBlock(_propBlock);

        m_colorID = Shader.PropertyToID("_Color");
    }

    void Update()
    {
        // Assign our new value.
        _propBlock.SetColor(m_colorID, Color.Lerp(Color1, Color2, (Mathf.Cos(Time.time * Speed + Offset) + 1) / 2f));
        // Apply the edited values to the renderer.
        _renderer.SetPropertyBlock(_propBlock);
    }
}

Curve-based colorizing

We can use a slightly more complex way of switching between colors – using an AnimationCurve instead of Lerp, to have more control over the color switching (e.g., steps instead of smooth changes):

[RequireComponent(typeof(Renderer))]
public class CurveBasedColorsWithMaterialPropertyBlock : MonoBehaviour
{
    public Color Color1, Color2;
    public float Speed = 1, Offset;

    public AnimationCurve Curve;

    private Renderer _renderer;
    private int m_colorID;
    private MaterialPropertyBlock _propBlock;

    void Awake()
    {
        _renderer = GetComponent<Renderer>();
          
        // Get the current value of the material properties in the renderer.
        _propBlock = new MaterialPropertyBlock();
        _renderer.GetPropertyBlock(_propBlock);

        // Get the property ID of "_Color"
        m_colorID = Shader.PropertyToID("_Color");

        // Setting the curve to loop
        Curve.postWrapMode = WrapMode.Loop;
    }

    void Update()
    {
        // Assign our new value.
        _propBlock.SetColor(m_colorID, Color.Lerp(Color1, Color2, Curve.Evaluate(Time.time * Speed)));
        // Apply the edited values to the renderer.
        _renderer.SetPropertyBlock(_propBlock);
    }
}

You can download the whole code of this tutorial here: https://gist.github.com/saguiitay/1d9a20c5611ce5adfcf2a028fb7b51ce

GET NOTIFIED

Sign up to receive notifications when a new Unity Asset is released.