- Home /
See-through hole via shaders on a 2D plane
Hi!
I need to make a see through hole on a 2D texture using a custom shader. Defined variables are: r (hole radius) x,y (hole position, either by float or vector2) slope (not necessary, but a useful feature to set a alpha slope for our hole)
The way it should work is when a user wants to see through a building in a 2D game, he simply moves his mouse above it and then we change input variables via simple script command (renderer.material.SetFloat( "_Radius", radius);, etc) we make that texture see-through, like the example below:
The building and grass are two separate orth 2d textures.
Is there a way of doing it without using Alpha test or anything expensive like that? (iOS project)
Thanks a lot guys
This type of thing has been asked before, you should try search. Even google.
I believe this is a duplicate question. You can probably get the answer on how to do this here
The example you linked is using Alpha Test (cutoff), which is extremely expensive for iOS devices. I could not find anything to solve my problem that does not use that
Answer by Jessy · May 03, 2013 at 09:48 PM
Whether it's expensive depends on how many pixels you're blending. You haven't specified what orientation your world is in, so the properties here are in UV space. You could do it in world space, in 3D, as a generic solution, but I think it might be faster to only deal with two dimensions.
Shader "Hole Thing" {
Properties {
_Center ("Hole Center", Vector) = (.5, .5, 0 , 0)
_Radius ("Hole Radius", Float) = .25
_Shape ("Hole Shape", Float) = .25
_MainTex ("Main Texture", 2D) = ""
}
SubShader {
Tags {"Queue" = "Transparent"}
Blend SrcAlpha OneMinusSrcAlpha
Pass {
CGPROGRAM
struct appdata {
float4 position : POSITION;
half2 texCoord : TEXCOORD;
};
struct v2f {
float4 position_clip : SV_POSITION;
half2 position_uv : TEXCOORD;
};
#pragma vertex vert
uniform half4 _MainTex_ST;
v2f vert(appdata i) {
v2f o;
o.position_clip = mul(UNITY_MATRIX_MVP, i.position);
o.position_uv = _MainTex_ST.xy * i.texCoord + _MainTex_ST.zw;
return o;
}
#pragma fragment frag
uniform sampler2D _MainTex;
uniform half2 _Center;
half _Radius, _Shape;
fixed4 frag(v2f i) : COLOR {
fixed4 fragColor = tex2D(_MainTex, i.position_uv);
half hole = min(distance(i.position_uv, _Center) / _Radius, 1.);
fragColor.a *= pow(hole, _Shape);
return fragColor;
}
ENDCG
}
}
}
@Jessy saves the day once again. Now using a simple line we can change the position of our hole (orthogonal xy coords): renderer.material.SetVector( "_Center", Vector4(Input.mousePosition.x/1000,Input.mousePosition.y/1000,0,0));
Here's a working example: https://dl.dropboxusercontent.com/u/18351237/Web_pl.html
Thank you very much @Jessy, what an efficient and elegant solution.
@Strab, any chance you can post the project that you linked to above? I'd like to implement this shader in a similar way that you did and am having trouble.
Hello Guys! I m trying to use you solution but in a wall between the player and the camera.
Need two helps my friends: 1° Is there a way to make this shader cast shadow? 2° A raycast from a camera hit the wall...how can i use the hit's coordenates to change the hole offset?
I tried that line insede FixedUpdate:
_hit.collider.gameObject.GetComponent<Renderer>().material.SetVector("_Center", new Vector4(_hit.point.x,_hit.point.y,0,0));
Thanks bros!!!!!!
Answer by whydoidoit · May 03, 2013 at 10:02 PM
@Jessy's got a good shader there, just thought I'd pitch a different option.
Why not just render a cylinder with the DepthMask shader though - that would do it if you could live without the edge fading and is very easy to position at the mouse point, especially if overlapping two different textures.