Hello Guest

Author Topic: Color replacement in animations  (Read 7051 times)

lvictorino

  • Newbie
  • *
  • Posts: 7
    • View Profile
Color replacement in animations
« on: November 13, 2013, 07:21:22 am »
Hi,

I'm trying to do some color replacement for player customization purpose.
I want the player to be able to choose the color of his avatar. Imagine a sprite of a football player, I want to change the shirt color only.
I've been looking at some "green screen" technique, where the initial shirt color would be of a color I don't use (full green, or full pink), and then use Unity3D GetPixels / SetPixels to replace only pixels of this specific color with the one chosen by players.

It works fine with static sprites. But I wonder how to perform such replacement with sprite animation?

Also, if you have any better idea on how to perform such color replacement, please share it :)

Here is the code I use so far :

Code: [Select]
    private void Awake()
    {
        Texture2D tex = Instantiate(renderer.material.mainTexture) as Texture2D; // I guess it's because animator doesn't use mainTexture.
        renderer.material.mainTexture = tex;
        Color search = new Color(1.0f, 0.0f, 1.0f); // looking for pink color
        Color replace = new Color(Random.value, Random.value, Random.value); // changing it by a random color
        for (int y = 0; y < tex.height; ++y)
        {
            for (int x = 0; x < tex.width; ++x)
            {
                if (tex.GetPixel(x, y) == search)
                {
                    tex.SetPixel(x, y, replace);
                }
            }
        }
        tex.Apply();
    }

Thanks for your help

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Color replacement in animations
« Reply #1 on: November 13, 2013, 10:18:24 am »
You can do what you're trying to do there, but you will need to do it after the animator has set the first sprite.
Also, assigning the material will override all instances of the material.

renderer.material will duplicate the material. If you need to change all the instances of that sprite, then simply change sharedMaterial instead of material, but that will change the internal material... One valid alternative is to create a manager that swaps out the material whenever the sprite changes.

Use sprite.SpriteChanged to get a message whenever a sprite changes, and immediately update renderer.sharedMaterial with the replacement material. (I.e. instantiate the material AND the shader) and use that. You can use a global Dictionary for this.

lvictorino

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Color replacement in animations
« Reply #2 on: November 13, 2013, 02:08:34 pm »
Thanks for this quick answer.
If I understand your suggestion about sharedMaterial correctly it means that if I change the pixel value for the shareMaterial.texture it will change the pixel color for EVERY shirt of every player in the game. Am I right ?

As every player should have a different shirt color it's not what I need.

I'll go with this :
Code: [Select]
public class ColorReplace : MonoBehaviour
{
    Texture2D _modified_tex = null;

    private void RandomizeColor()
    {
        Texture2D tex = Instantiate(renderer.material.mainTexture) as Texture2D;
        renderer.material.mainTexture = tex;
        Color search = new Color(1.0f, 0.0f, 1.0f);
        Color replace = new Color(Random.value, Random.value, Random.value);
        Color[] pix = tex.GetPixels();
        for (int y = 0; y < tex.height; ++y)
        {
            for (int x = 0; x < tex.width; ++x)
            {
                if (pix[ y * tex.width + x ] == search)
                {
                    pix[ y * tex.width + x ] = replace;
                }
            }
        }
        tex.SetPixels(pix);
        tex.Apply();
        _modified_tex = tex;
    }

    private void Awake()
    {
        RandomizeColor();
        GetComponent<tk2dBaseSprite>().SpriteChanged += ColorReplace_SpriteChanged;
    }

    void ColorReplace_SpriteChanged(tk2dBaseSprite obj)
    {
        renderer.material.mainTexture = _modified_tex;
    }
}

Then, the pixel change will be compute only once and saved for every player. And as you suggested it I swap the texture every time the animator change the material.
What do you think? Does it look correct to you?

Thanks again for your answer.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Color replacement in animations
« Reply #3 on: November 13, 2013, 02:36:22 pm »
Unity will create a copy of the material every time you call renderer.material - you are likely leaking materials there... You probably want to maintain a list of materials yourself.

something like this:

Code: [Select]
Dictionary<Material, Material> myMaterials = new Dictionary<Material, Material>();
if ( myMaterials.ContainsKey(renderer.sharedMaterial)) {
   renderer.sharedMeaterial = myMaterials[renderer.sharedMaterial];
}
else {
   Material replacementMaterial =Instantiate(renderer.sharedMaterial);
   replacementMaterial.mainTexture = _modified_tex;
  myMaterials[renderer.sharedmaterial] = replacementmaterial;
}

lvictorino

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Color replacement in animations
« Reply #4 on: February 06, 2014, 08:51:03 am »
A question came to me...

Wouldn't be more efficient to do the color replacement via shaders?
Do you think it could be possible / easy to work on shaders while using tk2d?

Thanks,

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Color replacement in animations
« Reply #5 on: February 06, 2014, 09:10:25 am »
Yes, it will work with shaders, but there are many ways to do that, and you will have to consider filtering, etc. Its easier with just point filtering. You can replace the shader on the tk2d generated material no problem.

lvictorino

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Color replacement in animations
« Reply #6 on: February 06, 2014, 09:14:21 am »
Just to be sure... I'll have to modify the current tk2d shader and add what I want to it in order to keep the functionalities... right? (I'm so scared by shaders)

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Color replacement in animations
« Reply #7 on: February 06, 2014, 09:16:51 am »
No, don't modify tk2d shaders, create a new one (duplicate a tk2d shader to start will be fine), then select your atlas material in the sprite collection data folder and apply the shader.