- 編集済み
Animated Mask/Unity (HELP)
Hey, I need help here about Masks and Unity.
I have 2 different animations:
- First one I have some trees moving with the wind.
- Second animation is like a textures moving up.
My idea was to use the first animation as a mask of itself and to put the second animation only playing inside of the trees.
I was following this guide here: http://en.esotericsoftware.com/blog/Unity-SpriteMask-and-RectMask2D-support
The problem is this only work for static masks.
Is there a way to use an animation from spine as Mask itself?
I'm using SkeletonAnimation as component.
(creating mask on spine itself is not option)
Thanks
I'm afraid there is no easy way to have an animated skeleton act as a mask for another skeleton.
Typical solutions would require to render the mask object in front of the to-be-masked object with a shader that either:
a) writes to the stencil buffer (for which you would need a custom shader, Spine shaders do not offer this option), and a second shader at the masked object that performs a stencil-test accordingly.
b) or writes to the depth buffer but not to the color buffer (an "invisible" shader that only blocks other object's pixels from being rendered).
Could you please show a few images that describe what exactly you are trying to achieve? Perhaps this could be done in an easier way that does not require special shaders at all.
Harald wroteCould you please show a few images that describe what exactly you are trying to achieve? Perhaps this could be done in an easier way that does not require special shaders at all.
So on the left I have a static frame of the ice particles and on the right I have one of the tree tops also static.
This is what I'm trying to achieve in detail is explained in this post:
https://answers.unity.com/questions/1848598/using-an-object-as-a-mask-for-another-object-using.html
I got it "half-working" but I can't understand what's wrong now.
In the same post it is included a gif with the behavior.
Thanks for your attention Harald
Unfortunately I currently cannot access Unity Answers (most likely due to this issue on Unity's side, my license is definitely not expired).
If you can still access it and it's not too much of an effort, could you perhaps create some screenshots or copy text of the relevant parts of this Answers page and post it here? Otherwise I'm afraid I will need some more explanation of what you are trying to achieve and what your current problem is.
Harald wroteUnfortunately I currently cannot access Unity Answers (most likely due to this issue on Unity's side, my license is definitely not expired).
If you can still access it and it's not too much of an effort, could you perhaps create some screenshots or copy text of the relevant parts of this Answers page and post it here? Otherwise I'm afraid I will need some more explanation of what you are trying to achieve and what your current problem is.
Seems like the access is up again.
But here is a copy paste.
Hi! I'm doing a project and am using Spine for animations. I export those to Unity and use the Spine-runtime to control everything in Unity.
I wanted to use one animated object as a mask for another animated object. I know next to nothing about shaders. I only use the shadergraph here and there.
Spine objects come with their own shaders and I tried to modify a bit the code to achieve what I want, and the second object is indeed masked within the first object, but the problem is that it is masked in the whole image area, even where pixels are trasparent.
Here's a gif with the behaviour right now: https://i.gyazo.com/d7bd76bfd662da1e1afb0aaf1a7bb8d6.mp4
Here are the shader codes.
Mask
Shader "Spine/SkeletonMask" {
Properties {
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
[NoScaleOffset] MainTex ("Main Texture", 2D) = "black" {}
[Toggle(STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
// Outline properties are drawn via custom editor.
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
[HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1
[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
Fog { Mode Off }
Cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Lighting Off
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Replace
}
Pass {
Name "Normal"
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
VertexOutput vert (VertexInput v) {
VertexOutput o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.vertexColor = v.vertexColor;
return o;
}
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor);
}
ENDCG
}
Pass {
Name "Caster"
Tags { "LightMode"="ShadowCaster" }
Offset 1, 1
ZWrite On
ZTest LEqual
Fog { Mode Off }
Cull Off
Lighting Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _Cutoff;
struct VertexOutput {
V2F_SHADOW_CASTER;
float4 uvAndAlpha : TEXCOORD1;
};
VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) {
VertexOutput o;
o.uvAndAlpha = v.texcoord;
o.uvAndAlpha.a = vertexColor.a;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag (VertexOutput i) : SV_Target {
fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy);
clip(texcol.a * i.uvAndAlpha.a - _Cutoff);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
CustomEditor "SpineShaderWithOutlineGUI"
}
Masked:
// Spine/Skeleton PMA Screen
// - single color multiply tint
// - unlit
// - Premultiplied alpha Multiply blending
// - No depth, no backface culling, no fog.
// - ShadowCaster pass
Shader "Spine/Blend Modes/Skeleton PMA Screen Masked" {
Properties {
_Color ("Tint Color", Color) = (1,1,1,1)
[NoScaleOffset] MainTex ("MainTex", 2D) = "black" {}
[Toggle(STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
// Outline properties are drawn via custom editor.
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
[HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1
[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
LOD 100
Fog { Mode Off }
Cull Off
ZWrite Off
Blend One OneMinusSrcColor
Lighting Off
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
//Pass Keep
}
Pass {
Name "Normal"
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform float4 _Color;
struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
VertexOutput vert (VertexInput v) {
VertexOutput o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
return o;
}
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor);
}
ENDCG
}
Pass {
Name "Caster"
Tags { "LightMode"="ShadowCaster" }
Offset 1, 1
ZWrite On
ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
float4 uvAndAlpha : TEXCOORD1;
};
uniform float4 _MainTex_ST;
v2f vert (appdata_base v, float4 vertexColor : COLOR) {
v2f o;
TRANSFER_SHADOW_CASTER(o)
o.uvAndAlpha.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uvAndAlpha.z = 0;
o.uvAndAlpha.a = vertexColor.a;
return o;
}
uniform sampler2D _MainTex;
uniform fixed _Cutoff;
float4 frag (v2f i) : SV_Target {
fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy);
clip(texcol.a * i.uvAndAlpha.a - _Cutoff);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
CustomEditor "SpineShaderWithOutlineGUI"
}
It's indeed up again, thanks anyway for the copy&paste.
duarteabh wrotebut the problem is that it is masked in the whole image area, even where pixels are trasparent.
If this is your only problem, then it's simply because you never discard any fragments in your mask's fragment shader, they are always writing e.g. 1
to the stencil buffer. The stencil buffer acts in a binary way, it does not allow "semi-transparent" writes. What you need is to discard the fragment when its alpha value is below a threshold:
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
clip((texColor.a * i.vertexColor.a) - _Cutoff); // add this line
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor);
}
This is identical to ALPHA_CLIP(texColor, i.vertexColor)
and adding #define _ALPHA_CLIP
before including Sprite\CGIncludes\ShaderShared.cginc
.
Hey Harald, yap that was the problem. All good now Thanks for the help.
Glad to hear, thanks for letting us know!