Alright, I'm not very familiar with Shaders but I'll try to explain in details what I'm trying to achieve, why, and what I achieved so far. The background I use NGUI for my Game GUI and one great feature is that it keeps all images from your GUI on the same Atlas. This is good for saving both space and drawcalls I guess. Okay, when using NGUI I use this Unlit Transparent Colored Shader, which let me pick a color and multiply with my texture, this is great when I have a white sprite and want to change it's color. Here is the Shader Code (I hope there's no problem sharing it here as it's the base for my other shader): Code (csharp): Shader "Unlit/Transparent Colored" { Properties { _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {} } SubShader { LOD 100 Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Pass { Cull Off Lighting Off ZWrite Off Fog { Mode Off } Offset -1, -1 ColorMask RGB AlphaTest Greater .01 Blend SrcAlpha OneMinusSrcAlpha ColorMaterial AmbientAndDiffuse SetTexture [_MainTex] { Combine Texture * Primary } } } } The goal What I want to achieve is to have a monochromatic GUI that can change color based on the color I pick. In other words, I want to achieve a effect similar to the Overlay Blend Mode on Photoshop. Quoted from: http://www.photoshopessentials.com/photo-editing/layer-blend-modes/overlay/ Using Images to explain that would be that the gray button bellow would change its color as I picked blue(0, 0, 255) or red(192,43,43). What's achieved so far? By changing the shader above (and I had no Idea what I was doing) I could achieve a similar effect, that works quite well. Just change the previous shader Pass so it looks like this: Code (csharp): Pass { Cull Off Lighting Off ZWrite Off Fog { Mode Off } Offset -1, -1 ColorMask RGB AlphaTest Greater .01 Blend SrcAlpha OneMinusSrcAlpha ColorMaterial AmbientAndDiffuse SetTexture [_MainTex] { Combine Texture +- Primary, Texture * Primary } SetTexture [_MainTex] { Combine Texture +- previous, Texture * Primary } } The problem This shader works pretty well when I have grayscale buttons, the 50% gray looks about the color I pick and the "shadows and lights" seem to adjust well to the selected color. But when I put a colored sprite with this shader... well... I excpected that by selecting the 50% gray as my pick color everything should remain unchanged compared to the original sprite, but that's not what happen. Check the results bellow: Original / 50% gray picked Because of that weird effect I had separate all my grayscale and colored sprites into 2 atlases, which causes me a lot of trouble with rendring order. The Request Can anyone help me achieve what I want with the right code so I could use the same atlas for colored and grayscale sprites? I mean, because obviously my Pass is not doing the Overlay Blend Mode right, it's just something similar. The Thanks Thanks in advance, specially if you had patience to read this big post. I hope everything is well explained.
I have found some more info about the Overlay Formula, as I quoted before it combines Multiply with Screen blend modes. Wikipedia: http://en.wikipedia.org/wiki/Blend_modes StackOverflow: http://stackoverflow.com/questions/5825149/overlay-blend-mode-formula It seems I'll need an IF statement based on the texture pixel color... is there a code to check that in the SetTexture of a shader so I could chose between Screen and Multiply? Also, how can I use Screen Blend Mode? Multiply seems to be as easy as Code (csharp): Combine Texture * Primary
If I understand correctly, you want what is described in this thread. Here are all those bits of code put together: Code (csharp): Shader "Custom/OverlayBlend" { Properties { _MainTex ("Texture", 2D) = "" {} _Color ("Blend Color", Color) = (0.2, 0.3, 1 ,1) } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } Lighting Off Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Fog { Mode Off } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; }; sampler2D _MainTex; uniform float4 _MainTex_ST; uniform float4 _Color; v2f vert (appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.color = v.color; o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); return o; } fixed4 frag (v2f i) : COLOR { // Get the raw texture value float4 texColor = tex2D(_MainTex, i.texcoord); // Calculate the twiceLuminance of the texture color float twiceLuminance = dot(texColor, fixed4(0.2126, 0.7152, 0.0722, 0)) * 2; // Declare the output structure fixed4 output = 0; // The actual Overlay/High Light method is based on the shader if (twiceLuminance < 1) { output = lerp(fixed4(0, 0, 0, 0), _Color, twiceLuminance); } else { output = lerp(_Color, fixed4(1, 1, 1, 1), twiceLuminance - 1); } // The alpha can actually just be a simple blend of the two- // makes things nicely controllable in both texture and color output.a = texColor.a * _Color.a; return output; } ENDCG } } Fallback off }
No Daniel, it didn't work, I guess the problem described in that thread is not exactly the same as what I want here. I'm still trying to find the right shader, maybe I'll have to use some CG code for that, right?
You'll definitely have to use Cg. Perhaps you can explain in more detail what you would like your possible inputs to be, and what output you expect in each case? I can't view any of your original attachments except the twitter logo.
Sorry for that, I updated the post with new images so I hope it works now. In adition now that I studied NGUI a little more I discovered what its color pick does, it does pixel coloring on the plane where the sprite is going to be rendered with the selected color. So basically the code I want is: Code (csharp): foreach texture pixel { if (texture.pixel is darker than 0.5) { finalPixelColor = baseColor MULTIPLY texture.pixel.color } else { finalPixelColor = baseColor SCREEN texture.pixel.color } } Sorry, I'm not familiar with CG script...
Still looking for a solution without success, can someone take a look on this or give me directions on what to study?
Had a need for overlay a while back. However i made the mistake of trying to do the overlay on each channel RGB separately, didn't think to use luminescence for it. Anyway with that in mind, made a few changes to it and came up with something that seems to work. However not tested on any mobile device, I've read that using if tests on shaders isn't the best idea, and there may well be better ways to approximate the effect with less cost. Either way, here's what i came up with for it. Note: Not really knowing about luminescence at all not sure what the best value is for checking it. I found checking it < 1 looked a little bit off, checking <0 might also be useful (but without opening photoshop i cant compare the effect exactly) but 0.5 seems to give a decent effect as far as my memory of what an overlay does. However you may want to modify the value you check luminescence against if you want to fine tune. Code (csharp): Shader "Custom/OverlayBlend" { Properties { _MainTex ("Texture", 2D) = "" {} _Color ("Blend Color", Color) = (0.5, 0.5, 0.5, 1.0) } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } Lighting Off Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" struct appdata_custom { float4 vertex : POSITION; fixed2 uv : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; fixed2 uv : TEXCOORD0; }; sampler2D _MainTex; fixed4 _MainTex_ST; fixed4 _Color; v2f vert (appdata_custom v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.uv,_MainTex); return o; } fixed4 frag (v2f i) : COLOR { fixed4 diffuse = tex2D(_MainTex, i.uv); fixed luminance = dot(diffuse, fixed4(0.2126, 0.7152, 0.0722, 0)); fixed oldAlpha = diffuse.a; if (luminance < 0.5) diffuse *= 2 * _Color; else diffuse = 1-2*(1-diffuse)*(1-_Color); diffuse.a = oldAlpha * _Color.a; return diffuse; } ENDCG } } Fallback off }
Thanks a lot, this shader is almost what I need, I just need to know 2 things: 1. Could you tell if it is going to run on mobile devices? If yes is it optimized enough for that? 2. How can I use the mesh vertex color instead of the variable _Color of the shader?
Okay, with very few modifications I got it to work exactly like I wanted. Very special thanks to HenryStrattonFW. Code (csharp): Shader "Custom/OverlayBlend" { Properties { _MainTex ("Texture", 2D) = "" {} } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } Lighting Off Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" struct appdata_custom { float4 vertex : POSITION; fixed2 uv : TEXCOORD0; float4 color : COLOR; }; struct v2f { float4 vertex : POSITION; fixed2 uv : TEXCOORD0; float4 color : COLOR; }; sampler2D _MainTex; fixed4 _MainTex_ST; v2f vert (appdata_custom v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.uv,_MainTex); o.color = v.color; return o; } fixed4 frag (v2f i) : COLOR { fixed4 diffuse = tex2D(_MainTex, i.uv); fixed luminance = dot(diffuse, fixed4(0.2126, 0.7152, 0.0722, 0)); fixed oldAlpha = diffuse.a; if (luminance < 0.5) diffuse *= 2 * i.color; else diffuse = 1-2*(1-diffuse)*(1-i.color); diffuse.a = oldAlpha * i.color.a; return diffuse; } ENDCG } } Fallback off }
Hi. I've just had to implement a overlay shader my self and came across this thread when I was looking for inspiration. Cool you got what you wanted Lax! But even though you aren't looking any more I think I'll post my solution as it might be helpful for others trying to do the same. My shader is more like the overlay mode in photoshop as it operates on the whole screen area. The algorithm is a direct implementation of the algorithm described on the wikipedia page you linked to in an earlier post. (http://en.wikipedia.org/wiki/Blend_modes#Overlay) Anyway here goes (some explanation can be found after the code): Code (csharp): Shader "Custom/Overlay" { Properties { _OverlayTex ("Overlay (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent+1000"} LOD 200 GrabPass {} Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _GrabTexture; sampler2D _OverlayTex; struct appdata_t { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 projPos : TEXCOORD1; }; float4 _OverlayTex_ST; v2f vert( appdata_t v ){ v2f o; o.vertex = mul( UNITY_MATRIX_MVP, v.vertex ); o.uv = TRANSFORM_TEX( v.texcoord, _OverlayTex ); o.projPos = ComputeScreenPos( o.vertex ); return o; } half4 frag( v2f i ) : COLOR { i.projPos /= i.projPos.w; half4 base = tex2D( _GrabTexture, float2( i.projPos.xy )); half4 overlay = tex2D( _OverlayTex, i.uv ); return lerp( 1 - 2 * (1 - base) * (1 - overlay), 2 * base * overlay, step( base, 0.5 )); } ENDCG } } } As it can be seen above I use a pass to grab what is currently on the screen before rendering the overlay. This is a feature provided by Unity simply by including the GrabPass { } and it stores a reference to the grabbed texture in _GrabTexture. I can now use this as my base layer for the blend and I use normalized screen coordinates as uv's when reading from it (that is what the "o.projPos = ComputeScreenPos( o.vertex ); " and "i.projPos /= i.projPos.w;" lines are for). Finally I combine the two texture colors basted on the algorithm from the wikipedia page. The lerp and step functions is just another way of doing an if statement, This is hopefully less cost expensive than an actual if ( I'm by no means a shader expert! ) I've also made a shorter version implemented as a surface shader. But it is probably not that useful since it reacts to lighting. (In my experience the color of the pixel is alway change at least a little when using surface shaders. Even though you define your own lighting model that ignores light! ) Anyway, that's it. Hope somebody finds this help full. Cheers - Jakob
Yeah Jakob , liking the magic of your implementation of the overlay logic in a simple lerp... Wish I could find similar implementations of this set: http://forum.unity3d.com/threads/121661-Free-Photoshop-Blends - or some idea how you go from those if statements to what you produced. Either way, thanks for sharing!
I used a plane and put it between the camera and the scene with this shader. the color looks right but it renders the scene upside down edit: nvm, my screen coordinate in unity is reversed that's why the output is upside down.
Whoa, nice to see this post is still going on. I'll check that implementation later on on my project as it seems to be a bit more efficient.
Been a long time since I saw this thread, nice to see some alternative suggestions. @Ball-E 's use a lerp and steps is a good way around the if test. Will have to remember that next time I need to dig up my old overlay shader.
Hi, With unity5 the original shader in this thread is no longer usable. I tried this from Lex But I need the extra saturation from the original shader. this is the original shader: Code (CSharp): Shader "Unlit/Transparent Colored" { Properties { _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {} } SubShader { LOD 100 Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Pass { Cull Off Lighting Off ZWrite Off Fog { Mode Off } Offset -1, -1 ColorMask RGB AlphaTest Greater .01 Blend SrcAlpha OneMinusSrcAlpha ColorMaterial AmbientAndDiffuse SetTexture [_MainTex] { Combine Texture +- Primary, Texture * Primary } SetTexture [_MainTex] { Combine Texture +- previous, Texture * Primary } } } } How can I achieve the same effect in unity5? Thank you
So, as Spiral12 correctly stated, almost none of this works with unity 5 anymore. Ball-E's last offer was the closest thing I got to a working shader, and after minor adjustments I got it to work in a GUI context. The transparent shaders in the custom overlay image were still rendered and affecting the image, though. The shader has therefore been modified to take transparency into account so custom images are correctly blended in, as well as introduced a property which allows you to modify the strength of the overall layer. The last thing missing (to follow the photoshop effect) would be to make sure that overlays with a light intensity of 0.5 are rendered transparent, right now it just defaults to screen. Code (CSharp): Shader "Custom/Overlay" { Properties{ _MainTex("Texture", 2D) = "" {} _str("Overlay Strength", Float) = 0.45 } SubShader{ Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } GrabPass{} Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _GrabTexture; sampler2D _MainTex; float _str; struct appdata_t { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 projPos : TEXCOORD1; }; float4 _MainTex_ST; v2f vert(appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.projPos = ComputeScreenPos(o.vertex); return o; } half4 frag(v2f i) : COLOR{ i.projPos /= i.projPos.w; half4 base = tex2D(_GrabTexture, float2(i.projPos.x, 1-i.projPos.y)); half gray = (base.r + base.g + base.b) / 3; half4 overlay = tex2D(_MainTex, i.uv); float4 effect = lerp(1 - (2 * (1 - base)) * (1 - overlay), (2 * base) * overlay, step(gray, 0.5f)); return lerp(base, effect, (overlay.w * _str)); } ENDCG } } }
I made a little change at line 51. step(gray, 0.5f) -> step(base, 0.5f) No idea what I've done but it looks exactly same as PS. Code (CSharp): Shader "Custom/Overlay" { Properties{ _MainTex("Texture", 2D) = "" {} _str("Overlay Strength", Float) = 0.45 } SubShader{ Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } GrabPass{} Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _GrabTexture; sampler2D _MainTex; float _str; struct appdata_t { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 projPos : TEXCOORD1; }; float4 _MainTex_ST; v2f vert(appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.projPos = ComputeScreenPos(o.vertex); return o; } half4 frag(v2f i) : COLOR{ i.projPos /= i.projPos.w; half4 base = tex2D(_GrabTexture, float2(i.projPos.x, 1-i.projPos.y)); half gray = (base.r + base.g + base.b) / 3; half4 overlay = tex2D(_MainTex, i.uv); float4 effect = lerp(1 - (2 * (1 - base)) * (1 - overlay), (2 * base) * overlay, step(base, 0.5f)); return lerp(base, effect, (overlay.w * _str)); } ENDCG } } }
It must be a noob question, but I have the same issue about it rendering upside down, how do you reversed the coordinates in the shader? If I play the scene on PC it renders the right way, but on mobile (and in the "Scene View") it renders upside down. I know it is because de coordinates are handled different between platforms, but like I've said I'm a shader noob, I down't know how make it render correctly in different platforms.
Okay @FoxQ, I don't know why you would do that. I use gray so that the overall light level of the 3 color channels is used. I do not know if unity automatically assumes this with your method. I am specifically worried about your method also accounting for transparency, which I do not want in my case. And you are right @olopez1 sorry for taking so long, I've had the solution lying around for some time. The problem is indeed platform specific, and you rectify this by replacing line 47 with the following: #if SHADER_API_METAL || SHADER_API_D3D11 half4 base = tex2D(_GrabTexture, float2(i.projPos.x, 1-i.projPos.y)); #else half4 base = tex2D(_GrabTexture, float2(i.projPos.x, i.projPos.y)); #endif This will make the shader mess up in the scene-view and hopefully nowhere else.
Hi guys! Edit: I made a more simplified version, but by now it only works in the editor Basically, what I'm doing is just a substraction and an addition: half4 base = tex2D(_GrabTexture, float2(i.projPos.x, 1 - i.projPos.y)); half4 overlay = tex2D(_MainTex, i.uv); half4 mixer = half4 (0.5, 0.5, 0.5, 0.5); return base+overlay-mixer; Here is all the code. Regards Code (CSharp): Shader "Custom/Overlay" { Properties{ _MainTex("Texture", 2D) = "" {} } SubShader{ Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } GrabPass{} Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _GrabTexture; sampler2D _MainTex; struct appdata_t { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 projPos : TEXCOORD1; }; float4 _MainTex_ST; v2f vert(appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.projPos = ComputeScreenPos(o.vertex); return o; } half4 frag(v2f i) : COLOR{ i.projPos /= i.projPos.w; half4 base = tex2D(_GrabTexture, float2(i.projPos.x, 1 - i.projPos.y)); half4 overlay = tex2D(_MainTex, i.uv); half4 mixer = half4 (0.5, 0.5, 0.5, 0.5); return base+overlay-mixer; } ENDCG } } }
Can't you just use: Blend DstColor SrcColor // 2x Multiplicative Which doesn't use a grab pass. Then 0.5 output values are no change, above that is lighten, below is darken. This is what we use to do with multi-pass detail textures, back in the day.
I'm doing an x-ray shader, I got this code, but for what I want it's incomplete. Here's the shader website: http://www.photonworkshop.com/index.php/blog/x-ray-shader/ My knowledge in shader is pretty basic, I'm studying weeks in Unity documentation and in various tutorials, but nothing comes close to what I need. I need to make if one object is on top of the other the color turns green, in addition to having a density control of the material that makes it darker or lighter, and the same with the color intersected. And to finish the possibility of putting a texture in black and white and have an individual control the internal with these same characteristics. If you can help me, thank you. I tried via C # to change the color, but there remained a wagon hehehehhehehe. This is what I have. This is what I want to do. I tried to merge the idea of the overlay shader, but it did not work like I did. This was the idea on the internet closest to the control I want. I needed to know how to get pixel rendering from the scene and compare with conditionals, or if you think of something better with merges give me a touch. Thank you.
Shader "Unlit/Overlay" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent"} Zwrite off LOD 100 Pass { Blend SrcAlpha One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" fixed getAddValue(fixed value){ fixed v = value; if(v<0.5)v=0.5; return 2*(v-0.5); } struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex;float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 texCol = tex2D(_MainTex, i.uv); fixed4 col = fixed4(getAddValue(texCol.r),getAddValue(texCol.g),getAddValue(texCol.b),getAddValue(texCol.a)); return col; } ENDCG } Pass { Blend DstColor Zero CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" fixed getAddValue(fixed value){ fixed v = value; if(v>0.5)v=0.5; return 2*v; } struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex;float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 texCol = tex2D(_MainTex, i.uv); fixed4 col = fixed4(getAddValue(texCol.r),getAddValue(texCol.g),getAddValue(texCol.b),getAddValue(texCol.a)); return col; } ENDCG } } }