- Home /
Treating an animated sprite as a mask?
I would like to make an animated sprite which serves as a kind of portal, allowing you to view into another world. However, because it's going to be a character, it also needs to be able to interact with other objects.
Here's an example of what I mean.
Ignoring the awful MSPaint art, in this example, moving the character would result in the stripes shifting as he walks.
This would be pretty easy to achieve in something like flash, but from everything I've seen in Unity for masking, it seems it would be rather complex to do in Unity. Does anyone have any idea how I'd go about it? Is there away it could be achieved using transparency with a solid outline for the character?
I'm pretty sure there is a way, one I'd try would involve using an alpha'd PNG for the character and another texture for the background, and play with the UV's or tiling offsets, but since I have no solid answer, I'll leave that for someone else.
Answer by Jessy · Apr 05, 2011 at 05:34 PM
Use two cameras. The one with the higher depth value needs to use the Depth Only clear mode, which only overwrites color where meshes it sees have materials that render color data. Make sure that the lower-depth camera doesn't render the layer that your character is on.
With this shader, we'll render into the depth buffer only, which, because it renders first (Background queue), will show whatever the lower-depth camera renders, as long as no other meshes are closer to the camera. You will need to create an RGBA texture, where the alpha channel is white where your character's body is, and black everywhere else:
Shader "Alpha Test Depth Mask" {
Properties { _MainTex ("Texture", 2D) = "" }
Category { Tags {Queue = Background} ColorMask 0
SubShader {Pass {
GLSLPROGRAM
varying lowp vec2 uv;
#ifdef VERTEX
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
uv = gl_MultiTexCoord0.xy;
}
#endif
#ifdef FRAGMENT
uniform lowp sampler2D _MainTex;
void main() {
if (texture2D(_MainTex, uv).a < .5) discard;
}
#endif
ENDGLSL
}}
SubShader {Pass {
AlphaTest Greater 0.5
SetTexture[_MainTex]
}}
}
}
So there's the first step, creating a "hole" into the other "world". Next, you want a black outline. Black is easy, because it means we don't need any contribution of the character's texture. This is handy, because we can store the blending data in RGB, instead of A; A was already used, so the only choice is to use at least one other channel for blending data (if we want to keep this whole thing nice and compact in a single texture). Using all three is fine, and should lead to optimal compression:
Long story short, paint a black outline on a white background, in RGB (like you showed above).
Shader "Black Sprite Outline" {
Properties { _MainTex ("Texture", 2D) = "" }
Category { Tags {Queue = Transparent} ZWrite Off Blend Zero SrcColor
SubShader {Pass {
GLSLPROGRAM
varying lowp vec2 uv;
#ifdef VERTEX
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
uv = gl_MultiTexCoord0.xy;
}
#endif
#ifdef FRAGMENT
uniform lowp sampler2D _MainTex;
void main() {
gl_FragColor = texture2D(_MainTex, uv);
}
#endif
ENDGLSL
}}
SubShader {Pass {
SetTexture[_MainTex]
}}
}
}
It will look best if the "body" in the Alpha channel is bigger than the inner white negative space of the RGB outline. The black outline should be soft, and cover up the jagged aliased edges from the alpha test in the other shader. Unfortunately, you can't use two different queues, in a shader, so you're going to have to use two materials on the same mesh. (If we didn't put the outline in a late-queue shader, like Transparent, things would get really weird.)
This is an amazing response, I'll get right on it, thanks!
This is my first time experimenting with shaders and the likes, so it might take me a while, but I'm looking forward to the results!
BTW, just to double check, this will work fine on the free version of unity right? I've had a fair few things not work due to them requiring pro features lately, and it's making me paranoid.
If it doesn't work for you with a free license, then it's a bug. (It's working for me, but I have seen some oddities under DirectX with Color$$anonymous$$asking.)
http://unity3d.com/support/documentation/Components/class-$$anonymous$$eshRenderer.html
The background needs to render first, so the camera that renders it has to be of a lower depth. Just think of it like Photoshop layers; that's exactly what I did when I came up with the solution.
Your answer
Follow this Question
Related Questions
What's the best way to animate a transparent image descending over a circular image? 0 Answers
Can I change a SpriteMask sprite in an animation? 0 Answers
Sprite Editor/Pack Atlas Question for 2D Animating 0 Answers
How to do you import Spriter animations into Unity? 1 Answer
Error : Mask does not match hierarchy unity3d / Animation might not correctly 0 Answers