How do I make a texture turn greyscael?

So I've tried :

myImageObject.renderer.material.color=Color.black;

but that just makes my texture black. I imagine I want to change the materials shader but is there a shader that just renders in greyscale? If so what's it called and where can I get it?

I don't know if a grayscale shader is included w/ Unity, but this should be pretty easy with a custom shader. Create a new shader, then double-click it to open it in the editor. It might look like this:

Shader "GrayscaleLol" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = (c.r + c.g + c.b)/3;
            o.Alpha = c.a;
        }
        ENDCG
    } 
    FallBack "Diffuse"
}

The only change from the default shader is

o.Albedo = c.rgb; 

becomes

o.Albedo = (c.r + c.g + c.b)/3;

EDIT: In response to comment, transparent grayscale

Shader "GrayscaleLolTransparent" {
    Properties {
        _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    }

    SubShader {
        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert alpha

            sampler2D _MainTex;

            struct Input {
                float2 uv_MainTex;
            };

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = dot(c.rgb, float3(0.3, 0.59, 0.11));
                o.Alpha = c.a;
            }

        ENDCG
    }

    Fallback "Transparent/VertexLit"
}

Depending on what you're doing, you might prefer to make the actual texture grayscale:

function Start () {
    var texClone = Instantiate (renderer.material.mainTexture);
    renderer.material.mainTexture = texClone;
    MakeGrayscale (texClone);
}

function MakeGrayscale (tex : Texture2D) {
    var texColors = tex.GetPixels();
    for (i = 0; i < texColors.Length; i++) {
        var grayValue = texColors*.grayscale;*
 <em>texColors _= Color(grayValue, grayValue, grayValue, texColors*.a);*_</em>
 <em>_*}*_</em>
 <em>_*tex.SetPixels(texColors);*_</em>
 <em>_*tex.Apply();*_</em>
<em>_*}*_</em>
<em>_*```*_</em>
<em>_*<p>However that will probably use more memory, since the texture has to be marked readable, and be RGB24 or ARGB32.  On the other hand it will work on anything and not need a pixel shader.</p>*_</em>

I’m going to add a little tip since this thread has helped me get by. I’ve extended this code to let you vary the greyscale amount.

Add:

    _EffectAmount ("Effect Amount", Range (0, 1)) = 1.0

to the Properties list.

Add:

    uniform float _EffectAmount;

right below “sampler2D _MainTex;”

Finally, change

    o.Albedo = dot(c.rgb, float3(0.3, 0.59, 0.11));

to

    o.Albedo = lerp(c.rgb, dot(c.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);

This will result in a little slider on the shader options which you can drag to modify it. However, the real prize from this is that it allows you to script the effect amount. To set it, you can simply call this on the game object you’re drawing:

    GAMEOBJECT.renderer.material.SetFloat('_EffectAmount', AMOUNT_OF_GREYSCALE);

If you want it to animate this greyscale fade, you can use a coroutine. I’ll leave that part as an exercise for the reader.

This forum post has a great Sprite shader that has a greyscale parameter, in case anyone is looking.

Shader "Sprites/GrayScale"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
        _EffectAmount ("Effect Amount", Range (0, 1)) = 1.0
    }
 
    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }
 
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Blend SrcAlpha OneMinusSrcAlpha
 
        Pass
        {
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile DUMMY PIXELSNAP_ON
            #include "UnityCG.cginc"
           
            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
            };
 
            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                half2 texcoord  : TEXCOORD0;
            };
           
            fixed4 _Color;
 
            v2f vert(appdata_t IN)
            {
                v2f OUT;
                OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                OUT.texcoord = IN.texcoord;
                OUT.color = IN.color * _Color;
                #ifdef PIXELSNAP_ON
                OUT.vertex = UnityPixelSnap (OUT.vertex);
                #endif
 
                return OUT;
            }
 
            sampler2D _MainTex;
            uniform float _EffectAmount;
 
            fixed4 frag(v2f IN) : COLOR
            {
                half4 texcol = tex2D (_MainTex, IN.texcoord);              
                texcol.rgb = lerp(texcol.rgb, dot(texcol.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);
                texcol = texcol * IN.color;
                return texcol;
            }
        ENDCG
        }
    }
    Fallback "Sprites/Default"
}

My 2 cents…

  • You make the shader file, in my case called MyShader_GUI_Desaturated.shader
  • Make a material, in my case called gui_desaturated_material and select the shader for it.
  • Make the shader texture be a small white square. We have a 16x16 pixel white texture.
  • In your code for the GUI draw instead of GUI.DrawTexture, use Graphics.DrawTexture and use the material.

Here are the complete code pieces…

    Shader "MyShaders/GUI_Desaturated" {
        Properties {
            _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    		_EffectAmount ("Effect Amount", Range (0, 1)) = 1.0
        }
     
        SubShader {
            Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
            LOD 200
     
            CGPROGRAM
            #pragma surface surf Lambert alpha
     
                sampler2D _MainTex;
    			uniform float _EffectAmount;
     
                struct Input {
                    float2 uv_MainTex;
                };
     
                void surf (Input IN, inout SurfaceOutput o) {
                    half4 c = tex2D(_MainTex, IN.uv_MainTex);
                    o.Albedo = lerp(c.rgb, dot(c.rgb, float3(0.3, 0.59, 0.11)), _EffectAmount);
                    o.Alpha = c.a;
                 }
     
            ENDCG
        }
     
        Fallback "Transparent/VertexLit"
    }

In the C# component…

	public Material craftingItemMaterial;

And in the OnGUI code. We only draw during the Repaint event.
Note: Unity3D calls OnGUI for events that happen. It is typical that OnGUI gets called twice, first with
a Layout event which is determining all the GUI… calls and their screen position layout, and then
with a Repaint event where the GUI items actually get drawn. You also may get other events in OnGUI like mouse and keyboard events. (That is how GUI and GUILayout get the job done so transparently.)

// Only do the draw on the Repaint event.
if(Event.current.type.Equals(EventType.Repaint))
{
   // The craftingItemMaterial is a MyShaders_GUI_Desaturated shader.
   Graphics.DrawTexture( 
      itemRect, 
      item_icon_texture,
      craftingItemMaterial );
}

Or have two textures (one greyscale) and swap them at runtime, this is what I do when hotkey buttons become unusable.

But how do you actually store/copy this rgb texture to a one channel texture (let says, Alpha8 format) ?

I try to simply read my rgb format to an alpha 8 format like that

textureA.LoadRawTextureData(textureRGB.GetRawTextureData());
textureA.Apply();

That does store 4 time the image one on top of the other.