- Home /
Help Shader: Texture mask using sliced mask and tiled texture.
Sorry the title might be confusing .... I'll try to be more clear.
So I got, on the right, a sliced texture which is the black outline representing a button or a panel ... whatever.
I want the tiled texture to fill the inside of the button and remove the extras (top left corner / bottom right corner)
So I thought .... let's do a shader.
The image on the right is what I got so far. I got a mask applied to every tiles ....
so My question is ... How can I get that mask to be applied once to remove only 2 cornes of the whole image instead of removing every corners of every tiles?
here is my shader so far :
Shader "UI/TextureMask"
{
Properties
{
_MainTex("Albedo (RGB)", 2D) = "white" {}
_OpacityTex("Opacity (A)", 2D) = "white" {}
}
SubShader
{
Tags{ "Queue" = "transparent" "RenderType" = "transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Lighting Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _OpacityTex;
uniform float4 _MainTex_ST;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
// Texture offset - GOOD
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
half4 frag(v2f i) : COLOR
{
fixed4 c = tex2D(_MainTex, i.uv);
half opacity = tex2D(_OpacityTex, i.uv).a;
if (opacity == 0)
{
c.a = c.a;
}
else
{
c.a = 0;
}
return c;
}
ENDCG
}
}
}
I have a feeling this is because I'm using the tiled Texture's uvs instead of the border's uv.. but I'm not too sure how to achieve that.
Any help is welcome.
Thanks
Vince
Update ---
here are the textures I'm currently using.
By the way, if there is a way to do it WITHOUT shaders, I'm totally open as well.
I would suggest using a GUI texture, you are over complicating it :) Sorry if this is in the answer section I keep trying to do it as a reply.
@jmgek, thanks for your reply. I figured there must be some other way to do this. GUITexture? isn't that deprecated? Unless you mean the new UI Image?
Would you $$anonymous$$d giving me more details? Are you suggesting editing the texture data manually using GetPixel and SetPixel through script???
Answer by helarts · Nov 06, 2015 at 02:54 PM
The problem is that you use the same uvs for both textures, not tested but it should work (some details as comments in the code):
Shader "UI/TextureMask"
{
Properties
{
_MainTex("Albedo (RGB)", 2D) = "white" {}
_OpacityTex("Opacity (A)", 2D) = "white" {}
}
SubShader
{
Tags{ "Queue" = "transparent" "RenderType" = "transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Lighting Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _OpacityTex;
uniform float4 _MainTex_ST;
// Needed by TRANSFORM_TEX
uniform float4 _OpacityTex_ST;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
// "declare" a new set of uvs will be passed from the vertex to the fragment shader
float2 uvOpacityTex : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
// Texture offset - GOOD
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
// "bind" your new uvs with the OpacityTex tile and offset properties you can find in the material
o.uvOpacityTex = TRANSFORM_TEX(v.texcoord, _OpacityTex);
return o;
}
half4 frag(v2f i) : COLOR
{
fixed4 c = tex2D(_MainTex, i.uv);
// Use your OpacityTex uvs to map the texture
half opacity = tex2D(_OpacityTex, i.uvOpacityTex).a;
// sorry but this seems to be garbage
// if (opacity == 0)
// {
// c.a = c.a;
// }
// else
// {
// c.a = 0;
// }
// multiply _MainTex and _OpacityTex alpha
c.a *= opacity;
return c;
}
ENDCG
}
}
}
Edit: I think you'll have to invert the alpha of your OpacityTex or change
c.a *= opacity;
by:
c.a *= 1-opacity;
I get the same result as my own implementation. Lol yeah that opacity condition was garbage.. trying stuff.
I think this is too complicated to do... The mask needs to be sliced just like the border button.
$$anonymous$$aybe I'm doing this wrong too. I got 3 textures ... Border, filling and $$anonymous$$ask. Border and mask are 9-slice texture and filling is tileable.
the way it's setup in the editor is : I got a Gameobject which has a button component. It uses the border image set to sliced mode. then I added another image as a child of the button which has the material using this shader with the filling and the mask.
So basically, the mask has no way to know the size of the sliced border ...I think that's my problem here,..
Sorry I am not really a UI guy but if I understand well your mask texture is called _OpacityTex in the shader, right ? Then you should be able to slice your tileable texture like you want with the alpha of _OpacityTex. What I get:
http://helarts.com/stock/unityforum/screenshot1.jpg
with these textures:
http://helarts.com/stock/unityforum/tileablesquare.tga
http://helarts.com/stock/unityforum/mask.tga
PS: be sure you don't have 2 shaders with the same name ( Shader "UI/Texture$$anonymous$$ask" )
Dammit dude... I think I'll have to ask you how you set it up to get that result .. It just won't behave properly...
Are you using an image? You set the source image with the mask.tga then set the shader with the TileableSquare and it's mask?
I hope it helps: http://helarts.com/stock/unityforum/UIslicedTileable.jpg
Ok I got it working in a new project ... that's weird.. But it doesn't fullfill all my wishes unfortunately....
Ur example is scaling the image if I make the button bigger. what I want is to be able to use the "Sliced" mode. Like keep the angled border the same and scale the center parts... like the image at the top.
That's the biggest issue I think
ahhhhhh $$anonymous$$an! Thanks ! That's clever!! I was building a texture containing the grid itself.. ins$$anonymous$$d of just creating it from plain texture.
thanks alot!
The top image is sliced vs the shader ... I want these angles to be the same no matter what size I use.