Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
2
Question by Alexander283 · Jul 24, 2016 at 08:42 AM · animationshaderspriterenderermaterialpropertyblock

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: Many white squares Less white squares

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.

screenshot-45.png (103.1 kB)
screenshot-46.png (103.7 kB)
Comment
Add comment
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

1 Reply

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

Answer by Alexander283 · Jul 25, 2016 at 06:00 AM

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 :)

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!

Comment
Add comment · Show 1 · 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 LouisHong · Jul 14, 2017 at 07:31 AM 0
Share

Thank you for posting the solution

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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Change the color of a black sprite?,How can i change the color of a black sprite? 1 Answer

Does SetPropertyBlock work with new 2D SpriteRenderer? 1 Answer

Sprite Renderer Interaction Between Two Sprite Masks? 0 Answers

Changing Shaders HDR Color results in different Color. 1 Answer

Creating a fill animation for sprite renderer 0 Answers


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