Sprite with MaterialPropertyBlock not updating until Animated

Hello Unity Community, this is my first question I ask here and I hope I don’t do anything terribly wrong.

I am currently developing a Megaman fan-game with Unity and C#. It’s been going okay, since I’m still new to Unity, but now I’ve run into a roadblock.
After a lot of pain, I managed to get palette swapping going with greyscale images, palette textures and a shader. This shader is a small edit on the sprites/default shader, so I’ll just post the relevant part.

Shader "Sprites/Palette"
{
	Properties
	{
		[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
		[PerRendererData] _PaletteTex ("Palette Texture", 2D) = "grey" {}
		_Color ("Tint", Color) = (1,1,1,1)
		[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
	}

	SubShader
	{
		/* ... Everything here is Default ... */

			sampler2D _PaletteTex;

			fixed4 frag(v2f IN) : SV_Target
			{
				fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
				c.rgb = tex2D (_PaletteTex, fixed2(c.r,0.5)).rgb;
				c.rgb *= c.a;
				return c;
			}
		ENDCG
		}
	}
}

So after that, I attached the shader to a material and the material to the player and two enemies. I then wrote a script to access the palette functionality (TL;DR Have an array of palette textures and apply the chosen one by index):

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(SpriteRenderer))]
public class SpritePalette : MonoBehaviour {
	private static string PALETTE_TEXTURE = "_PaletteTex";

	public Texture2D[] paletteTextures;

	private SpriteRenderer rend;
	private MaterialPropertyBlock block;

	void Start () {
		rend = GetComponent<SpriteRenderer> ();
		block = new MaterialPropertyBlock ();
		SetPalette (0);
	}

	public void SetPalette (int index) {
		if ((index >= paletteTextures.Length) || (index < 0)) {
			Debug.LogWarning ("[" + ToString () + "] Invalid palette index: " + index + " (Available: " + paletteTextures.Length + ")");
			return;
		}

		block.SetTexture (PALETTE_TEXTURE, paletteTextures [index]);
		rend.SetPropertyBlock (block);
	}
}

But now, when I start the game and an enemy is instantiated, it appears as a white square. The enemy stays in that state until any animation happens, at which point the palettes work perfectly fine.
Same happens whenever the palette is changed via “SetPalette(int index);”.

Here are two screenshots to show what happens:


Thanks for reading this, I hope that someone does know what the root of this problem is.
If you know a fix for this or maybe some workaround, I’d be glad if you could let me know.

Have a nice day and good luck coding.

Hello there.
Since I posted this, I had a theory about the cause of this problem and it turns out I was able to fix it.
I will post the solution here, in case anyone else ever has the same problem as I did. That’s what Answers are for :slight_smile:

Thing is: Apperantly, a MaterialPropertyBlock does not only set properties, but also resets properties that you did not explicitly specify.
That’s why, before animation kicks in and the sprites are processed by the animator, the main texture is basically “gone”. You can combat this by modifying the palette switching script like this:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(SpriteRenderer))]
public class SpritePalette : MonoBehaviour {
	private static string MAIN_TEXTURE = "_MainTex";
	private static string PALETTE_TEXTURE = "_PaletteTex";

	public Texture2D[] paletteTextures;

	private SpriteRenderer rend;
	private MaterialPropertyBlock block;
	private Texture2D mainTex;  // Store the main texture here

	void Start () {
		rend = GetComponent<SpriteRenderer> ();
		block = new MaterialPropertyBlock ();
		mainTex = GetSpriteTexture ();  // Assign main texture in Start()

		Debug.Log (
			rend.material.HasProperty (PALETTE_TEXTURE) ?
			ToString () + " - exists" :
			ToString () + " - DOES NOT EXIST");
		SetPalette (0);
	}


	public void SetPalette (int index) {
		if ((index >= paletteTextures.Length) || (index < 0)) {
			Debug.LogWarning ("[" + ToString () + "] Invalid palette index: " + index + " (Available: " + paletteTextures.Length + ")");
			return;
		}

		block.SetTexture (MAIN_TEXTURE, mainTex);  // Apply the sprite's main texture
		block.SetTexture (PALETTE_TEXTURE, paletteTextures [index]);
		rend.SetPropertyBlock (block);
		rend.sprite = rend.sprite;
	}

	private Texture2D GetSpriteTexture () {
		// Get main texture trough MaterialPropertyBlock from sprite renderer
		MaterialPropertyBlock getBlock = new MaterialPropertyBlock ();
		rend.GetPropertyBlock (getBlock);
		return (Texture2D)getBlock.GetTexture (MAIN_TEXTURE);
	}
}

If anyone happens to run into this problem and stumbles upon this answer, I hope I could help.
Goodbye and happy coding!