- Home /
Access UI Image Color in Shader
Hi folks,
I'm trying to write a shader for UI Image component and I wonder how to access the "Color" property specified in it:
I know I can declare a Material Property, but then I'd have to create a material per each color variation, and the Image.color
property will obviously have no effect. They clearly achieve that with some kind of uniform
injected by Unity, but I can't figure what it is (Frame Debugger doesn't show it either :/)
Appreciate any help!
Answer by FunRobDev · Apr 12, 2018 at 01:47 PM
@BorisOkunskiy Hi guys,
I investigated the source code of UI/Image and UI/RawImage, and found out that both Image and RawImage puts its Color value into the vertex info in their OnPopulateMesh(VertexHelper vh). See RawImage.cs
After that I wrote this simple shader of Colorize, which uses the Image's or RawImage's color, in the code see line 69 which uses "i.color":
Shader "Colorize"
{
Properties
{
_MainTex("_MainTex", 2D) = "white" {} // Note _MainTex is a special name: This can also be accessed from C# via mainTexture property.
Colorize("Colorize", Range(0.0, 1.0)) = 1
}
SubShader
{
Pass
{
Name "ColorizeSubshader"
// ---
// For Alpha transparency: https://docs.unity3d.com/462/Documentation/Manual/SL-SubshaderTags.html
Tags
{
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha
// ---
CGPROGRAM
#pragma vertex MyVertexShaderFunction
#pragma fragment MyFragmentShaderFunction
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
float Colorize;
//fixed4 _Color0;
// http://wiki.unity3d.com/index.php/Shader_Code :
// There are some pre-defined structs e.g.: v2f_img, appdata_base, appdata_tan, appdata_full, v2f_vertex_lit
//
// but if you want to create a custom struct, then the see Acceptable Field types and names at http://wiki.unity3d.com/index.php/Shader_Code
// my custom struct recieving data from unity
struct my_needed_data_from_unity
{
float4 vertex : POSITION; // The vertex position in model space. // Name&type must be the same!
float4 texcoord : TEXCOORD0; // The first UV coordinate. // Name&type must be the same!
float4 color : COLOR; // The color value of this vertex specifically. // Name&type must be the same!
};
// my custom Vertex to Fragment struct
struct my_v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
my_v2f MyVertexShaderFunction(my_needed_data_from_unity v)
{
my_v2f result;
result.pos = UnityObjectToClipPos(v.vertex); // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
result.uv = v.texcoord.xy;
result.color = v.color;
return result;
}
float4 MyFragmentShaderFunction(my_v2f i) : COLOR
{
float4 texcolor = tex2D(_MainTex, i.uv); // texture's pixel color
float4 vertexcolor = i.color; // this is coming from UnityEngine.UI.Image.Color
texcolor.rgb = texcolor.rgb * (1 - Colorize) + vertexcolor.rgb * Colorize;
return texcolor;
}
ENDCG
}
}
//Fallback "Diffuse"
}
The custom structs "my_needed_data_from_unity" and "my_v2f" are needed, you can't solve it without them, and the field names and types in the my_needed_data_from_unity must be exactly the same to recieve data from Unity. Where can you find these field names and types? Here: Unity Wiki Shader Code
Another good page: Providing vertex data to vertex programs Also thanks to CHPedersen's post.
God Bless
Answer by Grish_tad · Dec 11, 2017 at 08:34 PM
You can use material.SetColor("_Color", color_value). "_Color"-is color parameter in shader. For more see here https://docs.unity3d.com/ScriptReference/Material.SetColor.html,
Thank you! Sure, that'll work. However, with this approach material is always copied, which prevents batch-rendering (but if you inspect UI.Image with default shader, multiple copies sharing same texture but different colors are actually rendered in batches).
What I'm interested in is: is there some intrinsic way of accessing UI.Image's color
property from within the shader? I mean, the default UI shader somehow knows this color, right? So I was wondering if custom shader can access it, too? Otherwise, yeah, will have to stick to a custom script which feeds image's color to shader (and even then, understanding the actual behind "No" would be great).
Your answer
